-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
test: Add build-time tests for node & bundler plugins #23618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
61 changes: 61 additions & 0 deletions
61
dev-packages/e2e-tests/test-applications/node-esbuild/assert.mjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| /** | ||
| * Asserts that `sentryEsbuildPlugin` performs build-time instrumentation: its code transform injects | ||
| * the orchestrion "bundler ran" banner into the entry chunk. A plain build (no plugin) does not. | ||
| * | ||
| * @module | ||
| */ | ||
| import { readdirSync, readFileSync } from 'node:fs'; | ||
| import { dirname, join } from 'node:path'; | ||
| import { fileURLToPath } from 'node:url'; | ||
|
|
||
| const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
|
|
||
| // A distinctive slice of the orchestrion banner that the bundler plugin's build-time code transform | ||
| // prepends to the entry chunk (see `ORCHESTRION_BUNDLER_MARKER_BANNER` in `@sentry/server-utils`). | ||
| // It is emitted only when the plugin's build-time instrumentation runs, so it tells a `plugin` build | ||
| // apart from a `plain` one. Before matching we strip block comments and whitespace, because bundlers | ||
| // format the injected banner differently — Rolldown pretty-prints it and inserts a `/* @__PURE__ */` | ||
| // annotation. The banner initializes the set with `new Set()`, hence the stripped `newSet()` form. | ||
| const BUILD_TIME_TRANSFORM_MARKER = 'g.bundler=g.bundler||newSet()'; | ||
|
|
||
| function bundleText(name) { | ||
| const files = []; | ||
| const walk = dir => { | ||
| for (const entry of readdirSync(dir, { withFileTypes: true })) { | ||
| const full = join(dir, entry.name); | ||
| if (entry.isDirectory()) { | ||
| walk(full); | ||
| } else { | ||
| files.push(full); | ||
| } | ||
| } | ||
| }; | ||
| walk(join(__dirname, 'dist', name)); | ||
| return files | ||
| .map(f => readFileSync(f, 'utf8')) | ||
| .join('\n') | ||
| .replace(/\/\*[\s\S]*?\*\//g, '') | ||
| .replace(/\s+/g, ''); | ||
| } | ||
|
|
||
| let failed = false; | ||
| function check(condition, message) { | ||
| // eslint-disable-next-line no-console | ||
| console.log(`${condition ? 'ok ' : 'FAIL'} - ${message}`); | ||
| if (!condition) failed = true; | ||
| } | ||
|
|
||
| const plain = bundleText('plain'); | ||
| const plugin = bundleText('plugin'); | ||
|
|
||
| check(!plain.includes(BUILD_TIME_TRANSFORM_MARKER), 'plain build (no plugin) does not run build-time instrumentation'); | ||
| check( | ||
| plugin.includes(BUILD_TIME_TRANSFORM_MARKER), | ||
| 'sentryEsbuildPlugin runs build-time instrumentation (injects the orchestrion banner)', | ||
| ); | ||
|
|
||
| if (failed) { | ||
| process.exit(1); | ||
| } | ||
| // eslint-disable-next-line no-console | ||
| console.log('All bundle assertions passed.'); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. l: this logic is duplicated for every test in this PR, should we consolidate this? |
||
41 changes: 41 additions & 0 deletions
41
dev-packages/e2e-tests/test-applications/node-esbuild/build.mjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| // Bundles the entrypoint with esbuild twice: | ||
| // - `plain`: no Sentry plugin. | ||
| // - `plugin`: with `sentryEsbuildPlugin` (build-time instrumentation). | ||
| // Only the `plugin` build runs the orchestrion code transform, which prepends the "bundler ran" | ||
| // banner to the entry chunk. Kept unminified so the banner keeps its identifiers (a minifier would | ||
| // rename them); assert.mjs matches it whitespace-insensitively. | ||
| import { dirname, join } from 'node:path'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| import { build } from 'esbuild'; | ||
| import { sentryEsbuildPlugin } from '@sentry/node/esbuild'; | ||
|
|
||
| const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
|
|
||
| function run(name, plugins) { | ||
| return build({ | ||
| entryPoints: [join(__dirname, 'src', 'entry.mjs')], | ||
| outdir: join(__dirname, 'dist', name), | ||
| bundle: true, | ||
| platform: 'node', | ||
| format: 'esm', | ||
| minify: false, | ||
| logLevel: 'silent', | ||
| plugins, | ||
| }); | ||
| } | ||
|
|
||
| await run('plain', []); | ||
| await run( | ||
| 'plugin', | ||
| // No auth/release/telemetry — we only care about the build-time transforms and defines. | ||
| [ | ||
| sentryEsbuildPlugin({ | ||
| telemetry: false, | ||
| sourcemaps: { disable: true }, | ||
| release: { create: false, finalize: false, inject: false }, | ||
| }), | ||
| ], | ||
| ); | ||
|
|
||
| // eslint-disable-next-line no-console | ||
| console.log('built plain + plugin with esbuild'); |
23 changes: 23 additions & 0 deletions
23
dev-packages/e2e-tests/test-applications/node-esbuild/package.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| { | ||
| "name": "node-esbuild", | ||
| "description": "ensure the Sentry esbuild plugin performs build-time instrumentation", | ||
| "version": "1.0.0", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "clean": "npx rimraf node_modules dist pnpm-lock.yaml", | ||
| "test:build": "pnpm install && node ./build.mjs", | ||
| "test:assert": "node ./assert.mjs" | ||
| }, | ||
| "dependencies": { | ||
| "@sentry/node": "file:../../packed/sentry-node-packed.tgz", | ||
| "@sentry/server-utils": "file:../../packed/sentry-server-utils-packed.tgz", | ||
| "@sentry/bundler-plugins": "file:../../packed/sentry-bundler-plugins-packed.tgz" | ||
| }, | ||
| "devDependencies": { | ||
| "esbuild": "0.28.2" | ||
| }, | ||
| "volta": { | ||
| "extends": "../../package.json" | ||
| } | ||
| } |
File renamed without changes.
File renamed without changes.
41 changes: 0 additions & 41 deletions
41
dev-packages/e2e-tests/test-applications/node-orchestrion-webpack/assert.mjs
This file was deleted.
Oops, something went wrong.
61 changes: 61 additions & 0 deletions
61
dev-packages/e2e-tests/test-applications/node-rolldown/assert.mjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| /** | ||
| * Asserts that `sentryRollupPlugin` performs build-time instrumentation when bundling with Rolldown: its code transform injects | ||
| * the orchestrion "bundler ran" banner into the entry chunk. A plain build (no plugin) does not. | ||
| * | ||
| * @module | ||
| */ | ||
| import { readdirSync, readFileSync } from 'node:fs'; | ||
| import { dirname, join } from 'node:path'; | ||
| import { fileURLToPath } from 'node:url'; | ||
|
|
||
| const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
|
|
||
| // A distinctive slice of the orchestrion banner that the bundler plugin's build-time code transform | ||
| // prepends to the entry chunk (see `ORCHESTRION_BUNDLER_MARKER_BANNER` in `@sentry/server-utils`). | ||
| // It is emitted only when the plugin's build-time instrumentation runs, so it tells a `plugin` build | ||
| // apart from a `plain` one. Before matching we strip block comments and whitespace, because bundlers | ||
| // format the injected banner differently — Rolldown pretty-prints it and inserts a `/* @__PURE__ */` | ||
| // annotation. The banner initializes the set with `new Set()`, hence the stripped `newSet()` form. | ||
| const BUILD_TIME_TRANSFORM_MARKER = 'g.bundler=g.bundler||newSet()'; | ||
|
|
||
| function bundleText(name) { | ||
| const files = []; | ||
| const walk = dir => { | ||
| for (const entry of readdirSync(dir, { withFileTypes: true })) { | ||
| const full = join(dir, entry.name); | ||
| if (entry.isDirectory()) { | ||
| walk(full); | ||
| } else { | ||
| files.push(full); | ||
| } | ||
| } | ||
| }; | ||
| walk(join(__dirname, 'dist', name)); | ||
| return files | ||
| .map(f => readFileSync(f, 'utf8')) | ||
| .join('\n') | ||
| .replace(/\/\*[\s\S]*?\*\//g, '') | ||
| .replace(/\s+/g, ''); | ||
| } | ||
|
|
||
| let failed = false; | ||
| function check(condition, message) { | ||
| // eslint-disable-next-line no-console | ||
| console.log(`${condition ? 'ok ' : 'FAIL'} - ${message}`); | ||
| if (!condition) failed = true; | ||
| } | ||
|
|
||
| const plain = bundleText('plain'); | ||
| const plugin = bundleText('plugin'); | ||
|
|
||
| check(!plain.includes(BUILD_TIME_TRANSFORM_MARKER), 'plain build (no plugin) does not run build-time instrumentation'); | ||
| check( | ||
| plugin.includes(BUILD_TIME_TRANSFORM_MARKER), | ||
| 'sentryRollupPlugin runs build-time instrumentation (injects the orchestrion banner)', | ||
| ); | ||
|
|
||
| if (failed) { | ||
| process.exit(1); | ||
| } | ||
| // eslint-disable-next-line no-console | ||
| console.log('All bundle assertions passed.'); |
42 changes: 42 additions & 0 deletions
42
dev-packages/e2e-tests/test-applications/node-rolldown/build.mjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| // Bundles the entrypoint with Rolldown twice: | ||
| // - `plain`: no Sentry plugin. | ||
| // - `plugin`: with `sentryRollupPlugin` (build-time instrumentation). | ||
| // Only the `plugin` build runs the orchestrion code transform, which prepends the "bundler ran" | ||
| // banner to the entry chunk. Kept unminified so the banner keeps its identifiers (a minifier would | ||
| // rename them); assert.mjs matches it whitespace-insensitively. | ||
| // Rolldown is Rollup API-compatible, so it consumes the same `@sentry/node/rollup` plugin; it also | ||
| // resolves node modules and CommonJS natively, so no extra resolve/commonjs plugins are needed. | ||
| import { builtinModules } from 'node:module'; | ||
| import { dirname, join } from 'node:path'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| import { rolldown } from 'rolldown'; | ||
| import { sentryRollupPlugin } from '@sentry/node/rollup'; | ||
|
|
||
| const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
| const external = [...builtinModules, ...builtinModules.map(m => `node:${m}`)]; | ||
|
|
||
| async function run(name, extra) { | ||
| const bundle = await rolldown({ | ||
| input: join(__dirname, 'src', 'entry.mjs'), | ||
| external, | ||
| plugins: [...extra], | ||
| onwarn: () => {}, | ||
| }); | ||
| await bundle.write({ dir: join(__dirname, 'dist', name), format: 'es', entryFileNames: 'main.mjs' }); | ||
| await bundle.close(); | ||
| } | ||
|
|
||
| await run('plain', []); | ||
| await run( | ||
| 'plugin', | ||
| // `sentryRollupPlugin` returns an array of Rollup plugins. No auth/release/telemetry — we only care | ||
| // about the build-time transforms and defines. | ||
| sentryRollupPlugin({ | ||
| telemetry: false, | ||
| sourcemaps: { disable: true }, | ||
| release: { create: false, finalize: false, inject: false }, | ||
| }), | ||
| ); | ||
|
|
||
| // eslint-disable-next-line no-console | ||
| console.log('built plain + plugin with rolldown'); |
23 changes: 23 additions & 0 deletions
23
dev-packages/e2e-tests/test-applications/node-rolldown/package.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| { | ||
| "name": "node-rolldown", | ||
| "description": "ensure the Sentry rollup plugin performs build-time instrumentation when bundling with rolldown", | ||
| "version": "1.0.0", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "clean": "npx rimraf node_modules dist pnpm-lock.yaml", | ||
| "test:build": "pnpm install && node ./build.mjs", | ||
| "test:assert": "node ./assert.mjs" | ||
| }, | ||
| "dependencies": { | ||
| "@sentry/node": "file:../../packed/sentry-node-packed.tgz", | ||
| "@sentry/server-utils": "file:../../packed/sentry-server-utils-packed.tgz", | ||
| "@sentry/bundler-plugins": "file:../../packed/sentry-bundler-plugins-packed.tgz" | ||
| }, | ||
| "devDependencies": { | ||
| "rolldown": "1.2.5" | ||
| }, | ||
| "volta": { | ||
| "extends": "../../package.json" | ||
| } | ||
| } |
2 changes: 2 additions & 0 deletions
2
dev-packages/e2e-tests/test-applications/node-rolldown/src/app.mjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| // eslint-disable-next-line no-console | ||
| console.log('this is the application'); |
9 changes: 9 additions & 0 deletions
9
dev-packages/e2e-tests/test-applications/node-rolldown/src/entry.mjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import * as Sentry from '@sentry/node'; | ||
|
|
||
| Sentry.init({ | ||
| traceLifecycle: 'static', | ||
| dsn: 'https://public@dsn.ingest.sentry.io/1337', | ||
| tracesSampleRate: 1, | ||
| }); | ||
|
|
||
| await import('./app.mjs'); |
61 changes: 61 additions & 0 deletions
61
dev-packages/e2e-tests/test-applications/node-rollup/assert.mjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| /** | ||
| * Asserts that `sentryRollupPlugin` performs build-time instrumentation: its code transform injects | ||
| * the orchestrion "bundler ran" banner into the entry chunk. A plain build (no plugin) does not. | ||
| * | ||
| * @module | ||
| */ | ||
| import { readdirSync, readFileSync } from 'node:fs'; | ||
| import { dirname, join } from 'node:path'; | ||
| import { fileURLToPath } from 'node:url'; | ||
|
|
||
| const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
|
|
||
| // A distinctive slice of the orchestrion banner that the bundler plugin's build-time code transform | ||
| // prepends to the entry chunk (see `ORCHESTRION_BUNDLER_MARKER_BANNER` in `@sentry/server-utils`). | ||
| // It is emitted only when the plugin's build-time instrumentation runs, so it tells a `plugin` build | ||
| // apart from a `plain` one. Before matching we strip block comments and whitespace, because bundlers | ||
| // format the injected banner differently — Rolldown pretty-prints it and inserts a `/* @__PURE__ */` | ||
| // annotation. The banner initializes the set with `new Set()`, hence the stripped `newSet()` form. | ||
| const BUILD_TIME_TRANSFORM_MARKER = 'g.bundler=g.bundler||newSet()'; | ||
|
|
||
| function bundleText(name) { | ||
| const files = []; | ||
| const walk = dir => { | ||
| for (const entry of readdirSync(dir, { withFileTypes: true })) { | ||
| const full = join(dir, entry.name); | ||
| if (entry.isDirectory()) { | ||
| walk(full); | ||
| } else { | ||
| files.push(full); | ||
| } | ||
| } | ||
| }; | ||
| walk(join(__dirname, 'dist', name)); | ||
| return files | ||
| .map(f => readFileSync(f, 'utf8')) | ||
| .join('\n') | ||
| .replace(/\/\*[\s\S]*?\*\//g, '') | ||
| .replace(/\s+/g, ''); | ||
| } | ||
|
|
||
| let failed = false; | ||
| function check(condition, message) { | ||
| // eslint-disable-next-line no-console | ||
| console.log(`${condition ? 'ok ' : 'FAIL'} - ${message}`); | ||
| if (!condition) failed = true; | ||
| } | ||
|
|
||
| const plain = bundleText('plain'); | ||
| const plugin = bundleText('plugin'); | ||
|
|
||
| check(!plain.includes(BUILD_TIME_TRANSFORM_MARKER), 'plain build (no plugin) does not run build-time instrumentation'); | ||
| check( | ||
| plugin.includes(BUILD_TIME_TRANSFORM_MARKER), | ||
| 'sentryRollupPlugin runs build-time instrumentation (injects the orchestrion banner)', | ||
| ); | ||
|
|
||
| if (failed) { | ||
| process.exit(1); | ||
| } | ||
| // eslint-disable-next-line no-console | ||
| console.log('All bundle assertions passed.'); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
L: similar to Nico's comment - this is also duplicated in all the tests.