From 30e978bad8851867d46db7358e4469102d477e9e Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Tue, 27 Sep 2022 15:40:31 +0000 Subject: [PATCH 01/22] test(e2e): Add E2E Test recipe framework --- packages/e2e-tests/run.ts | 91 +++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/packages/e2e-tests/run.ts b/packages/e2e-tests/run.ts index 4a752e15a294..b578e44223c6 100644 --- a/packages/e2e-tests/run.ts +++ b/packages/e2e-tests/run.ts @@ -11,42 +11,59 @@ const PUBLISH_PACKAGES_DOCKER_IMAGE_NAME = 'publish-packages'; const publishScriptNodeVersion = process.env.E2E_TEST_PUBLISH_SCRIPT_NODE_VERSION; -try { - // Stop test registry container (Verdaccio) if it was already running - childProcess.execSync(`docker stop ${TEST_REGISTRY_CONTAINER_NAME}`, { stdio: 'ignore' }); - console.log('Stopped previously running test registry'); -} catch (e) { - // Don't throw if container wasn't running +// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines +function groupCIOutput(groupTitle: string, fn: () => void): void { + if (process.env.CI) { + console.log(`::group::{${groupTitle}}`); + fn(); + console.log('::endgroup::'); + } else { + fn(); + } } -// Start test registry (Verdaccio) -childProcess.execSync( - `docker run --detach --rm --name ${TEST_REGISTRY_CONTAINER_NAME} -p 4873:4873 -v ${__dirname}/verdaccio-config:/verdaccio/conf verdaccio/verdaccio:${VERDACCIO_VERSION}`, - { encoding: 'utf8', stdio: 'inherit' }, -); - -// Build container image that is uploading our packages to fake registry with specific Node.js/npm version -childProcess.execSync( - `docker build --tag ${PUBLISH_PACKAGES_DOCKER_IMAGE_NAME} --file ./Dockerfile.publish-packages ${ - publishScriptNodeVersion ? `--build-arg NODE_VERSION=${publishScriptNodeVersion}` : '' - } .`, - { - encoding: 'utf8', - stdio: 'inherit', - }, -); - -// Run container that uploads our packages to fake registry -childProcess.execSync( - `docker run --rm -v ${repositoryRoot}:/sentry-javascript --network host ${PUBLISH_PACKAGES_DOCKER_IMAGE_NAME}`, - { - encoding: 'utf8', - stdio: 'inherit', - }, -); - -// TODO: Run e2e tests here - -// Stop test registry -childProcess.execSync(`docker stop ${TEST_REGISTRY_CONTAINER_NAME}`, { encoding: 'utf8', stdio: 'ignore' }); -console.log('Successfully stopped test registry container'); // Output from command above is not good so we `ignore` it and emit our own +groupCIOutput('Test Registry Setup', () => { + try { + // Stop test registry container (Verdaccio) if it was already running + childProcess.execSync(`docker stop ${TEST_REGISTRY_CONTAINER_NAME}`, { stdio: 'ignore' }); + console.log('Stopped previously running test registry'); + } catch (e) { + // Don't throw if container wasn't running + } + + // Start test registry (Verdaccio) + childProcess.execSync( + `docker run --detach --rm --name ${TEST_REGISTRY_CONTAINER_NAME} -p 4873:4873 -v ${__dirname}/verdaccio-config:/verdaccio/conf verdaccio/verdaccio:${VERDACCIO_VERSION}`, + { encoding: 'utf8', stdio: 'inherit' }, + ); + + // Build container image that is uploading our packages to fake registry with specific Node.js/npm version + childProcess.execSync( + `docker build --tag ${PUBLISH_PACKAGES_DOCKER_IMAGE_NAME} --file ./Dockerfile.publish-packages ${ + publishScriptNodeVersion ? `--build-arg NODE_VERSION=${publishScriptNodeVersion}` : '' + } .`, + { + encoding: 'utf8', + stdio: 'inherit', + }, + ); + + // Run container that uploads our packages to fake registry + childProcess.execSync( + `docker run --rm -v ${repositoryRoot}:/sentry-javascript --network host ${PUBLISH_PACKAGES_DOCKER_IMAGE_NAME}`, + { + encoding: 'utf8', + stdio: 'inherit', + }, + ); +}); + +groupCIOutput('Run E2E Test Suites', () => { + // TODO: Run e2e tests here +}); + +groupCIOutput('Cleanup', () => { + // Stop test registry + childProcess.execSync(`docker stop ${TEST_REGISTRY_CONTAINER_NAME}`, { encoding: 'utf8', stdio: 'ignore' }); + console.log('Successfully stopped test registry container'); // Output from command above is not good so we `ignore` it and emit our own +}); From 908b2b9bd9359beb619eb43d89b19e2d03e94f46 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 11:34:57 +0000 Subject: [PATCH 02/22] Add logic --- packages/e2e-tests/.eslintrc.js | 2 +- packages/e2e-tests/run.ts | 160 ++++++++++++++++-- .../temporary-app-1/.gitignore | 1 + .../test-applications/temporary-app-1/.npmrc | 3 + .../test-applications/temporary-app-1/bad.js | 1 + .../test-applications/temporary-app-1/good.js | 1 + .../temporary-app-1/package.json | 13 ++ .../temporary-app-1/test-recipe.json | 21 +++ .../temporary-app-1/timeout.js | 3 + .../temporary-app-2/.gitignore | 1 + .../test-applications/temporary-app-2/.npmrc | 3 + .../test-applications/temporary-app-2/bad.js | 1 + .../test-applications/temporary-app-2/good.js | 1 + .../temporary-app-2/package.json | 13 ++ .../temporary-app-2/test-recipe.json | 21 +++ .../temporary-app-2/timeout.js | 3 + packages/e2e-tests/test-recipe-schema.json | 38 +++++ 17 files changed, 274 insertions(+), 12 deletions(-) create mode 100644 packages/e2e-tests/test-applications/temporary-app-1/.gitignore create mode 100644 packages/e2e-tests/test-applications/temporary-app-1/.npmrc create mode 100644 packages/e2e-tests/test-applications/temporary-app-1/bad.js create mode 100644 packages/e2e-tests/test-applications/temporary-app-1/good.js create mode 100644 packages/e2e-tests/test-applications/temporary-app-1/package.json create mode 100644 packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json create mode 100644 packages/e2e-tests/test-applications/temporary-app-1/timeout.js create mode 100644 packages/e2e-tests/test-applications/temporary-app-2/.gitignore create mode 100644 packages/e2e-tests/test-applications/temporary-app-2/.npmrc create mode 100644 packages/e2e-tests/test-applications/temporary-app-2/bad.js create mode 100644 packages/e2e-tests/test-applications/temporary-app-2/good.js create mode 100644 packages/e2e-tests/test-applications/temporary-app-2/package.json create mode 100644 packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json create mode 100644 packages/e2e-tests/test-applications/temporary-app-2/timeout.js create mode 100644 packages/e2e-tests/test-recipe-schema.json diff --git a/packages/e2e-tests/.eslintrc.js b/packages/e2e-tests/.eslintrc.js index 5b0457483479..8c585e48f252 100644 --- a/packages/e2e-tests/.eslintrc.js +++ b/packages/e2e-tests/.eslintrc.js @@ -3,7 +3,7 @@ module.exports = { node: true, }, extends: ['../../.eslintrc.js'], - ignorePatterns: [], + ignorePatterns: ['test-applications/**'], parserOptions: { sourceType: 'module', }, diff --git a/packages/e2e-tests/run.ts b/packages/e2e-tests/run.ts index b578e44223c6..2acaee570f23 100644 --- a/packages/e2e-tests/run.ts +++ b/packages/e2e-tests/run.ts @@ -1,5 +1,7 @@ /* eslint-disable no-console */ import * as childProcess from 'child_process'; +import * as fs from 'fs'; +import * as glob from 'glob'; import * as path from 'path'; const repositoryRoot = path.resolve(__dirname, '../..'); @@ -11,10 +13,12 @@ const PUBLISH_PACKAGES_DOCKER_IMAGE_NAME = 'publish-packages'; const publishScriptNodeVersion = process.env.E2E_TEST_PUBLISH_SCRIPT_NODE_VERSION; +const DEFAULT_TEST_TIMEOUT_SECONDS = 60; + // https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines function groupCIOutput(groupTitle: string, fn: () => void): void { if (process.env.CI) { - console.log(`::group::{${groupTitle}}`); + console.log(`::group::${groupTitle}`); fn(); console.log('::endgroup::'); } else { @@ -22,26 +26,54 @@ function groupCIOutput(groupTitle: string, fn: () => void): void { } } +// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message +function printCIErrorMessage(message: string): void { + if (process.env.CI) { + console.log(`::error::${message}`); + } else { + console.log(message); + } +} + groupCIOutput('Test Registry Setup', () => { try { // Stop test registry container (Verdaccio) if it was already running - childProcess.execSync(`docker stop ${TEST_REGISTRY_CONTAINER_NAME}`, { stdio: 'ignore' }); + childProcess.spawnSync('docker', ['stop', TEST_REGISTRY_CONTAINER_NAME], { stdio: 'ignore' }); console.log('Stopped previously running test registry'); } catch (e) { // Don't throw if container wasn't running } // Start test registry (Verdaccio) - childProcess.execSync( - `docker run --detach --rm --name ${TEST_REGISTRY_CONTAINER_NAME} -p 4873:4873 -v ${__dirname}/verdaccio-config:/verdaccio/conf verdaccio/verdaccio:${VERDACCIO_VERSION}`, + childProcess.spawnSync( + 'docker', + [ + 'run', + '--detach', + '--rm', + '--name', + TEST_REGISTRY_CONTAINER_NAME, + '-p', + '4873:4873', + '-v', + `${__dirname}/verdaccio-config:/verdaccio/conf`, + `verdaccio/verdaccio:${VERDACCIO_VERSION}`, + ], { encoding: 'utf8', stdio: 'inherit' }, ); // Build container image that is uploading our packages to fake registry with specific Node.js/npm version - childProcess.execSync( - `docker build --tag ${PUBLISH_PACKAGES_DOCKER_IMAGE_NAME} --file ./Dockerfile.publish-packages ${ - publishScriptNodeVersion ? `--build-arg NODE_VERSION=${publishScriptNodeVersion}` : '' - } .`, + childProcess.spawnSync( + 'docker', + [ + 'build', + '--tag', + PUBLISH_PACKAGES_DOCKER_IMAGE_NAME, + '--file', + './Dockerfile.publish-packages', + publishScriptNodeVersion ? `--build-arg NODE_VERSION=${publishScriptNodeVersion}` : undefined, + '.', + ].filter((arg): arg is string => arg !== undefined), { encoding: 'utf8', stdio: 'inherit', @@ -49,8 +81,17 @@ groupCIOutput('Test Registry Setup', () => { ); // Run container that uploads our packages to fake registry - childProcess.execSync( - `docker run --rm -v ${repositoryRoot}:/sentry-javascript --network host ${PUBLISH_PACKAGES_DOCKER_IMAGE_NAME}`, + childProcess.spawnSync( + 'docker', + [ + 'run', + '--rm', + '-v', + `${repositoryRoot}:/sentry-javascript`, + '--network', + 'host', + PUBLISH_PACKAGES_DOCKER_IMAGE_NAME, + ], { encoding: 'utf8', stdio: 'inherit', @@ -60,10 +101,107 @@ groupCIOutput('Test Registry Setup', () => { groupCIOutput('Run E2E Test Suites', () => { // TODO: Run e2e tests here + const recipePaths = glob.sync(`${__dirname}/test-applications/*/test-recipe.json`, { absolute: true }); + + const recipeResults = recipePaths.map(recipePath => { + type Recipe = { + testApplicationName: string; + buildCommand?: string; + tests: { + testName: string; + testCommand: string; + timeoutSeconds?: number; + }[]; + }; + + const recipe: Recipe = JSON.parse(fs.readFileSync(recipePath, 'utf-8')); + + if (recipe.buildCommand) { + console.log(`Running E2E test build command for test application "${recipe.testApplicationName}"`); + const [buildCommand, ...buildCommandArgs] = recipe.buildCommand.split(' '); + childProcess.spawnSync(buildCommand, buildCommandArgs, { + cwd: path.dirname(recipePath), + encoding: 'utf8', + stdio: 'inherit', + }); + } + + type TestResult = { + testName: string; + result: 'PASS' | 'FAIL' | 'TIMEOUT'; + }; + + const testResults: TestResult[] = recipe.tests.map(test => { + console.log( + `Running E2E test command for test application "${recipe.testApplicationName}", test "${test.testName}"`, + ); + + const [testCommand, ...testCommandArgs] = test.testCommand.split(' '); + const testProcessResult = childProcess.spawnSync(testCommand, testCommandArgs, { + cwd: path.dirname(recipePath), + timeout: (test.timeoutSeconds ?? DEFAULT_TEST_TIMEOUT_SECONDS) * 1000, + encoding: 'utf8', + stdio: 'pipe', + }); + + console.log(testProcessResult.stdout.replace(/^/gm, '[TEST OUTPUT] ')); + console.log(testProcessResult.stderr.replace(/^/gm, '[TEST OUTPUT] ')); + + const error: undefined | (Error & { code?: string }) = testProcessResult.error; + + if (error?.code === 'ETIMEDOUT') { + printCIErrorMessage( + `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( + recipePath, + )}) timed out.`, + ); + return { + testName: test.testName, + result: 'TIMEOUT', + }; + } else if (testProcessResult.status !== 0) { + printCIErrorMessage( + `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( + recipePath, + )}) failed.`, + ); + return { + testName: test.testName, + result: 'FAIL', + }; + } else { + console.log( + `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( + recipePath, + )}) succeeded.`, + ); + return { + testName: test.testName, + result: 'PASS', + }; + } + }); + + return { + testApplicationName: recipe.testApplicationName, + testApplicationPath: recipePath, + testResults, + }; + }); + + console.log('--------------------------------------'); + console.log('Test Result Summary:'); + + recipeResults.forEach(recipeResult => { + console.log(`● ${recipeResult.testApplicationName} (${path.dirname(recipeResult.testApplicationPath)})`); + recipeResult.testResults.forEach(testResult => { + console.log(` ● ${testResult.result.padEnd(7, ' ')} ${testResult.testName}`); + }); + }); }); groupCIOutput('Cleanup', () => { // Stop test registry - childProcess.execSync(`docker stop ${TEST_REGISTRY_CONTAINER_NAME}`, { encoding: 'utf8', stdio: 'ignore' }); + childProcess.spawnSync(`docker stop ${TEST_REGISTRY_CONTAINER_NAME}`, { encoding: 'utf8', stdio: 'ignore' }); console.log('Successfully stopped test registry container'); // Output from command above is not good so we `ignore` it and emit our own }); diff --git a/packages/e2e-tests/test-applications/temporary-app-1/.gitignore b/packages/e2e-tests/test-applications/temporary-app-1/.gitignore new file mode 100644 index 000000000000..8ee01d321b72 --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-1/.gitignore @@ -0,0 +1 @@ +yarn.lock diff --git a/packages/e2e-tests/test-applications/temporary-app-1/.npmrc b/packages/e2e-tests/test-applications/temporary-app-1/.npmrc new file mode 100644 index 000000000000..c35d987cca9f --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-1/.npmrc @@ -0,0 +1,3 @@ +@sentry:registry=http://localhost:4873 +@sentry-internal:registry=http://localhost:4873 +//localhost:4873/:_authToken=some-token diff --git a/packages/e2e-tests/test-applications/temporary-app-1/bad.js b/packages/e2e-tests/test-applications/temporary-app-1/bad.js new file mode 100644 index 000000000000..bf99992592d6 --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-1/bad.js @@ -0,0 +1 @@ +throw new Error('Sad :('); diff --git a/packages/e2e-tests/test-applications/temporary-app-1/good.js b/packages/e2e-tests/test-applications/temporary-app-1/good.js new file mode 100644 index 000000000000..8da91c072fb8 --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-1/good.js @@ -0,0 +1 @@ +console.log('Happy :)'); diff --git a/packages/e2e-tests/test-applications/temporary-app-1/package.json b/packages/e2e-tests/test-applications/temporary-app-1/package.json new file mode 100644 index 000000000000..449dbd698c88 --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-1/package.json @@ -0,0 +1,13 @@ +{ + "name": "temporary-app-1", + "version": "1.0.0", + "private": true, + "scripts": { + "start:good": "node good.js", + "start:bad": "node bad.js", + "start:timeout": "node timeout.js" + }, + "dependencies": { + "@sentry/node": "*" + } +} diff --git a/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json b/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json new file mode 100644 index 000000000000..ddc1f2e72d9e --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json @@ -0,0 +1,21 @@ +{ + "$schema": "../../test-recipe-schema.json", + "testApplicationName": "Temporary Application 1", + "buildCommand": "yarn install", + "tests": [ + { + "testName": "Example Test (Should Succeed)", + "testCommand": "yarn start:good", + "timeoutSeconds": 30 + }, + { + "testName": "Example Test (Should Fail)", + "testCommand": "yarn start:bad" + }, + { + "testName": "Example Test (Should time out)", + "testCommand": "yarn start:timeout", + "timeoutSeconds": 5 + } + ] +} diff --git a/packages/e2e-tests/test-applications/temporary-app-1/timeout.js b/packages/e2e-tests/test-applications/temporary-app-1/timeout.js new file mode 100644 index 000000000000..044ab5d7191a --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-1/timeout.js @@ -0,0 +1,3 @@ +setTimeout(() => { + console.log('Bored :/'); +}, 6000); diff --git a/packages/e2e-tests/test-applications/temporary-app-2/.gitignore b/packages/e2e-tests/test-applications/temporary-app-2/.gitignore new file mode 100644 index 000000000000..8ee01d321b72 --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-2/.gitignore @@ -0,0 +1 @@ +yarn.lock diff --git a/packages/e2e-tests/test-applications/temporary-app-2/.npmrc b/packages/e2e-tests/test-applications/temporary-app-2/.npmrc new file mode 100644 index 000000000000..c35d987cca9f --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-2/.npmrc @@ -0,0 +1,3 @@ +@sentry:registry=http://localhost:4873 +@sentry-internal:registry=http://localhost:4873 +//localhost:4873/:_authToken=some-token diff --git a/packages/e2e-tests/test-applications/temporary-app-2/bad.js b/packages/e2e-tests/test-applications/temporary-app-2/bad.js new file mode 100644 index 000000000000..bf99992592d6 --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-2/bad.js @@ -0,0 +1 @@ +throw new Error('Sad :('); diff --git a/packages/e2e-tests/test-applications/temporary-app-2/good.js b/packages/e2e-tests/test-applications/temporary-app-2/good.js new file mode 100644 index 000000000000..8da91c072fb8 --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-2/good.js @@ -0,0 +1 @@ +console.log('Happy :)'); diff --git a/packages/e2e-tests/test-applications/temporary-app-2/package.json b/packages/e2e-tests/test-applications/temporary-app-2/package.json new file mode 100644 index 000000000000..b9a5cb6f68e7 --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-2/package.json @@ -0,0 +1,13 @@ +{ + "name": "temporary-app-2", + "version": "1.0.0", + "private": true, + "scripts": { + "start:good": "node good.js", + "start:bad": "node bad.js", + "start:timeout": "node timeout.js" + }, + "dependencies": { + "@sentry/node": "*" + } +} diff --git a/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json b/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json new file mode 100644 index 000000000000..9d93f49cc667 --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json @@ -0,0 +1,21 @@ +{ + "$schema": "../../test-recipe-schema.json", + "testApplicationName": "Temporary Application 2", + "buildCommand": "yarn install", + "tests": [ + { + "testName": "Example Test (Should Succeed)", + "testCommand": "yarn start:good", + "timeoutSeconds": 60 + }, + { + "testName": "Example Test (Should Fail)", + "testCommand": "yarn start:bad" + }, + { + "testName": "Example Test (Should time out)", + "testCommand": "yarn start:timeout", + "timeoutSeconds": 5 + } + ] +} diff --git a/packages/e2e-tests/test-applications/temporary-app-2/timeout.js b/packages/e2e-tests/test-applications/temporary-app-2/timeout.js new file mode 100644 index 000000000000..044ab5d7191a --- /dev/null +++ b/packages/e2e-tests/test-applications/temporary-app-2/timeout.js @@ -0,0 +1,3 @@ +setTimeout(() => { + console.log('Bored :/'); +}, 6000); diff --git a/packages/e2e-tests/test-recipe-schema.json b/packages/e2e-tests/test-recipe-schema.json new file mode 100644 index 000000000000..f2fd9a25659b --- /dev/null +++ b/packages/e2e-tests/test-recipe-schema.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Sentry JavaScript E2E Test Recipe", + "type": "object", + "properties": { + "testApplicationName": { + "type": "string", + "description": "Name displayed in test output" + }, + "buildCommand": { + "type": "string", + "description": "Command that is run to install dependencies and build the test application. This command is only run once before all tests. Working directory of the command is the root of the test application." + }, + "tests": { + "type": "array", + "description": "Tests to run in this test application", + "items": { + "type": "object", + "properties": { + "testName": { + "type": "string", + "description": "Name displayed in test output" + }, + "testCommand": { + "type": "string", + "description": "Command that is run to start the test. Working directory of the command is the root of the test application. If this command returns a non-zero exit code the test counts as failed." + }, + "timeoutSeconds": { + "type": "number", + "description": "Test timeout in seconds. Default: 60" + } + }, + "required": ["testName", "testCommand"] + } + } + }, + "required": ["testApplicationName", "tests"] +} From 569f85d68f84ac6fc092ff7c95a4f2d49ce6dbde Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 11:56:23 +0000 Subject: [PATCH 03/22] Exit on failure of commands --- packages/e2e-tests/run.ts | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/e2e-tests/run.ts b/packages/e2e-tests/run.ts index 2acaee570f23..e0e290f38d86 100644 --- a/packages/e2e-tests/run.ts +++ b/packages/e2e-tests/run.ts @@ -36,16 +36,12 @@ function printCIErrorMessage(message: string): void { } groupCIOutput('Test Registry Setup', () => { - try { - // Stop test registry container (Verdaccio) if it was already running - childProcess.spawnSync('docker', ['stop', TEST_REGISTRY_CONTAINER_NAME], { stdio: 'ignore' }); - console.log('Stopped previously running test registry'); - } catch (e) { - // Don't throw if container wasn't running - } + // Stop test registry container (Verdaccio) if it was already running + childProcess.spawnSync('docker', ['stop', TEST_REGISTRY_CONTAINER_NAME], { stdio: 'ignore' }); + console.log('Stopped previously running test registry'); // Start test registry (Verdaccio) - childProcess.spawnSync( + const startRegistryProcessResult = childProcess.spawnSync( 'docker', [ 'run', @@ -62,8 +58,12 @@ groupCIOutput('Test Registry Setup', () => { { encoding: 'utf8', stdio: 'inherit' }, ); + if (startRegistryProcessResult.status !== 0) { + process.exit(1); + } + // Build container image that is uploading our packages to fake registry with specific Node.js/npm version - childProcess.spawnSync( + const buildPublishImageProcessResult = childProcess.spawnSync( 'docker', [ 'build', @@ -80,8 +80,12 @@ groupCIOutput('Test Registry Setup', () => { }, ); + if (buildPublishImageProcessResult.status !== 0) { + process.exit(1); + } + // Run container that uploads our packages to fake registry - childProcess.spawnSync( + const publishImageContainerRunProcess = childProcess.spawnSync( 'docker', [ 'run', @@ -97,6 +101,10 @@ groupCIOutput('Test Registry Setup', () => { stdio: 'inherit', }, ); + + if (publishImageContainerRunProcess.status !== 0) { + process.exit(1); + } }); groupCIOutput('Run E2E Test Suites', () => { @@ -119,11 +127,15 @@ groupCIOutput('Run E2E Test Suites', () => { if (recipe.buildCommand) { console.log(`Running E2E test build command for test application "${recipe.testApplicationName}"`); const [buildCommand, ...buildCommandArgs] = recipe.buildCommand.split(' '); - childProcess.spawnSync(buildCommand, buildCommandArgs, { + const buildCommandProcess = childProcess.spawnSync(buildCommand, buildCommandArgs, { cwd: path.dirname(recipePath), encoding: 'utf8', stdio: 'inherit', }); + + if (buildCommandProcess.status !== 0) { + process.exit(1); + } } type TestResult = { From 78b8ccebc33b72e6c5ea26cd32160554b3a683dc Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 11:59:26 +0000 Subject: [PATCH 04/22] Crash on failed tests --- packages/e2e-tests/run.ts | 194 ++++++++++++++++++++------------------ 1 file changed, 101 insertions(+), 93 deletions(-) diff --git a/packages/e2e-tests/run.ts b/packages/e2e-tests/run.ts index e0e290f38d86..20ed15c9594f 100644 --- a/packages/e2e-tests/run.ts +++ b/packages/e2e-tests/run.ts @@ -107,108 +107,109 @@ groupCIOutput('Test Registry Setup', () => { } }); -groupCIOutput('Run E2E Test Suites', () => { - // TODO: Run e2e tests here - const recipePaths = glob.sync(`${__dirname}/test-applications/*/test-recipe.json`, { absolute: true }); - - const recipeResults = recipePaths.map(recipePath => { - type Recipe = { - testApplicationName: string; - buildCommand?: string; - tests: { - testName: string; - testCommand: string; - timeoutSeconds?: number; - }[]; - }; - - const recipe: Recipe = JSON.parse(fs.readFileSync(recipePath, 'utf-8')); - - if (recipe.buildCommand) { - console.log(`Running E2E test build command for test application "${recipe.testApplicationName}"`); - const [buildCommand, ...buildCommandArgs] = recipe.buildCommand.split(' '); - const buildCommandProcess = childProcess.spawnSync(buildCommand, buildCommandArgs, { - cwd: path.dirname(recipePath), - encoding: 'utf8', - stdio: 'inherit', - }); - - if (buildCommandProcess.status !== 0) { - process.exit(1); - } - } +const recipePaths = glob.sync(`${__dirname}/test-applications/*/test-recipe.json`, { absolute: true }); + +let someTestFailed = false; - type TestResult = { +const recipeResults = recipePaths.map(recipePath => { + type Recipe = { + testApplicationName: string; + buildCommand?: string; + tests: { testName: string; - result: 'PASS' | 'FAIL' | 'TIMEOUT'; - }; + testCommand: string; + timeoutSeconds?: number; + }[]; + }; + + const recipe: Recipe = JSON.parse(fs.readFileSync(recipePath, 'utf-8')); + + if (recipe.buildCommand) { + console.log(`Running E2E test build command for test application "${recipe.testApplicationName}"`); + const [buildCommand, ...buildCommandArgs] = recipe.buildCommand.split(' '); + const buildCommandProcess = childProcess.spawnSync(buildCommand, buildCommandArgs, { + cwd: path.dirname(recipePath), + encoding: 'utf8', + stdio: 'inherit', + }); - const testResults: TestResult[] = recipe.tests.map(test => { - console.log( - `Running E2E test command for test application "${recipe.testApplicationName}", test "${test.testName}"`, - ); + if (buildCommandProcess.status !== 0) { + process.exit(1); + } + } - const [testCommand, ...testCommandArgs] = test.testCommand.split(' '); - const testProcessResult = childProcess.spawnSync(testCommand, testCommandArgs, { - cwd: path.dirname(recipePath), - timeout: (test.timeoutSeconds ?? DEFAULT_TEST_TIMEOUT_SECONDS) * 1000, - encoding: 'utf8', - stdio: 'pipe', - }); - - console.log(testProcessResult.stdout.replace(/^/gm, '[TEST OUTPUT] ')); - console.log(testProcessResult.stderr.replace(/^/gm, '[TEST OUTPUT] ')); - - const error: undefined | (Error & { code?: string }) = testProcessResult.error; - - if (error?.code === 'ETIMEDOUT') { - printCIErrorMessage( - `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( - recipePath, - )}) timed out.`, - ); - return { - testName: test.testName, - result: 'TIMEOUT', - }; - } else if (testProcessResult.status !== 0) { - printCIErrorMessage( - `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( - recipePath, - )}) failed.`, - ); - return { - testName: test.testName, - result: 'FAIL', - }; - } else { - console.log( - `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( - recipePath, - )}) succeeded.`, - ); - return { - testName: test.testName, - result: 'PASS', - }; - } + type TestResult = { + testName: string; + result: 'PASS' | 'FAIL' | 'TIMEOUT'; + }; + + const testResults: TestResult[] = recipe.tests.map(test => { + console.log( + `Running E2E test command for test application "${recipe.testApplicationName}", test "${test.testName}"`, + ); + + const [testCommand, ...testCommandArgs] = test.testCommand.split(' '); + const testProcessResult = childProcess.spawnSync(testCommand, testCommandArgs, { + cwd: path.dirname(recipePath), + timeout: (test.timeoutSeconds ?? DEFAULT_TEST_TIMEOUT_SECONDS) * 1000, + encoding: 'utf8', + stdio: 'pipe', }); - return { - testApplicationName: recipe.testApplicationName, - testApplicationPath: recipePath, - testResults, - }; + console.log(testProcessResult.stdout.replace(/^/gm, '[TEST OUTPUT] ')); + console.log(testProcessResult.stderr.replace(/^/gm, '[TEST OUTPUT] ')); + + const error: undefined | (Error & { code?: string }) = testProcessResult.error; + + if (error?.code === 'ETIMEDOUT') { + printCIErrorMessage( + `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( + recipePath, + )}) timed out.`, + ); + return { + testName: test.testName, + result: 'TIMEOUT', + }; + } else if (testProcessResult.status !== 0) { + someTestFailed = true; + printCIErrorMessage( + `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( + recipePath, + )}) failed.`, + ); + return { + testName: test.testName, + result: 'FAIL', + }; + } else { + someTestFailed = true; + console.log( + `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( + recipePath, + )}) succeeded.`, + ); + return { + testName: test.testName, + result: 'PASS', + }; + } }); - console.log('--------------------------------------'); - console.log('Test Result Summary:'); + return { + testApplicationName: recipe.testApplicationName, + testApplicationPath: recipePath, + testResults, + }; +}); - recipeResults.forEach(recipeResult => { - console.log(`● ${recipeResult.testApplicationName} (${path.dirname(recipeResult.testApplicationPath)})`); - recipeResult.testResults.forEach(testResult => { - console.log(` ● ${testResult.result.padEnd(7, ' ')} ${testResult.testName}`); - }); +console.log('--------------------------------------'); +console.log('Test Result Summary:'); + +recipeResults.forEach(recipeResult => { + console.log(`● ${recipeResult.testApplicationName} (${path.dirname(recipeResult.testApplicationPath)})`); + recipeResult.testResults.forEach(testResult => { + console.log(` ● ${testResult.result.padEnd(7, ' ')} ${testResult.testName}`); }); }); @@ -217,3 +218,10 @@ groupCIOutput('Cleanup', () => { childProcess.spawnSync(`docker stop ${TEST_REGISTRY_CONTAINER_NAME}`, { encoding: 'utf8', stdio: 'ignore' }); console.log('Successfully stopped test registry container'); // Output from command above is not good so we `ignore` it and emit our own }); + +if (someTestFailed) { + console.log('Not all tests succeeded.'); + process.exit(1); +} else { + console.log('All tests succeeded.'); +} From d0709fe9a47f0b74681fa5d4586e7d209c3c6367 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 12:03:25 +0000 Subject: [PATCH 05/22] No arg splitting --- packages/e2e-tests/run.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/e2e-tests/run.ts b/packages/e2e-tests/run.ts index 20ed15c9594f..d7e93cfcc6c4 100644 --- a/packages/e2e-tests/run.ts +++ b/packages/e2e-tests/run.ts @@ -126,11 +126,11 @@ const recipeResults = recipePaths.map(recipePath => { if (recipe.buildCommand) { console.log(`Running E2E test build command for test application "${recipe.testApplicationName}"`); - const [buildCommand, ...buildCommandArgs] = recipe.buildCommand.split(' '); - const buildCommandProcess = childProcess.spawnSync(buildCommand, buildCommandArgs, { + const buildCommandProcess = childProcess.spawnSync(recipe.buildCommand, { cwd: path.dirname(recipePath), encoding: 'utf8', stdio: 'inherit', + shell: true, // needed so we can pass the build command in as whole without splitting it up into args }); if (buildCommandProcess.status !== 0) { @@ -148,12 +148,12 @@ const recipeResults = recipePaths.map(recipePath => { `Running E2E test command for test application "${recipe.testApplicationName}", test "${test.testName}"`, ); - const [testCommand, ...testCommandArgs] = test.testCommand.split(' '); - const testProcessResult = childProcess.spawnSync(testCommand, testCommandArgs, { + const testProcessResult = childProcess.spawnSync(test.testCommand, { cwd: path.dirname(recipePath), timeout: (test.timeoutSeconds ?? DEFAULT_TEST_TIMEOUT_SECONDS) * 1000, encoding: 'utf8', stdio: 'pipe', + shell: true, // needed so we can pass the test command in as whole without splitting it up into args }); console.log(testProcessResult.stdout.replace(/^/gm, '[TEST OUTPUT] ')); From d46c984a64cdad843546eba07890c746274603ff Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 12:56:20 +0000 Subject: [PATCH 06/22] Fix build args --- packages/e2e-tests/run.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/e2e-tests/run.ts b/packages/e2e-tests/run.ts index d7e93cfcc6c4..e48e6135f701 100644 --- a/packages/e2e-tests/run.ts +++ b/packages/e2e-tests/run.ts @@ -71,9 +71,9 @@ groupCIOutput('Test Registry Setup', () => { PUBLISH_PACKAGES_DOCKER_IMAGE_NAME, '--file', './Dockerfile.publish-packages', - publishScriptNodeVersion ? `--build-arg NODE_VERSION=${publishScriptNodeVersion}` : undefined, + ...(publishScriptNodeVersion ? ['--build-arg', `NODE_VERSION=${publishScriptNodeVersion}`] : []), '.', - ].filter((arg): arg is string => arg !== undefined), + ], { encoding: 'utf8', stdio: 'inherit', From 6bce0de34e143d5b9518a968093345300e4696b2 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 13:33:14 +0000 Subject: [PATCH 07/22] Make E2E tests pass so we don't fail master --- packages/e2e-tests/run.ts | 9 ++++++--- .../test-applications/temporary-app-1/bad.js | 1 - .../temporary-app-1/test-recipe.json | 12 +----------- .../test-applications/temporary-app-1/timeout.js | 3 --- .../test-applications/temporary-app-2/bad.js | 1 - .../temporary-app-2/test-recipe.json | 12 +----------- .../test-applications/temporary-app-2/timeout.js | 3 --- 7 files changed, 8 insertions(+), 33 deletions(-) delete mode 100644 packages/e2e-tests/test-applications/temporary-app-1/bad.js delete mode 100644 packages/e2e-tests/test-applications/temporary-app-1/timeout.js delete mode 100644 packages/e2e-tests/test-applications/temporary-app-2/bad.js delete mode 100644 packages/e2e-tests/test-applications/temporary-app-2/timeout.js diff --git a/packages/e2e-tests/run.ts b/packages/e2e-tests/run.ts index e48e6135f701..aa26c774c54e 100644 --- a/packages/e2e-tests/run.ts +++ b/packages/e2e-tests/run.ts @@ -129,10 +129,13 @@ const recipeResults = recipePaths.map(recipePath => { const buildCommandProcess = childProcess.spawnSync(recipe.buildCommand, { cwd: path.dirname(recipePath), encoding: 'utf8', - stdio: 'inherit', shell: true, // needed so we can pass the build command in as whole without splitting it up into args }); + // Prepends some text to the output build command's output so we can distinguish it from logging in this script + console.log(buildCommandProcess.stdout.replace(/^/gm, '[BUILD OUTPUT] ')); + console.log(buildCommandProcess.stderr.replace(/^/gm, '[BUILD OUTPUT] ')); + if (buildCommandProcess.status !== 0) { process.exit(1); } @@ -152,16 +155,17 @@ const recipeResults = recipePaths.map(recipePath => { cwd: path.dirname(recipePath), timeout: (test.timeoutSeconds ?? DEFAULT_TEST_TIMEOUT_SECONDS) * 1000, encoding: 'utf8', - stdio: 'pipe', shell: true, // needed so we can pass the test command in as whole without splitting it up into args }); + // Prepends some text to the output test command's output so we can distinguish it from logging in this script console.log(testProcessResult.stdout.replace(/^/gm, '[TEST OUTPUT] ')); console.log(testProcessResult.stderr.replace(/^/gm, '[TEST OUTPUT] ')); const error: undefined | (Error & { code?: string }) = testProcessResult.error; if (error?.code === 'ETIMEDOUT') { + someTestFailed = true; printCIErrorMessage( `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( recipePath, @@ -183,7 +187,6 @@ const recipeResults = recipePaths.map(recipePath => { result: 'FAIL', }; } else { - someTestFailed = true; console.log( `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( recipePath, diff --git a/packages/e2e-tests/test-applications/temporary-app-1/bad.js b/packages/e2e-tests/test-applications/temporary-app-1/bad.js deleted file mode 100644 index bf99992592d6..000000000000 --- a/packages/e2e-tests/test-applications/temporary-app-1/bad.js +++ /dev/null @@ -1 +0,0 @@ -throw new Error('Sad :('); diff --git a/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json b/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json index ddc1f2e72d9e..480f0ce4003e 100644 --- a/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json +++ b/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json @@ -5,17 +5,7 @@ "tests": [ { "testName": "Example Test (Should Succeed)", - "testCommand": "yarn start:good", - "timeoutSeconds": 30 - }, - { - "testName": "Example Test (Should Fail)", - "testCommand": "yarn start:bad" - }, - { - "testName": "Example Test (Should time out)", - "testCommand": "yarn start:timeout", - "timeoutSeconds": 5 + "testCommand": "yarn start:good" } ] } diff --git a/packages/e2e-tests/test-applications/temporary-app-1/timeout.js b/packages/e2e-tests/test-applications/temporary-app-1/timeout.js deleted file mode 100644 index 044ab5d7191a..000000000000 --- a/packages/e2e-tests/test-applications/temporary-app-1/timeout.js +++ /dev/null @@ -1,3 +0,0 @@ -setTimeout(() => { - console.log('Bored :/'); -}, 6000); diff --git a/packages/e2e-tests/test-applications/temporary-app-2/bad.js b/packages/e2e-tests/test-applications/temporary-app-2/bad.js deleted file mode 100644 index bf99992592d6..000000000000 --- a/packages/e2e-tests/test-applications/temporary-app-2/bad.js +++ /dev/null @@ -1 +0,0 @@ -throw new Error('Sad :('); diff --git a/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json b/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json index 9d93f49cc667..c9367aa534ea 100644 --- a/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json +++ b/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json @@ -5,17 +5,7 @@ "tests": [ { "testName": "Example Test (Should Succeed)", - "testCommand": "yarn start:good", - "timeoutSeconds": 60 - }, - { - "testName": "Example Test (Should Fail)", - "testCommand": "yarn start:bad" - }, - { - "testName": "Example Test (Should time out)", - "testCommand": "yarn start:timeout", - "timeoutSeconds": 5 + "testCommand": "yarn start:good" } ] } diff --git a/packages/e2e-tests/test-applications/temporary-app-2/timeout.js b/packages/e2e-tests/test-applications/temporary-app-2/timeout.js deleted file mode 100644 index 044ab5d7191a..000000000000 --- a/packages/e2e-tests/test-applications/temporary-app-2/timeout.js +++ /dev/null @@ -1,3 +0,0 @@ -setTimeout(() => { - console.log('Bored :/'); -}, 6000); From 0390c53318621c2ed549cacbbb8eded9183b14dc Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 14:32:11 +0000 Subject: [PATCH 08/22] Improve failed build reporting --- packages/e2e-tests/run.ts | 57 ++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/packages/e2e-tests/run.ts b/packages/e2e-tests/run.ts index aa26c774c54e..0e26418b66a7 100644 --- a/packages/e2e-tests/run.ts +++ b/packages/e2e-tests/run.ts @@ -109,9 +109,21 @@ groupCIOutput('Test Registry Setup', () => { const recipePaths = glob.sync(`${__dirname}/test-applications/*/test-recipe.json`, { absolute: true }); -let someTestFailed = false; +let processShouldExitWithError = false; -const recipeResults = recipePaths.map(recipePath => { +type TestResult = { + testName: string; + result: 'PASS' | 'FAIL' | 'TIMEOUT'; +}; + +type RecipeResult = { + testApplicationName: string; + testApplicationPath: string; + buildFailed: boolean; + testResults: TestResult[]; +}; + +const recipeResults: RecipeResult[] = recipePaths.map(recipePath => { type Recipe = { testApplicationName: string; buildCommand?: string; @@ -137,15 +149,21 @@ const recipeResults = recipePaths.map(recipePath => { console.log(buildCommandProcess.stderr.replace(/^/gm, '[BUILD OUTPUT] ')); if (buildCommandProcess.status !== 0) { - process.exit(1); + processShouldExitWithError = true; + + printCIErrorMessage( + `Build command in test application "${recipe.testApplicationName}" (${path.dirname(recipePath)}) failed!`, + ); + + return { + testApplicationName: recipe.testApplicationName, + testApplicationPath: recipePath, + buildFailed: true, + testResults: [], + }; } } - type TestResult = { - testName: string; - result: 'PASS' | 'FAIL' | 'TIMEOUT'; - }; - const testResults: TestResult[] = recipe.tests.map(test => { console.log( `Running E2E test command for test application "${recipe.testApplicationName}", test "${test.testName}"`, @@ -165,7 +183,7 @@ const recipeResults = recipePaths.map(recipePath => { const error: undefined | (Error & { code?: string }) = testProcessResult.error; if (error?.code === 'ETIMEDOUT') { - someTestFailed = true; + processShouldExitWithError = true; printCIErrorMessage( `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( recipePath, @@ -176,7 +194,7 @@ const recipeResults = recipePaths.map(recipePath => { result: 'TIMEOUT', }; } else if (testProcessResult.status !== 0) { - someTestFailed = true; + processShouldExitWithError = true; printCIErrorMessage( `Test "${test.testName}" in test application "${recipe.testApplicationName}" (${path.dirname( recipePath, @@ -202,6 +220,7 @@ const recipeResults = recipePaths.map(recipePath => { return { testApplicationName: recipe.testApplicationName, testApplicationPath: recipePath, + buildFailed: false, testResults, }; }); @@ -210,10 +229,18 @@ console.log('--------------------------------------'); console.log('Test Result Summary:'); recipeResults.forEach(recipeResult => { - console.log(`● ${recipeResult.testApplicationName} (${path.dirname(recipeResult.testApplicationPath)})`); - recipeResult.testResults.forEach(testResult => { - console.log(` ● ${testResult.result.padEnd(7, ' ')} ${testResult.testName}`); - }); + if (recipeResult.buildFailed) { + console.log( + `● BUILD FAILED - ${recipeResult.testApplicationName} (${path.dirname(recipeResult.testApplicationPath)})`, + ); + } else { + console.log( + `● BUILD SUCCEEDED - ${recipeResult.testApplicationName} (${path.dirname(recipeResult.testApplicationPath)})`, + ); + recipeResult.testResults.forEach(testResult => { + console.log(` ● ${testResult.result.padEnd(7, ' ')} ${testResult.testName}`); + }); + } }); groupCIOutput('Cleanup', () => { @@ -222,7 +249,7 @@ groupCIOutput('Cleanup', () => { console.log('Successfully stopped test registry container'); // Output from command above is not good so we `ignore` it and emit our own }); -if (someTestFailed) { +if (processShouldExitWithError) { console.log('Not all tests succeeded.'); process.exit(1); } else { From 7995d93792b74f7cea9193d17a122be13709f88b Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 14:32:42 +0000 Subject: [PATCH 09/22] Remove unnecessary scripts --- .../e2e-tests/test-applications/temporary-app-1/package.json | 4 +--- .../e2e-tests/test-applications/temporary-app-2/package.json | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/e2e-tests/test-applications/temporary-app-1/package.json b/packages/e2e-tests/test-applications/temporary-app-1/package.json index 449dbd698c88..6adffeacc75f 100644 --- a/packages/e2e-tests/test-applications/temporary-app-1/package.json +++ b/packages/e2e-tests/test-applications/temporary-app-1/package.json @@ -3,9 +3,7 @@ "version": "1.0.0", "private": true, "scripts": { - "start:good": "node good.js", - "start:bad": "node bad.js", - "start:timeout": "node timeout.js" + "start:good": "node good.js" }, "dependencies": { "@sentry/node": "*" diff --git a/packages/e2e-tests/test-applications/temporary-app-2/package.json b/packages/e2e-tests/test-applications/temporary-app-2/package.json index b9a5cb6f68e7..a01456cb2f2e 100644 --- a/packages/e2e-tests/test-applications/temporary-app-2/package.json +++ b/packages/e2e-tests/test-applications/temporary-app-2/package.json @@ -3,9 +3,7 @@ "version": "1.0.0", "private": true, "scripts": { - "start:good": "node good.js", - "start:bad": "node bad.js", - "start:timeout": "node timeout.js" + "start:good": "node good.js" }, "dependencies": { "@sentry/node": "*" From fbeafabd296f796b9002a9683f35b7a34e627e78 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 15:00:39 +0000 Subject: [PATCH 10/22] Remove unnecessary configuration --- packages/e2e-tests/test-applications/temporary-app-1/.npmrc | 1 - packages/e2e-tests/test-applications/temporary-app-2/.npmrc | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/e2e-tests/test-applications/temporary-app-1/.npmrc b/packages/e2e-tests/test-applications/temporary-app-1/.npmrc index c35d987cca9f..c6b3ef9b3eaa 100644 --- a/packages/e2e-tests/test-applications/temporary-app-1/.npmrc +++ b/packages/e2e-tests/test-applications/temporary-app-1/.npmrc @@ -1,3 +1,2 @@ @sentry:registry=http://localhost:4873 @sentry-internal:registry=http://localhost:4873 -//localhost:4873/:_authToken=some-token diff --git a/packages/e2e-tests/test-applications/temporary-app-2/.npmrc b/packages/e2e-tests/test-applications/temporary-app-2/.npmrc index c35d987cca9f..c6b3ef9b3eaa 100644 --- a/packages/e2e-tests/test-applications/temporary-app-2/.npmrc +++ b/packages/e2e-tests/test-applications/temporary-app-2/.npmrc @@ -1,3 +1,2 @@ @sentry:registry=http://localhost:4873 @sentry-internal:registry=http://localhost:4873 -//localhost:4873/:_authToken=some-token From f9800015a286b52d8fc886eb4dbb861ab37ca518 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 15:06:05 +0000 Subject: [PATCH 11/22] Don't create lockfiles --- .../test-applications/temporary-app-1/test-recipe.json | 2 +- .../test-applications/temporary-app-2/test-recipe.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json b/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json index 480f0ce4003e..c00b1ff55a7e 100644 --- a/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json +++ b/packages/e2e-tests/test-applications/temporary-app-1/test-recipe.json @@ -1,7 +1,7 @@ { "$schema": "../../test-recipe-schema.json", "testApplicationName": "Temporary Application 1", - "buildCommand": "yarn install", + "buildCommand": "yarn install --no-lockfile", "tests": [ { "testName": "Example Test (Should Succeed)", diff --git a/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json b/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json index c9367aa534ea..2ccdd52d62fb 100644 --- a/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json +++ b/packages/e2e-tests/test-applications/temporary-app-2/test-recipe.json @@ -1,7 +1,7 @@ { "$schema": "../../test-recipe-schema.json", "testApplicationName": "Temporary Application 2", - "buildCommand": "yarn install", + "buildCommand": "yarn install --no-lockfile", "tests": [ { "testName": "Example Test (Should Succeed)", From d5a5694ca0d5d1772161de3bf9d53597ef41d53f Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 15:06:38 +0000 Subject: [PATCH 12/22] Add readme --- packages/e2e-tests/README.md | 91 ++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 packages/e2e-tests/README.md diff --git a/packages/e2e-tests/README.md b/packages/e2e-tests/README.md new file mode 100644 index 000000000000..18babe21327c --- /dev/null +++ b/packages/e2e-tests/README.md @@ -0,0 +1,91 @@ +# E2E Tests + +E2E tests enable us to verify the behavior of the packages in this repository as if they were to be published in their current state. + +## How to run + +Prerequisites: Docker + +```bash +yarn test:e2e +``` + +## How they work + +Before running any tests we launch a fake test registry (in our case [Verdaccio](https://verdaccio.org/docs/e2e/)), we build our packages, pack them, and publish them to the fake registry. +The fake registry is hosted in a Docker container, and the script to publish the packages is also run from within a container to ensure that the fake publishing happens with the same Node.js and npm versions as we're using in CI. + +After publishing our freshly built packages to the fake registry, the E2E test script will look for `test-recipe.json` files in test applications located in the `test-applications` folder. +In this folder, we keep standalone test applications, that use our SDKs and can be used to verify their behavior. +The `test-recipe.json` recipe files contain information on how to build the test applications and how to run tests on these applications. + +## How to set up a new test + +Test applications are completely standalone applications that can be used to verify our SDKs. +To set one up, follow these commands: + +```sh +cd packages/e2e-tests + +# Create a new test application folder +mkdir test-applications/my-new-test-application # Name of the new folder doesn't technically matter but choose something meaningful + +# Create an npm configuration file that uses the fake test registry +cat > test-applications/my-new-test-application/.npmrc << EOF +@sentry:registry=http://localhost:4873 +@sentry-internal:registry=http://localhost:4873 +EOF + +# Add a gitignore that ignores lockfiles +cat > test-applications/my-new-test-application/.gitignore << EOF +yarn.lock +package-lock.json +EOF + +# Add a test recipe file to the test application +touch test-applications/my-new-test-application/test-recipe.json +``` + +To get you started with the recipe, you can copy the following into `test-recipe.json`: + +```json +{ + "$schema": "../../test-recipe-schema.json", + "testApplicationName": "My New Test Application", + "buildCommand": "yarn install --no-lockfile", + "tests": [ + { + "testName": "My new test", + "testCommand": "yarn test", + "timeoutSeconds": 60 + } + ] +} +``` + +The `test-recipe.json` files follow a schema (`e2e-tests/test-recipe-schema.json`). Here is a basic explanation of the fields: + +- The `buildCommand` command runs only once before any of the tests and is supposed to build the test application. If this command returns a non-zero exit code, it counts as a failed test and the test application's tests are not run. +- The `testCommand` command is supposed to run tests on the test application. If the configured command returns a non-zero exit code, it counts as a failed test. +- A test timeout can be configured via `timeoutSeconds`, it defaults to `60`. + +**An important thing to note:** In the context of the `buildCommand` the fake test registry is available at `http://localhost:4873`. It hosts all of our packages as if they were to be published with the state of the current branch. +This means we can install the packages from this registry via the `.npmrc` configuration as seen above. +If you add Sentry dependencies to your test application, you should set the dependency versions set to `*`: + +```jsonc +// package.json +{ + "name": "my-new-test-application", + "version": "1.0.0", + "private": true, + "scripts": { + "test": "echo \"Hello world!\"" + }, + "dependencies": { + "@sentry/node": "*" + } +} +``` + +All that is left for you to do now is to create a test app and run `yarn test:e2e`. From abe422557e07a561ccd43f13b23ada472d6639bf Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 15:25:33 +0000 Subject: [PATCH 13/22] Run prettier --- packages/e2e-tests/README.md | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/packages/e2e-tests/README.md b/packages/e2e-tests/README.md index 18babe21327c..fbf819dc6310 100644 --- a/packages/e2e-tests/README.md +++ b/packages/e2e-tests/README.md @@ -1,6 +1,7 @@ # E2E Tests -E2E tests enable us to verify the behavior of the packages in this repository as if they were to be published in their current state. +E2E tests enable us to verify the behavior of the packages in this repository as if they were to be published in their +current state. ## How to run @@ -12,17 +13,20 @@ yarn test:e2e ## How they work -Before running any tests we launch a fake test registry (in our case [Verdaccio](https://verdaccio.org/docs/e2e/)), we build our packages, pack them, and publish them to the fake registry. -The fake registry is hosted in a Docker container, and the script to publish the packages is also run from within a container to ensure that the fake publishing happens with the same Node.js and npm versions as we're using in CI. +Before running any tests we launch a fake test registry (in our case [Verdaccio](https://verdaccio.org/docs/e2e/)), we +build our packages, pack them, and publish them to the fake registry. The fake registry is hosted in a Docker container, +and the script to publish the packages is also run from within a container to ensure that the fake publishing happens +with the same Node.js and npm versions as we're using in CI. -After publishing our freshly built packages to the fake registry, the E2E test script will look for `test-recipe.json` files in test applications located in the `test-applications` folder. -In this folder, we keep standalone test applications, that use our SDKs and can be used to verify their behavior. -The `test-recipe.json` recipe files contain information on how to build the test applications and how to run tests on these applications. +After publishing our freshly built packages to the fake registry, the E2E test script will look for `test-recipe.json` +files in test applications located in the `test-applications` folder. In this folder, we keep standalone test +applications, that use our SDKs and can be used to verify their behavior. The `test-recipe.json` recipe files contain +information on how to build the test applications and how to run tests on these applications. ## How to set up a new test -Test applications are completely standalone applications that can be used to verify our SDKs. -To set one up, follow these commands: +Test applications are completely standalone applications that can be used to verify our SDKs. To set one up, follow +these commands: ```sh cd packages/e2e-tests @@ -63,15 +67,19 @@ To get you started with the recipe, you can copy the following into `test-recipe } ``` -The `test-recipe.json` files follow a schema (`e2e-tests/test-recipe-schema.json`). Here is a basic explanation of the fields: +The `test-recipe.json` files follow a schema (`e2e-tests/test-recipe-schema.json`). Here is a basic explanation of the +fields: -- The `buildCommand` command runs only once before any of the tests and is supposed to build the test application. If this command returns a non-zero exit code, it counts as a failed test and the test application's tests are not run. -- The `testCommand` command is supposed to run tests on the test application. If the configured command returns a non-zero exit code, it counts as a failed test. +- The `buildCommand` command runs only once before any of the tests and is supposed to build the test application. If + this command returns a non-zero exit code, it counts as a failed test and the test application's tests are not run. +- The `testCommand` command is supposed to run tests on the test application. If the configured command returns a + non-zero exit code, it counts as a failed test. - A test timeout can be configured via `timeoutSeconds`, it defaults to `60`. -**An important thing to note:** In the context of the `buildCommand` the fake test registry is available at `http://localhost:4873`. It hosts all of our packages as if they were to be published with the state of the current branch. -This means we can install the packages from this registry via the `.npmrc` configuration as seen above. -If you add Sentry dependencies to your test application, you should set the dependency versions set to `*`: +**An important thing to note:** In the context of the `buildCommand` the fake test registry is available at +`http://localhost:4873`. It hosts all of our packages as if they were to be published with the state of the current +branch. This means we can install the packages from this registry via the `.npmrc` configuration as seen above. If you +add Sentry dependencies to your test application, you should set the dependency versions set to `*`: ```jsonc // package.json From 5a44229b7818b5d176a63d2f0123c61cad801d7d Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 15:32:35 +0000 Subject: [PATCH 14/22] Run create-react-app --- .../create-react-app/.gitignore | 24 +++++++++ .../create-react-app/README.md | 46 ++++++++++++++++++ .../create-react-app/package.json | 43 ++++++++++++++++ .../create-react-app/public/favicon.ico | Bin 0 -> 3870 bytes .../create-react-app/public/index.html | 43 ++++++++++++++++ .../create-react-app/public/logo192.png | Bin 0 -> 5347 bytes .../create-react-app/public/logo512.png | Bin 0 -> 9664 bytes .../create-react-app/public/manifest.json | 25 ++++++++++ .../create-react-app/public/robots.txt | 3 ++ .../create-react-app/src/App.css | 38 +++++++++++++++ .../create-react-app/src/App.test.tsx | 9 ++++ .../create-react-app/src/App.tsx | 26 ++++++++++ .../create-react-app/src/index.css | 13 +++++ .../create-react-app/src/index.tsx | 19 ++++++++ .../create-react-app/src/logo.svg | 1 + .../create-react-app/src/reportWebVitals.ts | 15 ++++++ .../create-react-app/src/setupTests.ts | 5 ++ .../create-react-app/tsconfig.json | 26 ++++++++++ 18 files changed, 336 insertions(+) create mode 100644 packages/e2e-tests/test-applications/create-react-app/.gitignore create mode 100644 packages/e2e-tests/test-applications/create-react-app/README.md create mode 100644 packages/e2e-tests/test-applications/create-react-app/package.json create mode 100644 packages/e2e-tests/test-applications/create-react-app/public/favicon.ico create mode 100644 packages/e2e-tests/test-applications/create-react-app/public/index.html create mode 100644 packages/e2e-tests/test-applications/create-react-app/public/logo192.png create mode 100644 packages/e2e-tests/test-applications/create-react-app/public/logo512.png create mode 100644 packages/e2e-tests/test-applications/create-react-app/public/manifest.json create mode 100644 packages/e2e-tests/test-applications/create-react-app/public/robots.txt create mode 100644 packages/e2e-tests/test-applications/create-react-app/src/App.css create mode 100644 packages/e2e-tests/test-applications/create-react-app/src/App.test.tsx create mode 100644 packages/e2e-tests/test-applications/create-react-app/src/App.tsx create mode 100644 packages/e2e-tests/test-applications/create-react-app/src/index.css create mode 100644 packages/e2e-tests/test-applications/create-react-app/src/index.tsx create mode 100644 packages/e2e-tests/test-applications/create-react-app/src/logo.svg create mode 100644 packages/e2e-tests/test-applications/create-react-app/src/reportWebVitals.ts create mode 100644 packages/e2e-tests/test-applications/create-react-app/src/setupTests.ts create mode 100644 packages/e2e-tests/test-applications/create-react-app/tsconfig.json diff --git a/packages/e2e-tests/test-applications/create-react-app/.gitignore b/packages/e2e-tests/test-applications/create-react-app/.gitignore new file mode 100644 index 000000000000..7d3cec2ef6bd --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/.gitignore @@ -0,0 +1,24 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +yarn.lock diff --git a/packages/e2e-tests/test-applications/create-react-app/README.md b/packages/e2e-tests/test-applications/create-react-app/README.md new file mode 100644 index 000000000000..b58e0af830ec --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/README.md @@ -0,0 +1,46 @@ +# Getting Started with Create React App + +This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). + +## Available Scripts + +In the project directory, you can run: + +### `yarn start` + +Runs the app in the development mode.\ +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.\ +You will also see any lint errors in the console. + +### `yarn test` + +Launches the test runner in the interactive watch mode.\ +See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. + +### `yarn build` + +Builds the app for production to the `build` folder.\ +It correctly bundles React in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.\ +Your app is ready to be deployed! + +See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. + +### `yarn eject` + +**Note: this is a one-way operation. Once you `eject`, you can’t go back!** + +If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. + +Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. + +You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. + +## Learn More + +You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). + +To learn React, check out the [React documentation](https://reactjs.org/). diff --git a/packages/e2e-tests/test-applications/create-react-app/package.json b/packages/e2e-tests/test-applications/create-react-app/package.json new file mode 100644 index 000000000000..004ef32f0b40 --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/package.json @@ -0,0 +1,43 @@ +{ + "name": "my-app", + "version": "0.1.0", + "private": true, + "dependencies": { + "@testing-library/jest-dom": "^5.14.1", + "@testing-library/react": "^13.0.0", + "@testing-library/user-event": "^13.2.1", + "@types/jest": "^27.0.1", + "@types/node": "^16.7.13", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1", + "typescript": "^4.4.2", + "web-vitals": "^2.1.0" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/packages/e2e-tests/test-applications/create-react-app/public/favicon.ico b/packages/e2e-tests/test-applications/create-react-app/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a11777cc471a4344702741ab1c8a588998b1311a GIT binary patch literal 3870 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 baj7?x%VD!5Cxk2YbYLNVeiXvvpMCWYo=by@ literal 0 HcmV?d00001 diff --git a/packages/e2e-tests/test-applications/create-react-app/public/index.html b/packages/e2e-tests/test-applications/create-react-app/public/index.html new file mode 100644 index 000000000000..aa069f27cbd9 --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/public/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + React App + + + +
+ + + diff --git a/packages/e2e-tests/test-applications/create-react-app/public/logo192.png b/packages/e2e-tests/test-applications/create-react-app/public/logo192.png new file mode 100644 index 0000000000000000000000000000000000000000..fc44b0a3796c0e0a64c3d858ca038bd4570465d9 GIT binary patch literal 5347 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 b{|{}U^kRn2wo}j7|0ATu<;8xA7zX}7|B6mN literal 0 HcmV?d00001 diff --git a/packages/e2e-tests/test-applications/create-react-app/public/manifest.json b/packages/e2e-tests/test-applications/create-react-app/public/manifest.json new file mode 100644 index 000000000000..080d6c77ac21 --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/packages/e2e-tests/test-applications/create-react-app/public/robots.txt b/packages/e2e-tests/test-applications/create-react-app/public/robots.txt new file mode 100644 index 000000000000..e9e57dc4d41b --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/packages/e2e-tests/test-applications/create-react-app/src/App.css b/packages/e2e-tests/test-applications/create-react-app/src/App.css new file mode 100644 index 000000000000..74b5e053450a --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/src/App.css @@ -0,0 +1,38 @@ +.App { + text-align: center; +} + +.App-logo { + height: 40vmin; + pointer-events: none; +} + +@media (prefers-reduced-motion: no-preference) { + .App-logo { + animation: App-logo-spin infinite 20s linear; + } +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/packages/e2e-tests/test-applications/create-react-app/src/App.test.tsx b/packages/e2e-tests/test-applications/create-react-app/src/App.test.tsx new file mode 100644 index 000000000000..2a68616d9846 --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/src/App.test.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + render(); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/packages/e2e-tests/test-applications/create-react-app/src/App.tsx b/packages/e2e-tests/test-applications/create-react-app/src/App.tsx new file mode 100644 index 000000000000..a53698aab3c6 --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/src/App.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import logo from './logo.svg'; +import './App.css'; + +function App() { + return ( + + ); +} + +export default App; diff --git a/packages/e2e-tests/test-applications/create-react-app/src/index.css b/packages/e2e-tests/test-applications/create-react-app/src/index.css new file mode 100644 index 000000000000..ec2585e8c0bb --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/packages/e2e-tests/test-applications/create-react-app/src/index.tsx b/packages/e2e-tests/test-applications/create-react-app/src/index.tsx new file mode 100644 index 000000000000..032464fb6ec4 --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/src/index.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import './index.css'; +import App from './App'; +import reportWebVitals from './reportWebVitals'; + +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement +); +root.render( + + + +); + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals(); diff --git a/packages/e2e-tests/test-applications/create-react-app/src/logo.svg b/packages/e2e-tests/test-applications/create-react-app/src/logo.svg new file mode 100644 index 000000000000..9dfc1c058ceb --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/src/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/e2e-tests/test-applications/create-react-app/src/reportWebVitals.ts b/packages/e2e-tests/test-applications/create-react-app/src/reportWebVitals.ts new file mode 100644 index 000000000000..49a2a16e0fbc --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/src/reportWebVitals.ts @@ -0,0 +1,15 @@ +import { ReportHandler } from 'web-vitals'; + +const reportWebVitals = (onPerfEntry?: ReportHandler) => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/packages/e2e-tests/test-applications/create-react-app/src/setupTests.ts b/packages/e2e-tests/test-applications/create-react-app/src/setupTests.ts new file mode 100644 index 000000000000..8f2609b7b3e0 --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/src/setupTests.ts @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom'; diff --git a/packages/e2e-tests/test-applications/create-react-app/tsconfig.json b/packages/e2e-tests/test-applications/create-react-app/tsconfig.json new file mode 100644 index 000000000000..a273b0cfc0e9 --- /dev/null +++ b/packages/e2e-tests/test-applications/create-react-app/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "include": [ + "src" + ] +} From d7050517d83a3cc65743dd572fbc7474d4533899 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Wed, 28 Sep 2022 15:41:41 +0000 Subject: [PATCH 15/22] Add Sentry --- .../create-react-app/README.md | 46 ------------------- .../create-react-app/package.json | 26 ++++++----- .../create-react-app/public/index.html | 5 +- .../create-react-app/src/App.tsx | 37 ++++++++------- .../create-react-app/src/index.css | 8 ++-- .../create-react-app/src/index.tsx | 17 +++++-- .../create-react-app/tsconfig.json | 12 ++--- 7 files changed, 55 insertions(+), 96 deletions(-) delete mode 100644 packages/e2e-tests/test-applications/create-react-app/README.md diff --git a/packages/e2e-tests/test-applications/create-react-app/README.md b/packages/e2e-tests/test-applications/create-react-app/README.md deleted file mode 100644 index b58e0af830ec..000000000000 --- a/packages/e2e-tests/test-applications/create-react-app/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Getting Started with Create React App - -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). - -## Available Scripts - -In the project directory, you can run: - -### `yarn start` - -Runs the app in the development mode.\ -Open [http://localhost:3000](http://localhost:3000) to view it in the browser. - -The page will reload if you make edits.\ -You will also see any lint errors in the console. - -### `yarn test` - -Launches the test runner in the interactive watch mode.\ -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. - -### `yarn build` - -Builds the app for production to the `build` folder.\ -It correctly bundles React in production mode and optimizes the build for the best performance. - -The build is minified and the filenames include the hashes.\ -Your app is ready to be deployed! - -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. - -### `yarn eject` - -**Note: this is a one-way operation. Once you `eject`, you can’t go back!** - -If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. - -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. - -You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). diff --git a/packages/e2e-tests/test-applications/create-react-app/package.json b/packages/e2e-tests/test-applications/create-react-app/package.json index 004ef32f0b40..201f636468ad 100644 --- a/packages/e2e-tests/test-applications/create-react-app/package.json +++ b/packages/e2e-tests/test-applications/create-react-app/package.json @@ -1,20 +1,22 @@ { - "name": "my-app", + "name": "create-react-app-test", "version": "0.1.0", "private": true, "dependencies": { - "@testing-library/jest-dom": "^5.14.1", - "@testing-library/react": "^13.0.0", - "@testing-library/user-event": "^13.2.1", - "@types/jest": "^27.0.1", - "@types/node": "^16.7.13", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "@sentry/react": "*", + "@sentry/tracing": "*", + "@testing-library/jest-dom": "5.14.1", + "@testing-library/react": "13.0.0", + "@testing-library/user-event": "13.2.1", + "@types/jest": "27.0.1", + "@types/node": "16.7.13", + "@types/react": "18.0.0", + "@types/react-dom": "18.0.0", + "react": "18.2.0", + "react-dom": "18.2.0", "react-scripts": "5.0.1", - "typescript": "^4.4.2", - "web-vitals": "^2.1.0" + "typescript": "4.4.2", + "web-vitals": "2.1.0" }, "scripts": { "start": "react-scripts start", diff --git a/packages/e2e-tests/test-applications/create-react-app/public/index.html b/packages/e2e-tests/test-applications/create-react-app/public/index.html index aa069f27cbd9..6a9f8c26bb7b 100644 --- a/packages/e2e-tests/test-applications/create-react-app/public/index.html +++ b/packages/e2e-tests/test-applications/create-react-app/public/index.html @@ -5,10 +5,7 @@ - +