diff --git a/.github/scripts/build_npm_applications.sh b/.github/scripts/build_npm_applications.sh
new file mode 100644
index 00000000..53bd3025
--- /dev/null
+++ b/.github/scripts/build_npm_applications.sh
@@ -0,0 +1,46 @@
+PRE_OR_POST_RELEASE=$1
+MODULE_TYPE=$2
+
+
+if [ "$PRE_OR_POST_RELEASE" = "PRE" ]; then
+ if [ "$MODULE_TYPE" = "NPM-ES" ]; then
+ cd smoke/smoke-test-application-NPM-ES
+ npm uninstall aws-rum-web
+ npm run clean
+ npm install
+ npm install /home/runner/work/aws-rum-web/aws-rum-web #Install locally
+ npm run build
+ elif [ "$MODULE_TYPE" = "NPM-CJS" ]; then
+ cd smoke/smoke-test-application-NPM-CJS
+ npm uninstall aws-rum-web
+ npm run clean
+ npm install
+ npm install $(npm pack /home/runner/work/aws-rum-web/aws-rum-web | tail -1) #Install locally
+ npm run build
+ else
+ echo "Not a valid module type"
+ fi
+elif [ "$PRE_OR_POST_RELEASE" = "POST" ]; then
+
+ if [ "$MODULE_TYPE" = "NPM-ES" ]; then
+ cd smoke/smoke-test-application-NPM-ES
+ npm uninstall aws-rum-web
+ npm run clean
+ npm install
+ npm install aws-rum-web #Install latest released direct from NPM
+ npm run build
+ elif [ "$MODULE_TYPE" = "NPM-CJS" ]; then
+ cd smoke/smoke-test-application-NPM-CJS
+ npm uninstall aws-rum-web
+ npm run clean
+ npm install
+ npm install aws-rum-web #Install latest released direct from NPM
+ npm run build
+ else
+ echo "Not a valid module type"
+ fi
+else
+ echo "No valid option. Please provide PRE OR POST"
+fi
+
+
diff --git a/.github/scripts/update_smoke_test.sh b/.github/scripts/update_smoke_test.sh
index e0725162..ffe083f2 100644
--- a/.github/scripts/update_smoke_test.sh
+++ b/.github/scripts/update_smoke_test.sh
@@ -1,3 +1,4 @@
+# App monitor details
MONITOR_ID=$1
REGION=$2
GUEST_ARN=$3
@@ -6,6 +7,17 @@ ENDPOINT=$5
CDN=$6
VERSION=$(npm pkg get version | sed 's/"//g')/cwr.js
CDN+=${VERSION}
+INSTALL_METHOD=$7
+
+if [ "$INSTALL_METHOD" = "CDN" ]; then
awk '{sub(/\$MONITOR_ID/,MONITOR_ID);sub(/\$REGION/,REGION);sub(/\$CDN/,CDN);sub(/\$GUEST_ARN/,GUEST_ARN);sub(/\$IDENTITY_POOL/,IDENTITY_POOL);sub(/\$ENDPOINT/,ENDPOINT);}1' \
- MONITOR_ID="'$MONITOR_ID'" REGION="'$REGION'" CDN="'$CDN'" GUEST_ARN="'$GUEST_ARN'" IDENTITY_POOL="'$IDENTITY_POOL'" ENDPOINT="'$ENDPOINT'" app/smoke.html
-
\ No newline at end of file
+ MONITOR_ID="'$MONITOR_ID'" REGION="'$REGION'" CDN="'$CDN'" GUEST_ARN="'$GUEST_ARN'" IDENTITY_POOL="'$IDENTITY_POOL'" ENDPOINT="'$ENDPOINT'" smoke/smoke-test-application-CDN/smoke.html
+elif [ "$INSTALL_METHOD" = "NPM_ES" ]; then
+awk '{sub(/\$MONITOR_ID/,MONITOR_ID);sub(/\$REGION/,REGION);sub(/\$CDN/,CDN);sub(/\$GUEST_ARN/,GUEST_ARN);sub(/\$IDENTITY_POOL/,IDENTITY_POOL);sub(/\$ENDPOINT/,ENDPOINT);}1' \
+ MONITOR_ID="'$MONITOR_ID'" REGION="'$REGION'" CDN="'$CDN'" GUEST_ARN="'$GUEST_ARN'" IDENTITY_POOL="'$IDENTITY_POOL'" ENDPOINT="'$ENDPOINT'" smoke/smoke-test-application-NPM-ES/src/loader-npm-rum.ts
+ elif [ "$INSTALL_METHOD" = "NPM_CJS" ]; then
+awk '{sub(/\$MONITOR_ID/,MONITOR_ID);sub(/\$REGION/,REGION);sub(/\$CDN/,CDN);sub(/\$GUEST_ARN/,GUEST_ARN);sub(/\$IDENTITY_POOL/,IDENTITY_POOL);sub(/\$ENDPOINT/,ENDPOINT);}1' \
+ MONITOR_ID="'$MONITOR_ID'" REGION="'$REGION'" CDN="'$CDN'" GUEST_ARN="'$GUEST_ARN'" IDENTITY_POOL="'$IDENTITY_POOL'" ENDPOINT="'$ENDPOINT'" smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum.ts
+else
+ echo "No valid installation method input"
+fi
diff --git a/.github/scripts/upload_smoke_test.sh b/.github/scripts/upload_smoke_test.sh
index af387310..ea3b6a5c 100644
--- a/.github/scripts/upload_smoke_test.sh
+++ b/.github/scripts/upload_smoke_test.sh
@@ -1,3 +1,13 @@
bucket=$1
-key=smoke-$(npm pkg get version | sed 's/"//g').html
-aws s3api put-object --bucket $bucket --key "$key" --body processed_smoke.html --content-type "text/html"
+version=$(npm pkg get version | sed 's/"//g')
+
+# CDN
+aws s3api put-object --bucket $bucket --key "smoke-$version.html" --body processed_smoke.html --content-type "text/html"
+
+# NPM ES
+aws s3api put-object --bucket $bucket --key "npm/es/$version/smoke.html" --body smoke/smoke-test-application-NPM-ES/app/smoke.html --content-type "text/html"
+aws s3api put-object --bucket $bucket --key "npm/es/$version/loader_npm_rum_tmp.js" --body smoke/smoke-test-application-NPM-ES/build/dev/loader_npm_rum_tmp.js --content-type application/x-javascript
+
+# NPM CJS
+aws s3api put-object --bucket $bucket --key "npm/cjs/$version/smoke.html" --body smoke/smoke-test-application-NPM-CJS/app/smoke.html --content-type "text/html"
+aws s3api put-object --bucket $bucket --key "npm/cjs/$version/loader_npm_rum_tmp.js" --body smoke/smoke-test-application-NPM-CJS/build/dev/loader_npm_rum_tmp.js --content-type application/x-javascript
diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml
index d8fdae00..cb78ce18 100644
--- a/.github/workflows/cd.yaml
+++ b/.github/workflows/cd.yaml
@@ -67,13 +67,37 @@ jobs:
curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value' > $AWS_WEB_IDENTITY_TOKEN_FILE
- - name: Update Smoke Test Application
- id: update-smoke-test
+ - name: Update Smoke Test Application - CDN
+ id: update-smoke-test-cdn
run: |
chmod u+x .github/scripts/update_smoke_test.sh
- .github/scripts/update_smoke_test.sh ${{ secrets.SMOKE_MONITOR }} ${{ secrets.SMOKE_REGION }} ${{ secrets.SMOKE_ARN }} ${{ secrets.SMOKE_IDENTITY }} ${{ secrets.CONFIG_ENDPOINT }} ${{ secrets.CDN }} >> processed_smoke.html
+ .github/scripts/update_smoke_test.sh ${{ secrets.SMOKE_MONITOR }} ${{ secrets.SMOKE_REGION }} ${{ secrets.SMOKE_ARN }} ${{ secrets.SMOKE_IDENTITY }} ${{ secrets.CONFIG_ENDPOINT }} ${{ secrets.CDN }} "CDN" >> processed_smoke.html
- - name: Upload Smoke Test to CloudFront
+ - name: Update Smoke Test Application - NPM/ES
+ id: update-smoke-test-npm-es
+ run: |
+ chmod u+x .github/scripts/update_smoke_test.sh
+ .github/scripts/update_smoke_test.sh ${{ secrets.SMOKE_MONITOR }} ${{ secrets.SMOKE_REGION }} ${{ secrets.SMOKE_ARN }} ${{ secrets.SMOKE_IDENTITY }} ${{ secrets.CONFIG_ENDPOINT }} ${{ secrets.CDN }} "NPM_ES" >> smoke/smoke-test-application-NPM-ES/src/loader-npm-rum-tmp.ts
+
+ - name: Update Smoke Test Application - NPM/CJS
+ id: update-smoke-test-npm-cjs
+ run: |
+ chmod u+x .github/scripts/update_smoke_test.sh
+ .github/scripts/update_smoke_test.sh ${{ secrets.SMOKE_MONITOR }} ${{ secrets.SMOKE_REGION }} ${{ secrets.SMOKE_ARN }} ${{ secrets.SMOKE_IDENTITY }} ${{ secrets.CONFIG_ENDPOINT }} ${{ secrets.CDN }} "NPM_CJS" >> smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum-tmp.ts
+
+ - name: Build Smoke Test Application - NPM/ES
+ id: build-npm-es-application-pre-release
+ run: |
+ chmod u+x .github/scripts/build_npm_applications.sh
+ .github/scripts/build_npm_applications.sh "PRE" "NPM-ES"
+
+ - name: Build Smoke Test Application - NPM/CJS
+ id: build-npm-cjs-application-pre-release
+ run: |
+ chmod u+x .github/scripts/build_npm_applications.sh
+ .github/scripts/build_npm_applications.sh "PRE" "NPM-CJS"
+
+ - name: Upload Smoke Tests to CloudFront
id: upload-smoke-test
run: |
chmod u+x .github/scripts/upload_smoke_test.sh
@@ -82,12 +106,57 @@ jobs:
- name: Install PlayWright
run: npx playwright install --with-deps chromium
- - name: Run Smoke Test
+ - name: Run Smoke Test (NPM ES)
+ env:
+ URL: ${{ secrets.SMOKE_URL }}
+ MONITOR: ${{ secrets.SMOKE_MONITOR }}
+ ENDPOINT: ${{ secrets.SMOKE_ENDPOINT }}
+ NAME: ${{ secrets.SMOKE_MONITOR_NAME }}
+ INSTALL_METHOD: 'NPM-ES'
+ run: npm run smoke:headless
+ timeout-minutes: 10
+
+ - name: Fetch AWS Credentials for Smoke Test
+ run: |
+ export AWS_ROLE_ARN=${{ secrets.SMOKE_TEST_ROLE }}
+ export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/awscreds
+ export AWS_DEFAULT_REGION=us-east-1
+
+ echo AWS_WEB_IDENTITY_TOKEN_FILE=$AWS_WEB_IDENTITY_TOKEN_FILE >> $GITHUB_ENV
+ echo AWS_ROLE_ARN=$AWS_ROLE_ARN >> $GITHUB_ENV
+ echo AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION >> $GITHUB_ENV
+
+ curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value' > $AWS_WEB_IDENTITY_TOKEN_FILE
+
+ - name: Run Smoke Test (NPM CJS)
+ env:
+ URL: ${{ secrets.SMOKE_URL }}
+ MONITOR: ${{ secrets.SMOKE_MONITOR }}
+ ENDPOINT: ${{ secrets.SMOKE_ENDPOINT }}
+ NAME: ${{ secrets.SMOKE_MONITOR_NAME }}
+ INSTALL_METHOD: 'NPM-CJS'
+ run: npm run smoke:headless
+ timeout-minutes: 10
+
+ - name: Fetch AWS Credentials for Smoke Test
+ run: |
+ export AWS_ROLE_ARN=${{ secrets.SMOKE_TEST_ROLE }}
+ export AWS_WEB_IDENTITY_TOKEN_FILE=/tmp/awscreds
+ export AWS_DEFAULT_REGION=us-east-1
+
+ echo AWS_WEB_IDENTITY_TOKEN_FILE=$AWS_WEB_IDENTITY_TOKEN_FILE >> $GITHUB_ENV
+ echo AWS_ROLE_ARN=$AWS_ROLE_ARN >> $GITHUB_ENV
+ echo AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION >> $GITHUB_ENV
+
+ curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r '.value' > $AWS_WEB_IDENTITY_TOKEN_FILE
+
+ - name: Run Smoke Test (CDN)
env:
URL: ${{ secrets.SMOKE_URL }}
MONITOR: ${{ secrets.SMOKE_MONITOR }}
ENDPOINT: ${{ secrets.SMOKE_ENDPOINT }}
NAME: ${{ secrets.SMOKE_MONITOR_NAME }}
+ INSTALL_METHOD: 'CDN'
run: npm run smoke:headless
- name: Publish to NPM
@@ -95,6 +164,18 @@ jobs:
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ - name: Build Smoke Test Application - NPM/ES (Post NPM Release)
+ id: build-npm-es-application-post-release
+ run: |
+ chmod u+x .github/scripts/build_npm_applications.sh
+ .github/scripts/build_npm_applications.sh "POST" "NPM-ES"
+
+ - name: Build Smoke Test Application - NPM/CJS (Post NPM Release)
+ id: build-npm-cjs-application-post-release
+ run: |
+ chmod u+x .github/scripts/build_npm_applications.sh
+ .github/scripts/build_npm_applications.sh "POST" "NPM-CJS"
+
- name: Create GitHub Release
id: create_release
uses: actions/create-release@v1
diff --git a/.prettierignore b/.prettierignore
index aafe6a9b..63b692c2 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -5,4 +5,4 @@ coverage
src/events
package-lock.json
docs/
-.vscode
+.vscode
\ No newline at end of file
diff --git a/package.json b/package.json
index 8485910e..31c8d075 100644
--- a/package.json
+++ b/package.json
@@ -56,8 +56,7 @@
"postinteg:local:nightwatch:firefox": "kill $(lsof -t -i:8080)",
"smoke:local:headless": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version npx playwright test --config=playwright.local.config.ts",
"smoke:local": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version npx playwright test --config=playwright.local.config.ts --headed",
- "smoke": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version npx playwright test --config=playwright.config.ts --headed",
- "smoke:headless": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version npx playwright test --config=playwright.config.ts",
+ "smoke:headless": "cross-env URL=$URL MONITOR_ID=$MONITOR ENDPOINT=$ENDPOINT NAME=$NAME VERSION=$npm_package_version INSTALL_METHOD=$INSTALL_METHOD npx playwright test --config=playwright.config.ts",
"prepare": "husky install"
},
"devDependencies": {
diff --git a/playwright.config.ts b/playwright.config.ts
index 8b0be1ae..3a89eb99 100644
--- a/playwright.config.ts
+++ b/playwright.config.ts
@@ -2,11 +2,14 @@
// @ts-check
const { devices } = require('@playwright/test');
-const config = {
+var config = {
forbidOnly: !!process.env.CI,
reporter: 'list',
workers: process.env.CI ? 4 : undefined,
- testDir: 'src/__smoke-test__',
+ testDir:
+ process.env.INSTALL_METHOD === 'CDN'
+ ? 'src/__smoke-test__'
+ : 'src/__smoke-test-npm__',
retries: process.env.CI ? 2 : 2,
timeout: 300000,
use: {
diff --git a/smoke/smoke-test-application-CDN/smoke.html b/smoke/smoke-test-application-CDN/smoke.html
new file mode 100644
index 00000000..ff11b9ba
--- /dev/null
+++ b/smoke/smoke-test-application-CDN/smoke.html
@@ -0,0 +1,271 @@
+
+
+
+
+ RUM Smoke Test
+
+
+
+
+
+
+
+
+
+ This application is used for RUM smoke testing.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/smoke/smoke-test-application-NPM-CJS/app/smoke.html b/smoke/smoke-test-application-NPM-CJS/app/smoke.html
new file mode 100644
index 00000000..4d99a58a
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-CJS/app/smoke.html
@@ -0,0 +1,185 @@
+
+
+
+
+ RUM Smoke Test
+
+
+
+
+
+
+
+
+
+
+ This application is used for RUM smoke testing.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/smoke/smoke-test-application-NPM-CJS/package.json b/smoke/smoke-test-application-NPM-CJS/package.json
new file mode 100644
index 00000000..8f801751
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-CJS/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "smoke-test-application-NPM-ES",
+ "version": "1.0.0",
+ "type": "commonjs",
+ "scripts": {
+ "build": "webpack --config webpack/webpack.dev.js",
+ "release": "npm run build",
+ "server": "webpack-dev-server --config webpack/webpack.dev.js",
+ "clean": "rm -rf build && rm -rf dist && rm -rf node_modules"
+ },
+ "devDependencies": {
+ "@babel/core": "7.16.0",
+ "@babel/plugin-transform-runtime": "^7.16.0",
+ "@babel/preset-env": "~7.6.3",
+ "@webpack-cli/serve": "^1.6.0",
+ "babel-loader": "~8.0.6",
+ "case-sensitive-paths-webpack-plugin": "^2.1.2",
+ "copy-webpack-plugin": "^6.3.2",
+ "ts-loader": "^9.2.6",
+ "typescript": "^4.4.3",
+ "webpack": "^5.58.1",
+ "webpack-dev-middleware": "^5.2.1",
+ "webpack-dev-server": "^4.3.1"
+ },
+ "dependencies": {
+ "@babel/runtime": "^7.16.0",
+ "aws-rum-web": "^1.13.6",
+ "buffer": "^6.0.3",
+ "html-webpack-plugin": "^5.5.0"
+ },
+ "browserslist": [
+ "defaults"
+ ]
+}
diff --git a/smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum.ts b/smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum.ts
new file mode 100644
index 00000000..95691f75
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-CJS/src/loader-npm-rum.ts
@@ -0,0 +1,30 @@
+// @ts-nocheck
+const { AwsRum, AwsRumConfig } = require('aws-rum-web');
+
+let awsRum;
+
+try {
+ const config: AwsRumConfig = {
+ sessionSampleRate: 1,
+ guestRoleArn: $GUEST_ARN,
+ identityPoolId: $IDENTITY_POOL,
+ endpoint: $ENDPOINT,
+ telemetries: ['performance', 'errors', 'http', 'interaction'],
+ allowCookies: true,
+ enableXRay: true
+ };
+
+ const APPLICATION_ID: string = $MONITOR_ID;
+ const APPLICATION_VERSION: string = '1.0.0';
+ const APPLICATION_REGION: string = $REGION;
+
+ awsRum: AwsRum = new AwsRum(
+ APPLICATION_ID,
+ APPLICATION_VERSION,
+ APPLICATION_REGION,
+ config
+ );
+} catch (error) {
+ console.log(error);
+ throw error;
+}
diff --git a/smoke/smoke-test-application-NPM-CJS/tsconfig.json b/smoke/smoke-test-application-NPM-CJS/tsconfig.json
new file mode 100644
index 00000000..3ad37e38
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-CJS/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "baseUrl": "src",
+ "declaration": true,
+ "lib": ["dom", "es2018"],
+ "module": "esnext",
+ "moduleResolution": "node",
+ "strict": false,
+ "target": "es5"
+ },
+ "include": ["src/**/*"]
+}
diff --git a/smoke/smoke-test-application-NPM-CJS/tsconfig.webpack.json b/smoke/smoke-test-application-NPM-CJS/tsconfig.webpack.json
new file mode 100644
index 00000000..5abb2493
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-CJS/tsconfig.webpack.json
@@ -0,0 +1,7 @@
+{
+ "compilerOptions": {
+ "module": "es2020",
+ "outDir": "./dist/webpack"
+ },
+ "extends": "./tsconfig"
+}
diff --git a/smoke/smoke-test-application-NPM-CJS/webpack/webpack.dev.js b/smoke/smoke-test-application-NPM-CJS/webpack/webpack.dev.js
new file mode 100644
index 00000000..3be7d4a0
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-CJS/webpack/webpack.dev.js
@@ -0,0 +1,76 @@
+const CopyWebpackPlugin = require('copy-webpack-plugin');
+const path = require('path');
+const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
+
+const babelLoaderOptions = {
+ presets: [['@babel/preset-env', {}]],
+ plugins: [
+ [
+ '@babel/plugin-transform-runtime',
+ {
+ absoluteRuntime: false,
+ corejs: false,
+ helpers: true,
+ regenerator: true
+ }
+ ]
+ ]
+};
+
+module.exports = {
+ mode: 'development',
+ devtool: 'inline-source-map',
+ target: ['web', 'es5'],
+ entry: {
+ loader_npm_rum_tmp: './src/loader-npm-rum-tmp.ts'
+ },
+ resolve: {
+ extensions: ['.ts', '.js', '.json'],
+ mainFields: ['main', 'module', 'browser']
+ },
+ plugins: [
+ new CopyWebpackPlugin({
+ patterns: [{ from: 'app' }]
+ }),
+ new CaseSensitivePathsPlugin()
+ ],
+ output: {
+ path: path.join(__dirname, '../build/dev'),
+ filename: '[name].js',
+ publicPath: ''
+ },
+ devServer: {
+ static: path.join(__dirname, '../build/dev'),
+ port: 9000,
+ https: false,
+ hot: true
+ },
+ module: {
+ rules: [
+ {
+ test: [/\.js$/],
+ exclude: /node_modules/,
+ use: {
+ loader: 'babel-loader',
+ options: babelLoaderOptions
+ }
+ },
+ {
+ test: [/\.ts$/],
+ exclude: /node_modules/,
+ use: [
+ {
+ loader: 'babel-loader',
+ options: babelLoaderOptions
+ },
+ {
+ loader: 'ts-loader',
+ options: {
+ configFile: 'tsconfig.webpack.json'
+ }
+ }
+ ]
+ }
+ ]
+ }
+};
diff --git a/smoke/smoke-test-application-NPM-ES/app/smoke.html b/smoke/smoke-test-application-NPM-ES/app/smoke.html
new file mode 100644
index 00000000..4d99a58a
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-ES/app/smoke.html
@@ -0,0 +1,185 @@
+
+
+
+
+ RUM Smoke Test
+
+
+
+
+
+
+
+
+
+
+ This application is used for RUM smoke testing.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/smoke/smoke-test-application-NPM-ES/package.json b/smoke/smoke-test-application-NPM-ES/package.json
new file mode 100644
index 00000000..cb22159a
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-ES/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "smoke-test-application-NPM-ES",
+ "version": "1.0.0",
+ "scripts": {
+ "build": "webpack --config webpack/webpack.dev.js",
+ "release": "npm run build",
+ "server": "webpack-dev-server --config webpack/webpack.dev.js",
+ "clean": "rm -rf build && rm -rf dist && rm -rf node_modules"
+ },
+ "devDependencies": {
+ "@babel/core": "7.16.0",
+ "@babel/plugin-transform-runtime": "^7.16.0",
+ "@babel/preset-env": "~7.6.3",
+ "@webpack-cli/serve": "^1.6.0",
+ "babel-loader": "~8.0.6",
+ "case-sensitive-paths-webpack-plugin": "^2.1.2",
+ "copy-webpack-plugin": "^6.3.2",
+ "ts-loader": "^9.2.6",
+ "typescript": "^4.4.3",
+ "webpack": "^5.58.1",
+ "webpack-dev-middleware": "^5.2.1",
+ "webpack-dev-server": "^4.3.1"
+ },
+ "dependencies": {
+ "@babel/runtime": "^7.16.0",
+ "aws-rum-web": "file:../.."
+ },
+ "browserslist": [
+ "defaults"
+ ]
+}
diff --git a/smoke/smoke-test-application-NPM-ES/src/loader-npm-rum.ts b/smoke/smoke-test-application-NPM-ES/src/loader-npm-rum.ts
new file mode 100644
index 00000000..7488493d
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-ES/src/loader-npm-rum.ts
@@ -0,0 +1,29 @@
+// @ts-nocheck
+import { AwsRum, AwsRumConfig } from 'aws-rum-web';
+let awsRum;
+
+try {
+ const config: AwsRumConfig = {
+ sessionSampleRate: 1,
+ guestRoleArn: $GUEST_ARN,
+ identityPoolId: $IDENTITY_POOL,
+ endpoint: $ENDPOINT,
+ telemetries: ['performance', 'errors', 'http', 'interaction'],
+ allowCookies: true,
+ enableXRay: true
+ };
+
+ const APPLICATION_ID: string = $MONITOR_ID;
+ const APPLICATION_VERSION: string = '1.0.0';
+ const APPLICATION_REGION: string = $REGION;
+
+ awsRum: AwsRum = new AwsRum(
+ APPLICATION_ID,
+ APPLICATION_VERSION,
+ APPLICATION_REGION,
+ config
+ );
+} catch (error) {
+ console.log(error);
+ throw error;
+}
diff --git a/smoke/smoke-test-application-NPM-ES/tsconfig.json b/smoke/smoke-test-application-NPM-ES/tsconfig.json
new file mode 100644
index 00000000..3ad37e38
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-ES/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "baseUrl": "src",
+ "declaration": true,
+ "lib": ["dom", "es2018"],
+ "module": "esnext",
+ "moduleResolution": "node",
+ "strict": false,
+ "target": "es5"
+ },
+ "include": ["src/**/*"]
+}
diff --git a/smoke/smoke-test-application-NPM-ES/tsconfig.webpack.json b/smoke/smoke-test-application-NPM-ES/tsconfig.webpack.json
new file mode 100644
index 00000000..5abb2493
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-ES/tsconfig.webpack.json
@@ -0,0 +1,7 @@
+{
+ "compilerOptions": {
+ "module": "es2020",
+ "outDir": "./dist/webpack"
+ },
+ "extends": "./tsconfig"
+}
diff --git a/smoke/smoke-test-application-NPM-ES/webpack/webpack.dev.js b/smoke/smoke-test-application-NPM-ES/webpack/webpack.dev.js
new file mode 100644
index 00000000..ee306471
--- /dev/null
+++ b/smoke/smoke-test-application-NPM-ES/webpack/webpack.dev.js
@@ -0,0 +1,75 @@
+const CopyWebpackPlugin = require('copy-webpack-plugin');
+const path = require('path');
+const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
+
+const babelLoaderOptions = {
+ presets: [['@babel/preset-env', {}]],
+ plugins: [
+ [
+ '@babel/plugin-transform-runtime',
+ {
+ absoluteRuntime: false,
+ corejs: false,
+ helpers: true,
+ regenerator: true
+ }
+ ]
+ ]
+};
+
+module.exports = {
+ mode: 'development',
+ devtool: 'inline-source-map',
+ target: ['web', 'es5'],
+ entry: {
+ loader_npm_rum_tmp: './src/loader-npm-rum-tmp.ts'
+ },
+ resolve: {
+ extensions: ['.ts', '.js', '.json']
+ },
+ plugins: [
+ new CopyWebpackPlugin({
+ patterns: [{ from: 'app' }]
+ }),
+ new CaseSensitivePathsPlugin()
+ ],
+ output: {
+ path: path.join(__dirname, '../build/dev'),
+ filename: '[name].js',
+ publicPath: ''
+ },
+ devServer: {
+ static: path.join(__dirname, '../build/dev'),
+ port: 9000,
+ https: false,
+ hot: true
+ },
+ module: {
+ rules: [
+ {
+ test: [/\.js$/],
+ exclude: /node_modules/,
+ use: {
+ loader: 'babel-loader',
+ options: babelLoaderOptions
+ }
+ },
+ {
+ test: [/\.ts$/],
+ exclude: /node_modules/,
+ use: [
+ {
+ loader: 'babel-loader',
+ options: babelLoaderOptions
+ },
+ {
+ loader: 'ts-loader',
+ options: {
+ configFile: 'tsconfig.webpack.json'
+ }
+ }
+ ]
+ }
+ ]
+ }
+};
diff --git a/src/__smoke-test-npm__/dataplane-integ.spec.ts b/src/__smoke-test-npm__/dataplane-integ.spec.ts
new file mode 100644
index 00000000..2ff2345c
--- /dev/null
+++ b/src/__smoke-test-npm__/dataplane-integ.spec.ts
@@ -0,0 +1,72 @@
+import { test, expect } from '@playwright/test';
+import {
+ getEventsByType,
+ getUrl,
+ isDataPlaneRequest
+} from 'test-utils/smoke-test-utils';
+import {
+ PERFORMANCE_NAVIGATION_EVENT_TYPE,
+ PERFORMANCE_RESOURCE_EVENT_TYPE,
+ PAGE_VIEW_EVENT_TYPE,
+ SESSION_START_EVENT_TYPE
+} from '../plugins/utils/constant';
+
+// Environment variables set through CLI command
+const ENDPOINT = process.env.ENDPOINT;
+const MONITOR_ID = process.env.MONITOR;
+const TEST_URL = getUrl(
+ process.env.URL,
+ process.env.VERSION,
+ process.env.INSTALL_METHOD
+);
+const TARGET_URL = ENDPOINT + MONITOR_ID;
+
+test('when web client calls PutRumEvents then the response code is 200', async ({
+ page
+}) => {
+ // Open page
+ await page.goto(TEST_URL);
+
+ // Test will timeout if no successful dataplane request is found
+ await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(response, TARGET_URL)
+ );
+});
+
+test('when web client calls PutRumEvents then the payload contains all events', async ({
+ page
+}) => {
+ // Expected number of events per type
+ const SESSION_START_COUNT = 1;
+ const PAGEVIEW_COUNT = 1;
+ const NAVIGATION_COUNT = 1;
+ const RESOURCE_EVENT_COUNT = 1;
+
+ // Open page
+ await page.goto(TEST_URL);
+
+ // Test will timeout if no successful dataplane request is found
+ const response = await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(response, TARGET_URL)
+ );
+
+ // Parse payload to verify event count
+ const requestBody = JSON.parse(response.request().postData());
+
+ const session = getEventsByType(requestBody, SESSION_START_EVENT_TYPE);
+ const navigation = getEventsByType(
+ requestBody,
+ PERFORMANCE_NAVIGATION_EVENT_TYPE
+ );
+ const pageView = getEventsByType(requestBody, PAGE_VIEW_EVENT_TYPE);
+ const resource = getEventsByType(
+ requestBody,
+ PERFORMANCE_RESOURCE_EVENT_TYPE
+ );
+
+ // Verify no events are dropped
+ expect(session.length).toEqual(SESSION_START_COUNT);
+ expect(pageView.length).toEqual(PAGEVIEW_COUNT);
+ expect(navigation.length).toEqual(NAVIGATION_COUNT);
+ expect(resource.length).toEqual(RESOURCE_EVENT_COUNT);
+});
diff --git a/src/__smoke-test-npm__/ingestion-integ.spec.ts b/src/__smoke-test-npm__/ingestion-integ.spec.ts
new file mode 100644
index 00000000..42faefb2
--- /dev/null
+++ b/src/__smoke-test-npm__/ingestion-integ.spec.ts
@@ -0,0 +1,329 @@
+import { test, expect } from '@playwright/test';
+import { RUMClient } from '@aws-sdk/client-rum';
+import {
+ HTTP_EVENT_TYPE,
+ JS_ERROR_EVENT_TYPE,
+ LCP_EVENT_TYPE,
+ FID_EVENT_TYPE,
+ CLS_EVENT_TYPE,
+ PERFORMANCE_NAVIGATION_EVENT_TYPE,
+ PERFORMANCE_RESOURCE_EVENT_TYPE,
+ PAGE_VIEW_EVENT_TYPE,
+ SESSION_START_EVENT_TYPE,
+ DOM_EVENT_TYPE,
+ XRAY_TRACE_EVENT_TYPE
+} from '../plugins/utils/constant';
+import {
+ getEventIds,
+ getEventsByType,
+ getUrl,
+ isDataPlaneRequest,
+ verifyIngestionWithRetry
+} from 'test-utils/smoke-test-utils';
+
+// Environment variables set through CLI command
+const ENDPOINT = process.env.ENDPOINT;
+const MONITOR_ID = process.env.MONITOR;
+const TEST_URL = getUrl(
+ process.env.URL,
+ process.env.VERSION,
+ process.env.INSTALL_METHOD
+);
+const MONITOR_NAME = process.env.NAME;
+const REGION = ENDPOINT.split('.')[2];
+const TARGET_URL = ENDPOINT + MONITOR_ID;
+
+// Parse region from endpoint
+const rumClient = new RUMClient({ region: REGION });
+
+// Run the tests in parallel
+test.describe.configure({ mode: 'parallel' });
+test('when session start event is sent then event is ingested', async ({
+ page
+}) => {
+ const timestamp = Date.now() - 30000;
+
+ // Open page
+ await page.goto(TEST_URL);
+
+ // Test will timeout if no successful dataplane request is found
+ const response = await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(response, TARGET_URL)
+ );
+
+ // Parse payload to verify event count
+ const requestBody = JSON.parse(response.request().postData());
+
+ const session = getEventsByType(requestBody, SESSION_START_EVENT_TYPE);
+ const eventIds = getEventIds(session);
+
+ const isIngestionCompleted = await verifyIngestionWithRetry(
+ rumClient,
+ eventIds,
+ timestamp,
+ MONITOR_NAME,
+ 5
+ );
+ expect(isIngestionCompleted).toEqual(true);
+});
+
+test('when resource event is sent then event is ingested', async ({ page }) => {
+ const timestamp = Date.now() - 30000;
+
+ // Open page
+ await page.goto(TEST_URL);
+
+ // Test will timeout if no successful dataplane request is found
+ const response = await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(response, TARGET_URL)
+ );
+
+ // Parse payload to verify event count
+ const requestBody = JSON.parse(response.request().postData());
+
+ const resource = getEventsByType(
+ requestBody,
+ PERFORMANCE_RESOURCE_EVENT_TYPE
+ );
+ const eventIds = getEventIds(resource);
+
+ const isIngestionCompleted = await verifyIngestionWithRetry(
+ rumClient,
+ eventIds,
+ timestamp,
+ MONITOR_NAME,
+ 5
+ );
+ expect(isIngestionCompleted).toEqual(true);
+});
+
+test('when LCP event is sent then event is ingested', async ({ page }) => {
+ const timestamp = Date.now() - 30000;
+
+ // Open page
+ await page.goto(TEST_URL);
+ const clearButton = page.locator('[id=dummyButton]');
+ await clearButton.click();
+
+ // Test will timeout if no successful dataplane request is found
+ const response = await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(response, TARGET_URL)
+ );
+
+ // Parse payload to verify event count
+ const requestBody = JSON.parse(response.request().postData());
+
+ const lcp = getEventsByType(requestBody, LCP_EVENT_TYPE);
+ const eventIds = getEventIds(lcp);
+
+ expect(eventIds.length).not.toEqual(0);
+ const isIngestionCompleted = await verifyIngestionWithRetry(
+ rumClient,
+ eventIds,
+ timestamp,
+ MONITOR_NAME,
+ 5
+ );
+ expect(isIngestionCompleted).toEqual(true);
+});
+
+test('when FID event is sent then event is ingested', async ({ page }) => {
+ const timestamp = Date.now() - 30000;
+
+ // Open page
+ await page.goto(TEST_URL);
+ const clearButton = page.locator('[id=dummyButton]');
+ await clearButton.click();
+
+ // Test will timeout if no successful dataplane request is found
+ const response = await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(response, TARGET_URL)
+ );
+
+ // Parse payload to verify event count
+ const requestBody = JSON.parse(response.request().postData());
+
+ const fid = getEventsByType(requestBody, FID_EVENT_TYPE);
+ const eventIds = getEventIds(fid);
+
+ expect(eventIds.length).not.toEqual(0);
+ const isIngestionCompleted = await verifyIngestionWithRetry(
+ rumClient,
+ eventIds,
+ timestamp,
+ MONITOR_NAME,
+ 5
+ );
+ expect(isIngestionCompleted).toEqual(true);
+});
+
+test('when navigation events are sent then events are ingested', async ({
+ page
+}) => {
+ const timestamp = Date.now() - 30000;
+
+ // Open page
+ await page.goto(TEST_URL);
+ const clearButton = page.locator('[id=pushStateOneToHistory]');
+ await clearButton.click();
+
+ // Test will timeout if no successful dataplane request is found
+ const response = await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(response, TARGET_URL)
+ );
+
+ // Parse payload to verify event count
+ const requestBody = JSON.parse(response.request().postData());
+
+ const navigation = getEventsByType(
+ requestBody,
+ PERFORMANCE_NAVIGATION_EVENT_TYPE
+ );
+ const eventIds = getEventIds(navigation);
+
+ // One initial load, one route change
+ expect(eventIds.length).toEqual(2);
+ const isIngestionCompleted = await verifyIngestionWithRetry(
+ rumClient,
+ eventIds,
+ timestamp,
+ MONITOR_NAME,
+ 5
+ );
+ expect(isIngestionCompleted).toEqual(true);
+});
+
+test('when page view event is sent then the event is ingested', async ({
+ page
+}) => {
+ const timestamp = Date.now() - 30000;
+
+ // Open page
+ await page.goto(TEST_URL);
+ const clearButton = page.locator('[id=pushStateOneToHistory]');
+ await clearButton.click();
+
+ // Test will timeout if no successful dataplane request is found
+ const response = await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(response, TARGET_URL)
+ );
+
+ // Parse payload to verify event count
+ const requestBody = JSON.parse(response.request().postData());
+
+ const pageViews = getEventsByType(requestBody, PAGE_VIEW_EVENT_TYPE);
+ const eventIds = getEventIds(pageViews);
+
+ // One initial load, one route change
+ expect(eventIds.length).toEqual(2);
+ const isIngestionCompleted = await verifyIngestionWithRetry(
+ rumClient,
+ eventIds,
+ timestamp,
+ MONITOR_NAME,
+ 5
+ );
+ expect(isIngestionCompleted).toEqual(true);
+});
+
+test('when http events are sent then the events are ingested', async ({
+ page
+}) => {
+ const timestamp = Date.now() - 30000;
+
+ // Open page
+ await page.goto(TEST_URL);
+ const fetch500 = page.locator('[id=httpStatFetch500]');
+ const xhr500 = page.locator('[id=httpStatXhr500]');
+ await fetch500.click();
+ await xhr500.click();
+
+ // Test will timeout if no successful dataplane request is found
+ const response = await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(response, TARGET_URL)
+ );
+
+ // Parse payload to verify event count
+ const requestBody = JSON.parse(response.request().postData());
+
+ const httpEvents = getEventsByType(requestBody, HTTP_EVENT_TYPE);
+ const eventIds = getEventIds(httpEvents);
+
+ // Expect two http events
+ expect(eventIds.length).toEqual(2);
+ const isIngestionCompleted = await verifyIngestionWithRetry(
+ rumClient,
+ eventIds,
+ timestamp,
+ MONITOR_NAME,
+ 5
+ );
+ expect(isIngestionCompleted).toEqual(true);
+});
+
+test('when CLS event is sent then the event is ingested', async ({ page }) => {
+ const timestamp = Date.now() - 30000;
+
+ // Open page
+ await page.goto(TEST_URL);
+ const cls = page.locator('[id=dispatchCLS]');
+ await cls.click();
+
+ // CLS is reported only when the page is background or unloaded (visibilitychange)
+ // Thus, while triggering CLS, Web client will use beacon instead of fetch
+ // As a result, we need to take a substring of the existing target url
+ const response = await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(
+ response,
+ TARGET_URL.substring(0, TARGET_URL.length - 1)
+ )
+ );
+
+ // Parse payload to verify event count
+ const requestBody = JSON.parse(response.request().postData());
+
+ const clsEvents = getEventsByType(requestBody, CLS_EVENT_TYPE);
+ const eventIds = getEventIds(clsEvents);
+
+ // Expect one cls event
+ expect(eventIds.length).toEqual(1);
+ const isIngestionCompleted = await verifyIngestionWithRetry(
+ rumClient,
+ eventIds,
+ timestamp,
+ MONITOR_NAME,
+ 5
+ );
+ expect(isIngestionCompleted).toEqual(true);
+});
+
+test('when xray event is sent then the event is ingested', async ({ page }) => {
+ const timestamp = Date.now() - 30000;
+
+ // Open page
+ await page.goto(TEST_URL);
+ const http200 = page.locator('[id=httpStatFetch200]');
+ await http200.click();
+
+ // Test will timeout if no successful dataplane request is found
+ const response = await page.waitForResponse(async (response) =>
+ isDataPlaneRequest(response, TARGET_URL)
+ );
+
+ // Parse payload to verify event count
+ const requestBody = JSON.parse(response.request().postData());
+
+ const xrayEvent = getEventsByType(requestBody, XRAY_TRACE_EVENT_TYPE);
+ const eventIds = getEventIds(xrayEvent);
+
+ // Except one xray event
+ expect(eventIds.length).toEqual(1);
+ const isIngestionCompleted = await verifyIngestionWithRetry(
+ rumClient,
+ eventIds,
+ timestamp,
+ MONITOR_NAME,
+ 5
+ );
+ expect(isIngestionCompleted).toEqual(true);
+});
diff --git a/src/__smoke-test__/dataplane-integ.spec.ts b/src/__smoke-test__/dataplane-integ.spec.ts
index 41e01377..2ff2345c 100644
--- a/src/__smoke-test__/dataplane-integ.spec.ts
+++ b/src/__smoke-test__/dataplane-integ.spec.ts
@@ -14,7 +14,11 @@ import {
// Environment variables set through CLI command
const ENDPOINT = process.env.ENDPOINT;
const MONITOR_ID = process.env.MONITOR;
-const TEST_URL = getUrl(process.env.URL, process.env.VERSION);
+const TEST_URL = getUrl(
+ process.env.URL,
+ process.env.VERSION,
+ process.env.INSTALL_METHOD
+);
const TARGET_URL = ENDPOINT + MONITOR_ID;
test('when web client calls PutRumEvents then the response code is 200', async ({
diff --git a/src/__smoke-test__/ingestion-integ.spec.ts b/src/__smoke-test__/ingestion-integ.spec.ts
index c6404d3c..c4491bad 100644
--- a/src/__smoke-test__/ingestion-integ.spec.ts
+++ b/src/__smoke-test__/ingestion-integ.spec.ts
@@ -24,7 +24,11 @@ import {
// Environment variables set through CLI command
const ENDPOINT = process.env.ENDPOINT;
const MONITOR_ID = process.env.MONITOR;
-const TEST_URL = getUrl(process.env.URL, process.env.VERSION);
+const TEST_URL = getUrl(
+ process.env.URL,
+ process.env.VERSION,
+ process.env.INSTALL_METHOD
+);
const MONITOR_NAME = process.env.NAME;
const REGION = ENDPOINT.split('.')[2];
const TARGET_URL = ENDPOINT + MONITOR_ID;
diff --git a/src/test-utils/smoke-test-utils.ts b/src/test-utils/smoke-test-utils.ts
index 0e5bc093..088c3062 100644
--- a/src/test-utils/smoke-test-utils.ts
+++ b/src/test-utils/smoke-test-utils.ts
@@ -46,14 +46,23 @@ export const getEventIds = (events: any[]) => {
/** Returns the smoke test URL with the right version */
export const getUrl = (
testUrl: string | URL | undefined,
- version: string | undefined
+ version: string | undefined,
+ install_method: string | undefined
) => {
if (!testUrl) {
return 'http://localhost:9000/smoke_local.html';
}
const url = new URL(testUrl);
if (url.pathname === '/') {
- return url + `smoke-${version}.html`;
+ if (install_method === 'CDN') {
+ return url + `smoke-${version}.html`;
+ } else if (install_method === 'NPM-ES') {
+ return url + `npm/es/${version}/smoke.html`;
+ } else if (install_method === 'NPM-CJS') {
+ return url + `npm/cjs/${version}/smoke.html`;
+ } else {
+ return url.toString();
+ }
} else {
return url.toString();
}