|  | 
| 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'; | 
| 3 | 4 | 
 | 
| 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]; | 
| 6 | 6 | 
 | 
| 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 | +]; | 
| 11 | 20 | 
 | 
| 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]']; | 
| 13 | 30 | 
 | 
| 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 | +} | 
| 17 | 38 | 
 | 
| 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 | +} | 
| 22 | 47 | 
 | 
| 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 transformers written in TS, the legacy version does not. | 
|  | 57 | +  run('yarn tsc --skipLibCheck jest/transformers/constReplacer.ts'); | 
| 31 | 58 | 
 | 
| 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'); | 
| 42 | 64 | 
 | 
| 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']; | 
| 55 | 67 | 
 | 
| 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 | +  ); | 
| 57 | 78 | 
 | 
| 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); | 
| 60 | 82 | } | 
| 61 | 83 | 
 | 
| 62 |  | -const ignoreFlags = ignorePackages.map(dep => `--ignore="${dep}"`).join(' '); | 
|  | 84 | +/** | 
|  | 85 | + * Skip tests which don't apply to Node and 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 | +} | 
| 63 | 94 | 
 | 
| 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 | +} | 
| 65 | 126 | 
 | 
| 66 |  | -process.exit(0); | 
|  | 127 | +runTests(); | 
0 commit comments