Skip to content

Commit 0bc6985

Browse files
committed
reorganize test script and fix transformer use in node 8
1 parent 7ce86b2 commit 0bc6985

File tree

1 file changed

+113
-52
lines changed

1 file changed

+113
-52
lines changed

scripts/test.ts

Lines changed: 113 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,127 @@
1-
import { spawnSync } from 'child_process';
2-
import { join } from 'path';
1+
import * as childProcess from 'child_process';
2+
import * as fs from 'fs';
3+
import * as path from 'path';
34

4-
function run(cmd: string, cwd: string = '') {
5-
const result = spawnSync(cmd, { shell: true, stdio: 'inherit', cwd: join(__dirname, '..', cwd || '') });
5+
const CURRENT_NODE_VERSION = process.version.replace('v', '').split('.')[0];
66

7-
if (result.status !== 0) {
8-
process.exit(result.status || undefined);
9-
}
10-
}
7+
// We run ember tests in their own job.
8+
const DEFAULT_SKIP_TESTS_PACKAGES = ['@sentry/ember'];
9+
// These packages don't support Node 8 for syntax or dependency reasons.
10+
const NODE_8_SKIP_TESTS_PACKAGES = [
11+
...DEFAULT_SKIP_TESTS_PACKAGES,
12+
'@sentry-internal/eslint-plugin-sdk',
13+
'@sentry/react',
14+
'@sentry/wasm',
15+
'@sentry/gatsby',
16+
'@sentry/serverless',
17+
'@sentry/nextjs',
18+
'@sentry/angular',
19+
];
1120

12-
const nodeMajorVersion = parseInt(process.version.split('.')[0].replace('v', ''), 10);
21+
// We have to downgrade some of our dependencies in order to run tests in Node 8 and 10.
22+
const NODE_8_LEGACY_DEPENDENCIES = [
23+
24+
25+
26+
27+
28+
];
29+
const NODE_10_LEGACY_DEPENDENCIES = ['[email protected]'];
1330

14-
// Ember tests require dependency changes for each set of tests, making them quite slow. To compensate for this, in CI
15-
// we run them in a separate, parallel job.
16-
let ignorePackages = ['@sentry/ember'];
31+
/**
32+
* Run the given shell command, piping the shell process's `stdin`, `stdout`, and `stderr` to that of the current
33+
* process. Returns contents of `stdout`.
34+
*/
35+
function run(cmd: string, options?: childProcess.ExecSyncOptions) {
36+
return childProcess.execSync(cmd, { stdio: 'inherit', ...options });
37+
}
1738

18-
// install legacy versions of third-party packages whose current versions don't support node 8 or 10, and skip testing
19-
// our own packages which don't support node 8 for various syntax or dependency reasons
20-
if (nodeMajorVersion <= 10) {
21-
let legacyDependencies;
39+
/**
40+
* Install the given legacy dependencies, for compatibility with tests run in older versions of Node.
41+
*/
42+
function installLegacyDeps(legacyDeps: string[] = []): void {
43+
// Ignoring engines and scripts lets us get away with having incompatible things installed for SDK packages we're not
44+
// testing in the current node version, and ignoring the root check lets us install things at the repo root.
45+
run(`yarn add --dev --ignore-engines --ignore-scripts --ignore-workspace-root-check ${legacyDeps.join(' ')}`);
46+
}
2247

23-
if (nodeMajorVersion === 8) {
24-
legacyDependencies = [
25-
26-
27-
28-
29-
30-
];
48+
/**
49+
* Add a tranformer to our jest config, to do the same `const`-to-`var` replacement as our rollup plugin does.
50+
*
51+
* This is needed because Node 8 doesn't like the way we shadow `global` (`const global = getGlobalObject()`). Changing
52+
* it to a `var` solves this by making it redeclarable.
53+
*
54+
*/
55+
function addTransformer(): void {
56+
// Though newer ts-jest versions support TS transformers, the legacy version does not.
57+
run('yarn tsc --skipLibCheck jest/transformers/constReplacer.ts');
3158

32-
ignorePackages = [
33-
...ignorePackages,
34-
'@sentry-internal/eslint-plugin-sdk',
35-
'@sentry/react',
36-
'@sentry/wasm',
37-
'@sentry/gatsby',
38-
'@sentry/serverless',
39-
'@sentry/nextjs',
40-
'@sentry/angular',
41-
];
59+
// Loading the existing Jest config will error out unless the config file has an accompanying types file, so we have
60+
// to create that before we can load it.
61+
run('yarn tsc --allowJs --skipLibCheck --declaration --emitDeclarationOnly jest/jest.config.js');
62+
// eslint-disable-next-line @typescript-eslint/no-var-requires
63+
const jestConfig = require('../jest/jest.config.js');
4264

43-
// This is a hack, to deal the fact that the browser-based tests fail under Node 8, because of a conflict buried
44-
// somewhere in the interaction between our current overall set of dependencies and the older versions of a small
45-
// subset we're about to install below. Since they're browser-based, these tests are never going to be running in a
46-
// node 8 environment in any case, so it's fine to skip them here. (In the long run, we should only run such tests
47-
// against a single version of node, but in the short run, this at least allows us to not be blocked by the
48-
// failures.)
49-
run('rm -rf packages/tracing/test/browser');
50-
}
51-
// Node 10
52-
else {
53-
legacyDependencies = ['[email protected]'];
54-
}
65+
// Inject the transformer
66+
jestConfig.globals['ts-jest'].astTransformers = ['<rootDir>/../../jest/transformers/constReplacer.js'];
5567

56-
const legacyDepStr = legacyDependencies.join(' ');
68+
// When we required the jest config file above, all expressions it contained were evaluated. Specifically, the
69+
// `rootDir: process.cwd()`
70+
// entry was replaced with
71+
// `rootDir: "<hard-coded string result of running `process.cwd()` in the current process>"`,
72+
// Though it's a little brute-force-y, the easiest way to fix this is to just stringify the code and perform the
73+
// substitution in reverse.
74+
const stringifiedConfig = JSON.stringify(jestConfig, null, 2).replace(
75+
`"rootDir": "${process.cwd()}"`,
76+
'rootDir: process.cwd()',
77+
);
5778

58-
// ignoring engines and scripts lets us get away with having incompatible things installed for packages we're not testing
59-
run(`yarn add --dev --ignore-engines --ignore-scripts --ignore-workspace-root-check ${legacyDepStr}`);
79+
// Now we just have to convert it back to a module and write it to disk
80+
const code = `module.exports = ${stringifiedConfig}`;
81+
fs.writeFileSync(path.resolve('jest/jest.config.js'), code);
6082
}
6183

62-
const ignoreFlags = ignorePackages.map(dep => `--ignore="${dep}"`).join(' ');
84+
/**
85+
* Skip tests which don't apply to Node than therefore don't need to run in older Node versions.
86+
*
87+
* TODO We're foreced to skip these tests for compatibility reasons (right now this function only gets called in Node
88+
* 8), but we could be skipping a lot more tests in Node 8-14 - anything where compatibility with different Node
89+
* versions is irrelevant - and only running them in Node 16.
90+
*/
91+
function skipNonNodeTests(): void {
92+
run('rm -rf packages/tracing/test/browser');
93+
}
6394

64-
run(`yarn test ${ignoreFlags}`);
95+
/**
96+
* Run tests, ignoring the given packages
97+
*/
98+
function runWithIgnores(skipPackages: string[] = []): void {
99+
const ignoreFlags = skipPackages.map(dep => `--ignore="${dep}"`).join(' ');
100+
run(`yarn test ${ignoreFlags}`);
101+
}
102+
103+
/**
104+
* Run the tests, accounting for compatibility problems in older versions of Node.
105+
*/
106+
function runTests(): void {
107+
if (CURRENT_NODE_VERSION === '8') {
108+
installLegacyDeps(NODE_8_LEGACY_DEPENDENCIES);
109+
// Inject a `const`-to-`var` transformer, in order to stop Node 8 from complaining when we shadow `global`
110+
addTransformer();
111+
// TODO Right now, this just skips incompatible tests, but it could be skipping more (hence the aspirational name),
112+
// and not just in Node 8. See `skipNonNodeTests`'s docstring.
113+
skipNonNodeTests();
114+
runWithIgnores(NODE_8_SKIP_TESTS_PACKAGES);
115+
}
116+
//
117+
else if (CURRENT_NODE_VERSION === '10') {
118+
installLegacyDeps(NODE_10_LEGACY_DEPENDENCIES);
119+
runWithIgnores(DEFAULT_SKIP_TESTS_PACKAGES);
120+
}
121+
//
122+
else {
123+
runWithIgnores(DEFAULT_SKIP_TESTS_PACKAGES);
124+
}
125+
}
65126

66-
process.exit(0);
127+
runTests();

0 commit comments

Comments
 (0)