Skip to content

Commit

Permalink
Make tests faster (#1719)
Browse files Browse the repository at this point in the history
* add notes and todo list

* safely repeating changes from add-cjs-loader-resolve to remember what I did and filter any WIP mess I may have forgotten about

* more sync

* fix downloaded artifacts

* sync

* sync

* sync

* sync

* cleanup

* sync node-internal-modules-cjs-loader-old.js with raw

* sync internal/modules/package_json_reader with new naming convention

* sync node-internal-modules-cjs-loader; rename back to old name

* sync

* more sync of filenames

* sync node-internal-errors

* lint-fix

* fix

* fix

* further alignment

* fix

* fix

* upgrade v8-compile-cache-lib to get rid of eventemitter warning in tests

* Make tests faster

* make tests faster

* more speed

* try running fewer tests up-front to give quicker test feedback

* try running fewer tests up-front to give quicker test feedback

* try running fewer tests up-front to give quicker test feedback

* try running fewer tests up-front to give quicker test feedback

* simplify changes to CI
  • Loading branch information
cspotcode committed Apr 16, 2022
1 parent 97f4ecf commit ccff67d
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 89 deletions.
1 change: 1 addition & 0 deletions .github/workflows/continuous-integration.yml
Expand Up @@ -173,6 +173,7 @@ jobs:
- run: |
npm config set cache "$( node -p "process.cwd()" )/temp/npm-cache"
- name: Cache dependencies
if: ${{ matrix.os != 'windows' }}
uses: actions/cache@v2
with:
path: temp/npm-cache
Expand Down
6 changes: 6 additions & 0 deletions src/test/helpers.ts
Expand Up @@ -22,6 +22,10 @@ export const ROOT_DIR = resolve(__dirname, '../..');
export const DIST_DIR = resolve(__dirname, '..');
export const TEST_DIR = join(__dirname, '../../tests');
export const PROJECT = join(TEST_DIR, 'tsconfig.json');
export const PROJECT_TRANSPILE_ONLY = join(
TEST_DIR,
'tsconfig-transpile-only.json'
);
export const BIN_PATH = join(TEST_DIR, 'node_modules/.bin/ts-node');
export const BIN_PATH_JS = join(TEST_DIR, 'node_modules/ts-node/dist/bin.js');
export const BIN_SCRIPT_PATH = join(
Expand All @@ -35,6 +39,8 @@ export const BIN_ESM_PATH = join(TEST_DIR, 'node_modules/.bin/ts-node-esm');
//#region command lines
/** Default `ts-node --project` invocation */
export const CMD_TS_NODE_WITH_PROJECT_FLAG = `"${BIN_PATH}" --project "${PROJECT}"`;
/** Default `ts-node --project` invocation with transpile-only */
export const CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG = `"${BIN_PATH}" --project "${PROJECT_TRANSPILE_ONLY}"`;
/** Default `ts-node` invocation without `--project` */
export const CMD_TS_NODE_WITHOUT_PROJECT_FLAG = `"${BIN_PATH}"`;
export const EXPERIMENTAL_MODULES_FLAG = semver.gte(process.version, '12.17.0')
Expand Down
154 changes: 69 additions & 85 deletions src/test/index.spec.ts
Expand Up @@ -5,6 +5,7 @@ import { tmpdir } from 'os';
import semver = require('semver');
import {
BIN_PATH_JS,
CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG,
nodeSupportsEsmHooks,
ts,
tsSupportsShowConfig,
Expand Down Expand Up @@ -143,7 +144,10 @@ test.suite('ts-node', (test) => {

test('should execute cli with absolute path', async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} "${join(TEST_DIR, 'hello-world')}"`
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} "${join(
TEST_DIR,
'hello-world'
)}"`
);
expect(err).toBe(null);
expect(stdout).toBe('Hello, world!\n');
Expand All @@ -157,26 +161,18 @@ test.suite('ts-node', (test) => {
expect(stdout).toBe('example\n');
});

test('should provide registered information globally', async () => {
test("should expose ts-node Service as a symbol property on Node's `process` object", async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} env`
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} env`
);
expect(err).toBe(null);
expect(stdout).toBe('object\n');
});

test('should provide registered information on register', async () => {
const { err, stdout } = await exec(`node -r ts-node/register env.ts`, {
cwd: TEST_DIR,
});
expect(err).toBe(null);
expect(stdout).toBe('object\n');
});

test('should allow js', async () => {
const { err, stdout } = await exec(
[
CMD_TS_NODE_WITH_PROJECT_FLAG,
CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG,
'-O "{\\"allowJs\\":true}"',
'-pe "import { main } from \'./allow-js/run\';main()"',
].join(' ')
Expand All @@ -188,7 +184,7 @@ test.suite('ts-node', (test) => {
test('should include jsx when `allow-js` true', async () => {
const { err, stdout } = await exec(
[
CMD_TS_NODE_WITH_PROJECT_FLAG,
CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG,
'-O "{\\"allowJs\\":true}"',
'-pe "import { Foo2 } from \'./allow-js/with-jsx\'; Foo2.sayHi()"',
].join(' ')
Expand All @@ -199,21 +195,21 @@ test.suite('ts-node', (test) => {

test('should eval code', async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} -e "import * as m from './module';console.log(m.example('test'))"`
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} -e "import * as m from './module';console.log(m.example('test'))"`
);
expect(err).toBe(null);
expect(stdout).toBe('TEST\n');
});

test('should import empty files', async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} -e "import './empty'"`
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} -e "import './empty'"`
);
expect(err).toBe(null);
expect(stdout).toBe('');
});

test('should throw errors', async () => {
test('should throw typechecking errors', async () => {
const { err } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} -e "import * as m from './module';console.log(m.example(123))"`
);
Expand Down Expand Up @@ -377,15 +373,17 @@ test.suite('ts-node', (test) => {
}

test('should pipe into `ts-node` and evaluate', async () => {
const execPromise = exec(CMD_TS_NODE_WITH_PROJECT_FLAG);
const execPromise = exec(CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG);
execPromise.child.stdin!.end("console.log('hello')");
const { err, stdout } = await execPromise;
expect(err).toBe(null);
expect(stdout).toBe('hello\n');
});

test('should pipe into `ts-node`', async () => {
const execPromise = exec(`${CMD_TS_NODE_WITH_PROJECT_FLAG} -p`);
const execPromise = exec(
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} -p`
);
execPromise.child.stdin!.end('true');
const { err, stdout } = await execPromise;
expect(err).toBe(null);
Expand All @@ -404,15 +402,15 @@ test.suite('ts-node', (test) => {

test('should support require flags', async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} -r ./hello-world -pe "console.log('success')"`
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} -r ./hello-world -pe "console.log('success')"`
);
expect(err).toBe(null);
expect(stdout).toBe('Hello, world!\nsuccess\nundefined\n');
});

test('should support require from node modules', async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} -r typescript -e "console.log('success')"`
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} -r typescript -e "console.log('success')"`
);
expect(err).toBe(null);
expect(stdout).toBe('success\n');
Expand Down Expand Up @@ -458,36 +456,25 @@ test.suite('ts-node', (test) => {
);
});

test('should preserve `ts-node` context with child process', async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} child-process`
);
expect(err).toBe(null);
expect(stdout).toBe('Hello, world!\n');
});

test('should import js before ts by default', async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} import-order/compiled`
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} import-order/compiled`
);
expect(err).toBe(null);
expect(stdout).toBe('Hello, JavaScript!\n');
});

const preferTsExtsEntrypoint = semver.gte(process.version, '12.0.0')
? 'import-order/compiled'
: 'import-order/require-compiled';
test('should import ts before js when --prefer-ts-exts flag is present', async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} --prefer-ts-exts ${preferTsExtsEntrypoint}`
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} --prefer-ts-exts import-order/compiled`
);
expect(err).toBe(null);
expect(stdout).toBe('Hello, TypeScript!\n');
});

test('should import ts before js when TS_NODE_PREFER_TS_EXTS env is present', async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} ${preferTsExtsEntrypoint}`,
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} import-order/compiled`,
{
env: { ...process.env, TS_NODE_PREFER_TS_EXTS: 'true' },
}
Expand All @@ -498,7 +485,7 @@ test.suite('ts-node', (test) => {

test('should ignore .d.ts files', async () => {
const { err, stdout } = await exec(
`${CMD_TS_NODE_WITH_PROJECT_FLAG} import-order/importer`
`${CMD_TS_NODE_WITH_PROJECT_TRANSPILE_ONLY_FLAG} import-order/importer`
);
expect(err).toBe(null);
expect(stdout).toBe('Hello, World!\n');
Expand Down Expand Up @@ -538,63 +525,60 @@ test.suite('ts-node', (test) => {
});
});

if (semver.gte(ts.version, '2.7.0')) {
test('should locate tsconfig relative to entry-point by default', async () => {
const { err, stdout } = await exec(`${BIN_PATH} ../a/index`, {
cwd: join(TEST_DIR, 'cwd-and-script-mode/b'),
});
expect(err).toBe(null);
expect(stdout).toMatch(/plugin-a/);
test('should locate tsconfig relative to entry-point by default', async () => {
const { err, stdout } = await exec(`${BIN_PATH} ../a/index`, {
cwd: join(TEST_DIR, 'cwd-and-script-mode/b'),
});
test('should locate tsconfig relative to entry-point via ts-node-script', async () => {
const { err, stdout } = await exec(`${BIN_SCRIPT_PATH} ../a/index`, {
cwd: join(TEST_DIR, 'cwd-and-script-mode/b'),
});
expect(err).toBe(null);
expect(stdout).toMatch(/plugin-a/);
});
test('should locate tsconfig relative to entry-point with --script-mode', async () => {
const { err, stdout } = await exec(
`${BIN_PATH} --script-mode ../a/index`,
{
cwd: join(TEST_DIR, 'cwd-and-script-mode/b'),
}
);
expect(err).toBe(null);
expect(stdout).toMatch(/plugin-a/);
expect(err).toBe(null);
expect(stdout).toMatch(/plugin-a/);
});
test('should locate tsconfig relative to entry-point via ts-node-script', async () => {
const { err, stdout } = await exec(`${BIN_SCRIPT_PATH} ../a/index`, {
cwd: join(TEST_DIR, 'cwd-and-script-mode/b'),
});
test('should locate tsconfig relative to cwd via ts-node-cwd', async () => {
const { err, stdout } = await exec(`${BIN_CWD_PATH} ../a/index`, {
expect(err).toBe(null);
expect(stdout).toMatch(/plugin-a/);
});
test('should locate tsconfig relative to entry-point with --script-mode', async () => {
const { err, stdout } = await exec(
`${BIN_PATH} --script-mode ../a/index`,
{
cwd: join(TEST_DIR, 'cwd-and-script-mode/b'),
});
expect(err).toBe(null);
expect(stdout).toMatch(/plugin-b/);
}
);
expect(err).toBe(null);
expect(stdout).toMatch(/plugin-a/);
});
test('should locate tsconfig relative to cwd via ts-node-cwd', async () => {
const { err, stdout } = await exec(`${BIN_CWD_PATH} ../a/index`, {
cwd: join(TEST_DIR, 'cwd-and-script-mode/b'),
});
test('should locate tsconfig relative to cwd in --cwd-mode', async () => {
expect(err).toBe(null);
expect(stdout).toMatch(/plugin-b/);
});
test('should locate tsconfig relative to cwd in --cwd-mode', async () => {
const { err, stdout } = await exec(`${BIN_PATH} --cwd-mode ../a/index`, {
cwd: join(TEST_DIR, 'cwd-and-script-mode/b'),
});
expect(err).toBe(null);
expect(stdout).toMatch(/plugin-b/);
});
test('should locate tsconfig relative to realpath, not symlink, when entrypoint is a symlink', async (t) => {
if (
lstatSync(
join(TEST_DIR, 'main-realpath/symlink/symlink.tsx')
).isSymbolicLink()
) {
const { err, stdout } = await exec(
`${BIN_PATH} --cwd-mode ../a/index`,
{ cwd: join(TEST_DIR, 'cwd-and-script-mode/b') }
`${BIN_PATH} main-realpath/symlink/symlink.tsx`
);
expect(err).toBe(null);
expect(stdout).toMatch(/plugin-b/);
});
test('should locate tsconfig relative to realpath, not symlink, when entrypoint is a symlink', async (t) => {
if (
lstatSync(
join(TEST_DIR, 'main-realpath/symlink/symlink.tsx')
).isSymbolicLink()
) {
const { err, stdout } = await exec(
`${BIN_PATH} main-realpath/symlink/symlink.tsx`
);
expect(err).toBe(null);
expect(stdout).toBe('');
} else {
t.log('Skipping');
return;
}
});
}
expect(stdout).toBe('');
} else {
t.log('Skipping');
return;
}
});

test.suite('should read ts-node options from tsconfig.json', (test) => {
const BIN_EXEC = `"${BIN_PATH}" --project tsconfig-options/tsconfig.json`;
Expand Down
4 changes: 2 additions & 2 deletions src/test/register.spec.ts
@@ -1,7 +1,7 @@
import { once } from 'lodash';
import {
contextTsNodeUnderTest,
PROJECT,
PROJECT_TRANSPILE_ONLY,
resetNodeEnvironment,
TEST_DIR,
tsNodeTypes,
Expand All @@ -16,7 +16,7 @@ const SOURCE_MAP_REGEXP =
/\/\/# sourceMappingURL=data:application\/json;charset=utf\-8;base64,[\w\+]+=*$/;

const createOptions: tsNodeTypes.CreateOptions = {
project: PROJECT,
project: PROJECT_TRANSPILE_ONLY,
compilerOptions: {
jsx: 'preserve',
},
Expand Down
3 changes: 3 additions & 0 deletions tests/cwd-and-script-mode/a/tsconfig.json
@@ -1,4 +1,7 @@
{
"ts-node": {
"transpileOnly": true
},
"compilerOptions": {
"plugins": [
{
Expand Down
3 changes: 3 additions & 0 deletions tests/cwd-and-script-mode/b/tsconfig.json
@@ -1,4 +1,7 @@
{
"ts-node": {
"transpileOnly": true
},
"compilerOptions": {
"plugins": [
{
Expand Down
3 changes: 3 additions & 0 deletions tests/esm-import-assertions/tsconfig.json
@@ -1,4 +1,7 @@
{
"ts-node": {
"transpileOnly": true
},
"compilerOptions": {
"module": "ESNext",
"target": "ESNext",
Expand Down
2 changes: 0 additions & 2 deletions tests/import-order/require-compiled.js

This file was deleted.

3 changes: 3 additions & 0 deletions tests/main-realpath/target/tsconfig.json
@@ -1,4 +1,7 @@
{
"ts-node": {
"transpileOnly": true
},
"compilerOptions": {
"jsx": "react"
}
Expand Down
4 changes: 4 additions & 0 deletions tests/recursive-fork/index.ts
@@ -1,5 +1,9 @@
import { fork } from 'child_process';

// Type syntax to prove its compiled, though the import above should also
// prove the same
const a = null as any;

console.log(JSON.stringify({ execArgv: process.execArgv, argv: process.argv }));
if (process.env.generation !== 'grandchild') {
const nextGeneration =
Expand Down
13 changes: 13 additions & 0 deletions tests/tsconfig-transpile-only.json
@@ -0,0 +1,13 @@
{
"ts-node": {
"transpileOnly": true
},
"compilerOptions": {
"target": "es2015",
"jsx": "react",
"noEmit": true,
"strict": true,
// Global type definitions.
"typeRoots": ["./typings", "../node_modules/@types"]
}
}

0 comments on commit ccff67d

Please sign in to comment.