dev-packages/e2e-tests/README.md
Warning
These test applications are not intended to be used as example apps or templates. They may contain:
- Outdated or deprecated dependency versions used for backwards compatibility testing
- Known security vulnerabilities in dependencies that we intentionally test against
- Non-production-ready configurations and code patterns
For official examples and best practices, please refer to our official documentation.
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.
Prerequisites: Docker
.env.example to .env.env for an example Sentry project - you only need this to run E2E tests that
send data to Sentry.yarn build:tarball in the root of the repository (needs to be rerun after every update in /packages for the
changes to have effect on the tests).To finally run all of the tests:
yarn test:e2e
Or run only a single E2E test app:
yarn test:run <app-name>
Or you can run a single E2E test app with a specific variant:
yarn test:run <app-name> --variant <variant-name>
Variant name matching is case-insensitive and partial. For example, --variant 13 will match nextjs-pages-dir (next@13) if a matching variant is present in the test app's package.json.
Alternatively, you can use the provided Makefile for an interactive test selection experience:
Prerequisites: Install fzf with Homebrew:
brew install fzf
Run tests interactively:
make run
This will display a fuzzy-finder menu of all available test applications. Select one to run it automatically.
List all test applications:
make list
For example, if you have the following variants in your test app's package.json:
"sentryTest": {
"variants": [
{
"build-command": "pnpm test:build-13",
"label": "nextjs-pages-dir (next@13)"
},
{
"build-command": "pnpm test:build-13-canary",
"label": "nextjs-pages-dir (next@13-canary)"
},
{
"build-command": "pnpm test:build-15",
"label": "nextjs-pages-dir (next@15)"
}
]
}
If you run yarn test:run nextjs-pages-dir --variant 13, it will match against the very first matching variant, which is nextjs-pages-dir (next@13). If you need to target the second variant in the example, you need to be more specific and use --variant 13-canary.
Before running any tests we launch a fake test registry (in our case Verdaccio), 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.
Test applications are completely standalone applications that can be used to verify our SDKs. To set one up, follow these commands:
cd dev-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://127.0.0.1:4873
@sentry-internal:registry=http://127.0.0.1:4873
EOF
Make sure to add a test:build and test:assert command to the new app's package.json file.
.npmrc FileEvery test application needs an .npmrc file (as shown above) to tell pnpm to fetch @sentry/* and @sentry-internal/* packages from the local Verdaccio registry. Without it, pnpm will install from the public npm registry and your local changes won't be tested - this is one of the most common causes of confusing test failures.
To verify packages are being installed from Verdaccio, check the version in node_modules/@sentry/*/package.json. If it shows something like 0.0.0-pr.12345, Verdaccio is working. If it shows a released version (e.g., 8.0.0), the .npmrc is missing or incorrect.
.npmrc file (see above)yarn build && yarn build:tarballnode_modules in the test application and re-run the testlsof -i :4873docker ps and docker stop <container-id>.npmrc file@sentry/* dependencies use latest || * version specifierdebug: true to the Sentry init config to see detailed SDK logscat node_modules/@sentry/browser/package.json | grep versionDifferent bundlers handle environment variables and code replacement differently. This is important when writing tests or SDK code that relies on build-time constants.
DefinePlugin replaces variables in your application codenode_modulesdefine option replaces variables in your application codenode_modulesimport.meta.env.VITE_* variables are replaced at build time@rollup/plugin-replaceprocess.env via webpack/turbopackimport.meta.env Considerationsimport.meta.envimport.meta.env must use try-catch to handle environments where it doesn't exist// Safe pattern for SDK code
let envValue: string | undefined;
try {
envValue = import.meta.env.VITE_SOME_VAR;
} catch {
// import.meta.env not available in this bundler
}
Test apps in the folder test-applications will be automatically picked up by CI in the job job_e2e_tests (in .github/workflows/build.yml).
The test matrix for CI is generated in dev-packages/e2e-tests/lib/getTestMatrix.mjs.
For each test app, CI checks its dependencies (and devDependencies) to see if any of them have changed in the current PR (based on nx affected projects). For example, if something is changed in the browser package, only E2E test apps that depend on browser will run, while others will be skipped.
You can add additional information about the test (e.g. canary versions, optional in CI) by adding sentryTest in the package.json
of a test application.
An important thing to note: In the context of the build/test commands the fake test registry is available at
http://127.0.0.1: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 latest || * in order
for it to work with both regular and prerelease versions:
// package.json
{
"name": "my-new-test-application",
"version": "1.0.0",
"private": true,
"scripts": {
"test": "echo \"Hello world!\"",
"test:build": "pnpm install",
"test:assert": "pnpm test",
},
"dependencies": {
"@sentry/node": "latest || *",
},
}
All that is left for you to do now is to create a test app and run yarn test:e2e.
For some of our E2E tests we define a standard for test applications as to how they should look and behave. Standardized test apps enables us to reuse the same test suite over a number of different frameworks/SDKs.
TODO: This is not up to date.
A standardized frontend test application has the following features:
Just for the sake of consistency we prefix the standardized frontend tests with standard-frontend-. For example
standard-frontend-nextjs.
A page at path /
<input type="button" id="exception-button"> that captures an Exception when clicked. The returned
eventId from the Sentry.captureException() call must be written to window.capturedExceptionId. It does not
matter what the captured error looks like.id="navigation" that navigates to /user/5. It doesn't have to be an <a> tag, for example
if a framework has another way of doing routing, the important part is that the element to click for navigation has
the correct id. Text of the link doesn't matter.An empty page at /user/5
Apps should write all pageload and navigation transaction IDs into an array at window.recordedTransactions. This can
be done with an event processor:
Sentry.addEventProcessor(event => {
if (
event.type === 'transaction' &&
(event.contexts?.trace?.op === 'pageload' || event.contexts?.trace?.op === 'navigation')
) {
const eventId = event.event_id;
window.recordedTransactions = window.recordedTransactions || [];
window.recordedTransactions.push(eventId);
}
return event;
});
TBD
A standardized Meta-Framework test application has the following features:
/user/:id that returns a JSON object with the user ID./user/:id that fetches the user data on the client-side from the API route and displays it.This setup creates the scenario where the frontend page loads, and then immediately makes an API request to the backend API.
The following test cases for connected tracing should be implemented in the test app:
/user/5 should be captured as /user/:id routehttp.client span that is the parent of the server API request spanhttp.client span should share the same trace_idtransaction names and the span description should be parameterized, e.g. /user/5 should be captured as /user/:id route