Skip to content

Commit 1efabf4

Browse files
authored
Cleanup test macros (#1724)
* WIP tweaking repl test macros to be cleaner, follow simpler ava conventions * test cleanup
1 parent 5d325b5 commit 1efabf4

15 files changed

+202
-179
lines changed

CONTRIBUTING.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,30 @@ We have a debug configuration for VSCode.
5454
Note that some tests might misbehave in the debugger. REPL tests in particular. I'm not sure why, but I think it is related to how `console` does not write to
5555
stdout when in a debug session.
5656

57+
### Test Context
58+
59+
Ava has the concept of test "context", an object which can store reusable fields common across many tests.
60+
61+
By convention, any functions that setup reusable context start with `ctx`, making them easier to tab-complete and auto-import while writing tests.
62+
63+
See `ctxTsNode` for an example.
64+
65+
Context setup functions are re-executed for each test case. If you don't want this, wrap the context function in lodash `once()`. Each test will still get a unique context object, but the values placed onto each context will be identical.
66+
67+
Every `ctx*` function has a namespace with `Ctx` and `T` types. These make it easier/cleaner to write tests.
68+
69+
### Test Macros
70+
71+
Ava has the concept of test "macros", reusable functions which can declare a type of test many times with different inputs.
72+
73+
Macro functions are created with `test.macro()`.
74+
75+
By convention, if a macro function is meant to be imported and reused in multiple files, its name should start with `macro`.
76+
77+
Macros can also be declared to require a certain "context," thanks to the namespace types described in "Test Context" above.
78+
79+
See examples in `helpers.ts`.
80+
5781
## Documentation
5882

5983
Documentation is written in markdown in `website/docs` and rendered into a website by Docusaurus. The README is also generated from these markdown files.

src/test/diagnostics.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { TSError } from '..';
2-
import { contextTsNodeUnderTest, ts } from './helpers';
2+
import { ctxTsNode, ts } from './helpers';
33
import { context, expect } from './testlib';
44
import * as semver from 'semver';
55
import { once } from 'lodash';
6-
const test = context(contextTsNodeUnderTest);
6+
const test = context(ctxTsNode);
77

88
test.suite('TSError diagnostics', ({ context }) => {
99
const test = context(

src/test/esm-loader.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
BIN_PATH_JS,
1111
CMD_ESM_LOADER_WITHOUT_PROJECT,
1212
CMD_TS_NODE_WITHOUT_PROJECT_FLAG,
13-
contextTsNodeUnderTest,
13+
ctxTsNode,
1414
delay,
1515
EXPERIMENTAL_MODULES_FLAG,
1616
nodeSupportsEsmHooks,
@@ -26,7 +26,7 @@ import * as expect from 'expect';
2626
import type { NodeLoaderHooksAPI2 } from '../';
2727
import { pathToFileURL } from 'url';
2828

29-
const test = context(contextTsNodeUnderTest);
29+
const test = context(ctxTsNode);
3030

3131
const exec = createExec({
3232
cwd: TEST_DIR,
@@ -233,8 +233,8 @@ test.suite('esm', (test) => {
233233
});
234234
});
235235

236-
test.suite('unit test hooks', (_test) => {
237-
const test = _test.context(async (t) => {
236+
test.suite('unit test hooks', ({ context }) => {
237+
const test = context(async (t) => {
238238
const service = t.context.tsNodeUnderTest.create({
239239
cwd: TEST_DIR,
240240
});

src/test/helpers.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type * as tsNodeTypes from '../index';
1414
import type _createRequire from 'create-require';
1515
import { has, mapValues, once } from 'lodash';
1616
import semver = require('semver');
17+
import type { ExecutionContext } from './testlib';
1718
const createRequire: typeof _createRequire = require('create-require');
1819
export { tsNodeTypes };
1920

@@ -79,13 +80,17 @@ export const tsSupportsShowConfig = semver.gte(ts.version, '3.2.0');
7980
export const xfs = new NodeFS(fs);
8081

8182
/** Pass to `test.context()` to get access to the ts-node API under test */
82-
export const contextTsNodeUnderTest = once(async () => {
83+
export const ctxTsNode = once(async () => {
8384
await installTsNode();
8485
const tsNodeUnderTest: typeof tsNodeTypes = testsDirRequire('ts-node');
8586
return {
8687
tsNodeUnderTest,
8788
};
8889
});
90+
export namespace ctxTsNode {
91+
export type Ctx = Awaited<ReturnType<typeof ctxTsNode>>;
92+
export type T = ExecutionContext<Ctx>;
93+
}
8994

9095
//#region install ts-node tarball
9196
const ts_node_install_lock = process.env.ts_node_install_lock as string;

src/test/index.spec.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { _test } from './testlib';
1+
import { context } from './testlib';
22
import * as expect from 'expect';
33
import { join, resolve, sep as pathSep } from 'path';
44
import { tmpdir } from 'os';
@@ -14,7 +14,6 @@ import {
1414
import { lstatSync, mkdtempSync } from 'fs';
1515
import { npath } from '@yarnpkg/fslib';
1616
import type _createRequire from 'create-require';
17-
import { pathToFileURL } from 'url';
1817
import { createExec } from './exec-helpers';
1918
import {
2019
BIN_CWD_PATH,
@@ -26,18 +25,17 @@ import {
2625
testsDirRequire,
2726
tsNodeTypes,
2827
xfs,
29-
contextTsNodeUnderTest,
28+
ctxTsNode,
3029
CMD_TS_NODE_WITH_PROJECT_FLAG,
3130
CMD_TS_NODE_WITHOUT_PROJECT_FLAG,
3231
CMD_ESM_LOADER_WITHOUT_PROJECT,
33-
EXPERIMENTAL_MODULES_FLAG,
3432
} from './helpers';
3533

3634
const exec = createExec({
3735
cwd: TEST_DIR,
3836
});
3937

40-
const test = _test.context(contextTsNodeUnderTest);
38+
const test = context(ctxTsNode);
4139

4240
test.suite('ts-node', (test) => {
4341
test('should export the correct version', (t) => {
@@ -709,8 +707,8 @@ test.suite('ts-node', (test) => {
709707

710708
test.suite(
711709
'should use implicit @tsconfig/bases config when one is not loaded from disk',
712-
(_test) => {
713-
const test = _test.context(async (t) => ({
710+
({ context }) => {
711+
const test = context(async (t) => ({
714712
tempDir: mkdtempSync(join(tmpdir(), 'ts-node-spec')),
715713
}));
716714
if (
@@ -941,8 +939,8 @@ test.suite('ts-node', (test) => {
941939
});
942940
});
943941

944-
test.suite('create', (_test) => {
945-
const test = _test.context(async (t) => {
942+
test.suite('create', ({ context }) => {
943+
const test = context(async (t) => {
946944
return {
947945
service: t.context.tsNodeUnderTest.create({
948946
compilerOptions: { target: 'es5' },
Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { context } from './testlib';
22
import {
3-
contextTsNodeUnderTest,
3+
ctxTsNode,
44
resetNodeEnvironment,
55
TEST_DIR,
66
tsSupportsTsconfigInheritanceViaNodePackages,
77
} from './helpers';
88
import * as expect from 'expect';
99
import { resolve } from 'path';
1010

11-
const test = context(contextTsNodeUnderTest);
11+
const test = context(ctxTsNode);
1212

1313
test.suite(
1414
'Pluggable dependency (compiler, transpiler, swc backend) is require()d relative to the tsconfig file that declares it',
@@ -26,74 +26,80 @@ test.suite(
2626
// ts-node should resolve ts-patch or @swc/core relative to the extended tsconfig
2727
// to ensure we use the known working versions.
2828

29-
const macro = _macro.bind(null, test);
29+
const macro = test.macro((config: string, expected: string) => [
30+
`${config} uses ${expected}`,
31+
async (t) => {
32+
t.teardown(resetNodeEnvironment);
33+
34+
const output = t.context.tsNodeUnderTest
35+
.create({
36+
project: resolve(TEST_DIR, 'pluggable-dep-resolution', config),
37+
})
38+
.compile('', 'index.ts');
3039

31-
macro('tsconfig-custom-compiler.json', 'root custom compiler');
32-
macro('tsconfig-custom-transpiler.json', 'root custom transpiler');
33-
macro('tsconfig-swc-custom-backend.json', 'root custom swc backend');
34-
macro('tsconfig-swc-core.json', 'root @swc/core');
35-
macro('tsconfig-swc-wasm.json', 'root @swc/wasm');
36-
macro('tsconfig-swc.json', 'root @swc/core');
40+
expect(output).toContain(`emit from ${expected}\n`);
41+
},
42+
]);
3743

38-
macro(
44+
test(macro, 'tsconfig-custom-compiler.json', 'root custom compiler');
45+
test(macro, 'tsconfig-custom-transpiler.json', 'root custom transpiler');
46+
test(macro, 'tsconfig-swc-custom-backend.json', 'root custom swc backend');
47+
test(macro, 'tsconfig-swc-core.json', 'root @swc/core');
48+
test(macro, 'tsconfig-swc-wasm.json', 'root @swc/wasm');
49+
test(macro, 'tsconfig-swc.json', 'root @swc/core');
50+
51+
test(
52+
macro,
3953
'node_modules/shared-config/tsconfig-custom-compiler.json',
4054
'shared-config custom compiler'
4155
);
42-
macro(
56+
test(
57+
macro,
4358
'node_modules/shared-config/tsconfig-custom-transpiler.json',
4459
'shared-config custom transpiler'
4560
);
46-
macro(
61+
test(
62+
macro,
4763
'node_modules/shared-config/tsconfig-swc-custom-backend.json',
4864
'shared-config custom swc backend'
4965
);
50-
macro(
66+
test(
67+
macro,
5168
'node_modules/shared-config/tsconfig-swc-core.json',
5269
'shared-config @swc/core'
5370
);
54-
macro(
71+
test(
72+
macro,
5573
'node_modules/shared-config/tsconfig-swc-wasm.json',
5674
'shared-config @swc/wasm'
5775
);
58-
macro(
76+
test(
77+
macro,
5978
'node_modules/shared-config/tsconfig-swc.json',
6079
'shared-config @swc/core'
6180
);
6281

6382
test.suite('"extends"', (test) => {
6483
test.runIf(tsSupportsTsconfigInheritanceViaNodePackages);
6584

66-
const macro = _macro.bind(null, test);
67-
68-
macro(
85+
test(
86+
macro,
6987
'tsconfig-extend-custom-compiler.json',
7088
'shared-config custom compiler'
7189
);
72-
macro(
90+
test(
91+
macro,
7392
'tsconfig-extend-custom-transpiler.json',
7493
'shared-config custom transpiler'
7594
);
76-
macro(
95+
test(
96+
macro,
7797
'tsconfig-extend-swc-custom-backend.json',
7898
'shared-config custom swc backend'
7999
);
80-
macro('tsconfig-extend-swc-core.json', 'shared-config @swc/core');
81-
macro('tsconfig-extend-swc-wasm.json', 'shared-config @swc/wasm');
82-
macro('tsconfig-extend-swc.json', 'shared-config @swc/core');
100+
test(macro, 'tsconfig-extend-swc-core.json', 'shared-config @swc/core');
101+
test(macro, 'tsconfig-extend-swc-wasm.json', 'shared-config @swc/wasm');
102+
test(macro, 'tsconfig-extend-swc.json', 'shared-config @swc/core');
83103
});
84-
85-
function _macro(_test: typeof test, config: string, expected: string) {
86-
_test(`${config} uses ${expected}`, async (t) => {
87-
t.teardown(resetNodeEnvironment);
88-
89-
const output = t.context.tsNodeUnderTest
90-
.create({
91-
project: resolve(TEST_DIR, 'pluggable-dep-resolution', config),
92-
})
93-
.compile('', 'index.ts');
94-
95-
expect(output).toContain(`emit from ${expected}\n`);
96-
});
97-
}
98104
}
99105
);

src/test/register.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { once } from 'lodash';
22
import {
3-
contextTsNodeUnderTest,
3+
ctxTsNode,
44
PROJECT_TRANSPILE_ONLY,
55
resetNodeEnvironment,
66
TEST_DIR,
@@ -22,7 +22,7 @@ const createOptions: tsNodeTypes.CreateOptions = {
2222
},
2323
};
2424

25-
const test = context(contextTsNodeUnderTest).context(
25+
const test = context(ctxTsNode).context(
2626
once(async (t) => {
2727
return {
2828
moduleTestPath: resolve(__dirname, '../../tests/module.ts'),

src/test/regression.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { join } from 'path';
55
import { createExec, createExecTester } from './exec-helpers';
66
import {
77
CMD_TS_NODE_WITHOUT_PROJECT_FLAG,
8-
contextTsNodeUnderTest,
8+
ctxTsNode,
99
TEST_DIR,
1010
} from './helpers';
11-
import { test as _test } from './testlib';
11+
import { context } from './testlib';
1212

13-
const test = _test.context(contextTsNodeUnderTest);
13+
const test = context(ctxTsNode);
1414
const exec = createExecTester({
1515
exec: createExec({
1616
cwd: TEST_DIR,

0 commit comments

Comments
 (0)