Skip to content

Commit 78c6a9d

Browse files
authored
test(e2e): Add Node SDK re-exports consistency e2e test (getsentry#10389)
Introduce an e2e test that checks if all `@sentry/node` exports were re-exported in packages that depend on `@sentry/node`. It's not a real e2e test, as there's no actual test application, but we only execute a script that imports various SDKs depending on `@sentry/node`. However, IMO it makes a lot of sense to test the export of the final tarballs which we already have the infrastructure for in our e2e tests. see PR description for more details
1 parent 87ad0fe commit 78c6a9d

File tree

6 files changed

+169
-0
lines changed

6 files changed

+169
-0
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,7 @@ jobs:
913913
'generic-ts3.8',
914914
'node-experimental-fastify-app',
915915
'node-hapi-app',
916+
'node-exports-test-app',
916917
]
917918
build-command:
918919
- false
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sentry:registry=http://127.0.0.1:4873
2+
@sentry-internal:registry=http://127.0.0.1:4873
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Consistent Node Export Test
2+
3+
This test "app" ensures that we consistently re-export exports from `@sentry/node` in packages depending on
4+
`@sentry/node`.
5+
6+
## How to add new package
7+
8+
1. Add package as a dependency to the test app
9+
2. In `scripts/consistentExports.ts`:
10+
- add namespace import
11+
- add `DEPENDENTS` entry
12+
- add any ignores/exclusion entries as necessary
13+
- if the package is still under development, you can also set `skip: true`
14+
15+
## Limitations:
16+
17+
- This script only checks top-level exports for now (e.g. `metrics` but no sub-exports like `metrics.increment`)
18+
- This script only checks ESM transpiled code for now, not CJS
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "node-express-app",
3+
"version": "1.0.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"build": "tsc",
8+
"start": "pnpm build && node dist/consistentExports.js",
9+
"test": " node dist/consistentExports.js",
10+
"clean": "npx rimraf node_modules,pnpm-lock.yaml,dist",
11+
"test:build": "pnpm install && pnpm build",
12+
"test:assert": "pnpm test"
13+
},
14+
"dependencies": {
15+
"@sentry/node": "latest || *",
16+
"@sentry/sveltekit": "latest || *",
17+
"@sentry/remix": "latest || *",
18+
"@sentry/astro": "latest || *",
19+
"@sentry/nextjs": "latest || *",
20+
"@sentry/serverless": "latest || *",
21+
"@sentry/bun": "latest || *",
22+
"@sentry/types": "latest || *",
23+
"@types/node": "18.15.1",
24+
"typescript": "4.9.5"
25+
},
26+
"devDependencies": {
27+
"ts-node": "10.9.1"
28+
},
29+
"volta": {
30+
"extends": "../../package.json"
31+
}
32+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import * as SentryAstro from '@sentry/astro';
2+
// import * as SentryBun from '@sentry/bun';
3+
import * as SentryNextJs from '@sentry/nextjs';
4+
import * as SentryNode from '@sentry/node';
5+
import * as SentryRemix from '@sentry/remix';
6+
import * as SentryServerless from '@sentry/serverless';
7+
import * as SentrySvelteKit from '@sentry/sveltekit';
8+
9+
/* List of exports that are safe to ignore / we don't require in any depending package */
10+
const NODE_EXPORTS_IGNORE = [
11+
'default',
12+
// Probably generated by transpilation, no need to require it
13+
'__esModule',
14+
// this function was deprecates almost immediately after it was introduced
15+
// due to a name change (startSpan). No need to re-export it IMHO.
16+
'startActiveSpan',
17+
// this was never meant for external use (and documented as such)
18+
'trace',
19+
// These Node exports were only made for type definition fixes (see #10339)
20+
'Undici',
21+
'Http',
22+
'DebugSession',
23+
'AnrIntegrationOptions',
24+
'LocalVariablesIntegrationOptions',
25+
// deprecated
26+
'spanStatusfromHttpCode',
27+
];
28+
29+
type Dependent = {
30+
package: string;
31+
exports: string[];
32+
ignoreExports?: string[];
33+
skip?: boolean;
34+
};
35+
36+
const DEPENDENTS: Dependent[] = [
37+
{
38+
package: '@sentry/astro',
39+
exports: Object.keys(SentryAstro),
40+
},
41+
{
42+
package: '@sentry/nextjs',
43+
// Next.js doesn't require explicit exports, so we can just merge top level and `default` exports:
44+
// @ts-expect-error: `default` is not in the type definition but it's defined
45+
exports: Object.keys({ ...SentryNextJs, ...SentryNextJs.default }),
46+
ignoreExports: ['withSentryConfig'],
47+
},
48+
{
49+
package: '@sentry/remix',
50+
exports: Object.keys(SentryRemix),
51+
// TODO: Fix exports in remix
52+
skip: true,
53+
},
54+
{
55+
package: '@sentry/serverless',
56+
exports: Object.keys(SentryServerless),
57+
ignoreExports: [
58+
// Deprecated, no need to add this now to serverless
59+
'extractTraceparentData',
60+
'getModuleFromFilename',
61+
// TODO: Should these be exported from serverless?
62+
'cron',
63+
'enableAnrDetection',
64+
'runWithAsyncContext',
65+
'hapiErrorPlugin',
66+
],
67+
// TODO: Fix exports in serverless
68+
skip: true,
69+
},
70+
{
71+
package: '@sentry/sveltekit',
72+
exports: Object.keys(SentrySvelteKit),
73+
// TODO: Fix exports in sveltekit
74+
skip: true,
75+
},
76+
];
77+
78+
/* Sanitized list of node exports */
79+
const nodeExports = Object.keys(SentryNode).filter(e => !NODE_EXPORTS_IGNORE.includes(e));
80+
81+
console.log('🔎 Checking for consistent exports of @sentry/node exports in depending packages');
82+
83+
const missingExports: Record<string, string[]> = {};
84+
const dependentsToCheck = DEPENDENTS.filter(d => !d.skip);
85+
86+
for (const nodeExport of nodeExports) {
87+
for (const dependent of dependentsToCheck) {
88+
if (dependent.ignoreExports?.includes(nodeExport)) {
89+
continue;
90+
}
91+
if (!dependent.exports.includes(nodeExport)) {
92+
missingExports[dependent.package] = [...(missingExports[dependent.package] ?? []), nodeExport];
93+
}
94+
}
95+
}
96+
97+
if (Object.keys(missingExports).length > 0) {
98+
console.error('\n❌ Found missing exports from @sentry/node in the following packages:\n');
99+
console.log(JSON.stringify(missingExports, null, 2));
100+
process.exit(1);
101+
}
102+
103+
console.log('✅ All good :)');
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"compilerOptions": {
3+
"types": ["node"],
4+
"esModuleInterop": true,
5+
"lib": ["ES6"],
6+
"strict": true,
7+
"outDir": "dist",
8+
"target": "ESNext",
9+
"moduleResolution": "node",
10+
"skipLibCheck": true
11+
},
12+
"include": ["scripts/**/*.ts"]
13+
}

0 commit comments

Comments
 (0)