Skip to content

Commit 32584f3

Browse files
committed
init
1 parent 96b4ae4 commit 32584f3

14 files changed

+166
-83
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/.nyc_output
22
/coverage
33
/node_modules
4+
/test/fixtures/compiled

README.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
Adds rudimentary [TypeScript](https://www.typescriptlang.org/) support to [AVA](https://avajs.dev).
44

5-
This is designed to work for projects that precompile their TypeScript code, including tests. It allows AVA to load the resulting JavaScript, while configuring AVA to use the TypeScript paths.
5+
This is designed to work for projects that precompile TypeScript. It allows AVA to load the compiled JavaScript, while configuring AVA to treat the TypeScript files as test files.
66

7-
In other words, say you have a test file at `src/test.ts`. You've configured TypeScript to output to `build/`. Using `@ava/typescript` you can run the `build/test.js` file using `npx ava src/test.ts`. AVA won't pick up any of the JavaScript files present in the `build/` directory, unless they have a TypeScript counterpart in `src/`.
7+
In other words, say you have a test file at `src/test.ts`. You've configured TypeScript to output to `build/`. Using `@ava/typescript` you can run the test using `npx ava src/test.ts`.
88

99
## Enabling TypeScript support
1010

@@ -24,13 +24,15 @@ Then, enable TypeScript support either in `package.json` or `ava.config.*`:
2424
"typescript": {
2525
"rewritePaths": {
2626
"src/": "build/"
27-
}
27+
},
28+
"compile": true
2829
}
2930
}
3031
}
3132
```
3233

33-
Both keys and values of the `rewritePaths` object must end with a `/`. Paths are relative to your project directory.
34+
Both keys and values of the `rewritePaths` object must end with a `/`. Paths are relative to your project directory.\
35+
You can enable compilation via the `compile` property. It is recommended to set it to `false` when running `ts` in a watcher mode.
3436

3537
Output files are expected to have the `.js` extension.
3638

index.js

+18-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
const path = require('path');
33

44
const escapeStringRegexp = require('escape-string-regexp');
5+
const execa = require('execa');
56

67
const pkg = require('./package.json');
78

@@ -26,6 +27,14 @@ function isValidRewritePaths(rewritePaths) {
2627
});
2728
}
2829

30+
function isValidCompile(compile) {
31+
return typeof compile === 'boolean';
32+
}
33+
34+
async function compileTypeScript(projectDir) {
35+
return execa('tsc', ['--incremental'], {preferLocal: true, cwd: projectDir});
36+
}
37+
2938
module.exports = ({negotiateProtocol}) => {
3039
const protocol = negotiateProtocol(['ava-3.2', 'ava-3'], {version: pkg.version});
3140
if (protocol === null) {
@@ -37,10 +46,11 @@ module.exports = ({negotiateProtocol}) => {
3746
let valid = false;
3847
if (isPlainObject(config)) {
3948
const keys = Object.keys(config);
40-
if (keys.every(key => key === 'extensions' || key === 'rewritePaths')) {
49+
if (keys.every(key => key === 'extensions' || key === 'rewritePaths' || key === 'compile')) {
4150
valid =
4251
(config.extensions === undefined || isValidExtensions(config.extensions)) &&
43-
isValidRewritePaths(config.rewritePaths);
52+
isValidRewritePaths(config.rewritePaths) &&
53+
isValidCompile(config.compile);
4454
}
4555
}
4656

@@ -50,7 +60,8 @@ module.exports = ({negotiateProtocol}) => {
5060

5161
const {
5262
extensions = ['ts'],
53-
rewritePaths: relativeRewritePaths
63+
rewritePaths: relativeRewritePaths,
64+
compile
5465
} = config;
5566

5667
const rewritePaths = Object.entries(relativeRewritePaths).map(([from, to]) => [
@@ -61,6 +72,10 @@ module.exports = ({negotiateProtocol}) => {
6172

6273
return {
6374
async compile() {
75+
if (compile) {
76+
await compileTypeScript(protocol.projectDir);
77+
}
78+
6479
return {
6580
extensions: extensions.slice(),
6681
rewritePaths: rewritePaths.slice()

package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
"escape-string-regexp": "^2.0.0"
2323
},
2424
"devDependencies": {
25-
"ava": "^3.0.0",
25+
"ava": "^3.15.0",
26+
"del": "^6.0.0",
2627
"execa": "^4.0.0",
27-
"nyc": "^15.0.0",
28-
"xo": "^0.25.3"
28+
"nyc": "^15.1.0",
29+
"xo": "^0.37.1"
2930
},
3031
"nyc": {
3132
"reporter": [

test/_with-provider.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const path = require('path');
2+
const pkg = require('../package.json');
3+
const makeProvider = require('..');
4+
5+
const withProvider = (t, run, identifier = 'ava-3.2') => run(t, makeProvider({
6+
negotiateProtocol(identifiers, {version}) {
7+
t.true(identifiers.includes(identifier));
8+
t.is(version, pkg.version);
9+
return {
10+
ava: {version: '3.2.0'},
11+
identifier,
12+
normalizeGlobPatterns: patterns => patterns,
13+
async findFiles({patterns}) {
14+
return patterns.map(file => path.join(__dirname, file));
15+
},
16+
projectDir: __dirname
17+
};
18+
}
19+
}));
20+
21+
module.exports = withProvider;

test/compilation.js

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const path = require('path');
2+
const test = require('ava');
3+
const del = require('del');
4+
const execa = require('execa');
5+
const withProvider = require('./_with-provider');
6+
7+
test.before('deleting compiled files', async t => {
8+
t.log(await del('test/fixtures/compiled'));
9+
});
10+
11+
const compile = async provider => {
12+
return {
13+
state: await provider.main({
14+
config: {
15+
rewritePaths: {
16+
'typescript/': 'fixtures/',
17+
'compiled/': 'fixtures/compiled/'
18+
},
19+
compile: true
20+
}
21+
}).compile()
22+
};
23+
};
24+
25+
test('worker(): load rewritten paths files', withProvider, async (t, provider) => {
26+
const {state} = await compile(provider);
27+
const {stdout, stderr} = await execa.node(
28+
path.join(__dirname, 'fixtures/install-and-load'),
29+
['ava-3', JSON.stringify(state), path.join(__dirname, 'typescript', 'file.ts')],
30+
{cwd: path.join(__dirname, 'fixtures')}
31+
);
32+
if (stderr.length > 0) {
33+
t.log(stderr);
34+
}
35+
36+
t.snapshot(stdout);
37+
});
38+
39+
test('worker(): runs compiled files', withProvider, async (t, provider) => {
40+
const {state} = await compile(provider);
41+
const {stdout, stderr} = await execa.node(
42+
path.join(__dirname, 'fixtures/install-and-load'),
43+
['ava-3', JSON.stringify(state), path.join(__dirname, 'compiled', 'typescript.ts')],
44+
{cwd: path.join(__dirname, 'fixtures')}
45+
);
46+
if (stderr.length > 0) {
47+
t.log(stderr);
48+
}
49+
50+
t.snapshot(stdout);
51+
});

test/fixtures/typescript.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('logged in typescript.ts');

test/protocol-ava-3.2.js

+4-21
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,24 @@
11
const path = require('path');
22
const test = require('ava');
3-
const pkg = require('../package.json');
4-
const makeProvider = require('..');
5-
6-
const withProvider = (t, run) => run(t, makeProvider({
7-
negotiateProtocol(identifiers, {version}) {
8-
t.true(identifiers.includes('ava-3.2'));
9-
t.is(version, pkg.version);
10-
return {
11-
ava: {version: '3.2.0'},
12-
identifier: 'ava-3.2',
13-
normalizeGlobPatterns: patterns => patterns,
14-
async findFiles({patterns}) {
15-
return patterns.map(file => path.join(__dirname, file));
16-
},
17-
projectDir: __dirname
18-
};
19-
}
20-
}));
3+
const withProvider = require('./_with-provider');
214

225
test('negotiates ava-3.2 protocol', withProvider, t => t.plan(2));
236

247
test('main() ignoreChange()', withProvider, (t, provider) => {
25-
const main = provider.main({config: {rewritePaths: {'src/': 'build/'}}});
8+
const main = provider.main({config: {rewritePaths: {'src/': 'build/'}, compile: false}});
269
t.true(main.ignoreChange(path.join(__dirname, 'src/foo.ts')));
2710
t.false(main.ignoreChange(path.join(__dirname, 'build/foo.js')));
2811
});
2912

3013
test('main() resolveTestfile()', withProvider, (t, provider) => {
31-
const main = provider.main({config: {rewritePaths: {'src/': 'build/'}}});
14+
const main = provider.main({config: {rewritePaths: {'src/': 'build/'}, compile: false}});
3215
t.is(main.resolveTestFile(path.join(__dirname, 'src/foo.ts')), path.join(__dirname, 'build/foo.js'));
3316
t.is(main.resolveTestFile(path.join(__dirname, 'build/foo.js')), path.join(__dirname, 'build/foo.js'));
3417
t.is(main.resolveTestFile(path.join(__dirname, 'foo/bar.ts')), path.join(__dirname, 'foo/bar.ts'));
3518
});
3619

3720
test('main() updateGlobs()', withProvider, (t, provider) => {
38-
const main = provider.main({config: {rewritePaths: {'src/': 'build/'}}});
21+
const main = provider.main({config: {rewritePaths: {'src/': 'build/'}, compile: false}});
3922
t.snapshot(main.updateGlobs({
4023
filePatterns: ['src/test.ts'],
4124
ignoredByWatcherPatterns: ['assets/**']

test/protocol-ava-3.js

+13-52
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,14 @@
1-
const path = require('path');
21
const test = require('ava');
3-
const execa = require('execa');
42
const pkg = require('../package.json');
5-
const makeProvider = require('..');
6-
7-
const withProvider = (t, run) => run(t, makeProvider({
8-
negotiateProtocol(identifiers, {version}) {
9-
t.true(identifiers.includes('ava-3'));
10-
t.is(version, pkg.version);
11-
return {
12-
ava: {version: '3.0.0'},
13-
identifier: 'ava-3',
14-
normalizeGlobPatterns: patterns => patterns,
15-
async findFiles({patterns}) {
16-
return patterns.map(file => path.join(__dirname, file));
17-
},
18-
projectDir: __dirname
19-
};
20-
}
21-
}));
3+
const withProvider = require('./_with-provider');
224

235
const validateConfig = (t, provider, config) => {
246
const error = t.throws(() => provider.main({config}));
257
error.message = error.message.replace(`v${pkg.version}`, 'v${pkg.version}'); // eslint-disable-line no-template-curly-in-string
268
t.snapshot(error);
279
};
2810

29-
test('negotiates ava-3 protocol', withProvider, t => t.plan(2));
11+
test('negotiates ava-3 protocol', withProvider, t => t.plan(2), 'ava-3');
3012

3113
test('main() config validation: throw when config is not a plain object', withProvider, (t, provider) => {
3214
validateConfig(t, provider, false);
@@ -35,7 +17,7 @@ test('main() config validation: throw when config is not a plain object', withPr
3517
validateConfig(t, provider, []);
3618
});
3719

38-
test('main() config validation: throw when config contains keys other than \'extensions\' or \'rewritePaths\'', withProvider, (t, provider) => {
20+
test('main() config validation: throw when config contains keys other than \'extensions\', \'rewritePaths\' or \'compile\'', withProvider, (t, provider) => {
3921
validateConfig(t, provider, {foo: 1});
4022
});
4123

@@ -55,47 +37,26 @@ test('main() config validation: config may not be an empty object', withProvider
5537
validateConfig(t, provider, {});
5638
});
5739

40+
test('main() config validation: throw when config.compile is not a boolean', withProvider, (t, provider) => {
41+
validateConfig(t, provider, {rewritePaths: {'src/': 'build/'}, compile: 1});
42+
validateConfig(t, provider, {rewritePaths: {'src/': 'build/'}, compile: undefined});
43+
});
44+
5845
test('main() config validation: rewrite paths must end in a /', withProvider, (t, provider) => {
59-
validateConfig(t, provider, {rewritePaths: {src: 'build/'}});
60-
validateConfig(t, provider, {rewritePaths: {'src/': 'build'}});
46+
validateConfig(t, provider, {rewritePaths: {src: 'build/', compile: false}});
47+
validateConfig(t, provider, {rewritePaths: {'src/': 'build', compile: false}});
6148
});
6249

6350
test('main() extensions: defaults to [\'ts\']', withProvider, (t, provider) => {
64-
t.deepEqual(provider.main({config: {rewritePaths: {'src/': 'build/'}}}).extensions, ['ts']);
51+
t.deepEqual(provider.main({config: {rewritePaths: {'src/': 'build/'}, compile: false}}).extensions, ['ts']);
6552
});
6653

6754
test('main() extensions: returns configured extensions', withProvider, (t, provider) => {
6855
const extensions = ['tsx'];
69-
t.deepEqual(provider.main({config: {extensions, rewritePaths: {'src/': 'build/'}}}).extensions, extensions);
56+
t.deepEqual(provider.main({config: {extensions, rewritePaths: {'src/': 'build/'}, compile: false}}).extensions, extensions);
7057
});
7158

7259
test('main() extensions: always returns new arrays', withProvider, (t, provider) => {
73-
const main = provider.main({config: {rewritePaths: {'src/': 'build/'}}});
60+
const main = provider.main({config: {rewritePaths: {'src/': 'build/'}, compile: false}});
7461
t.not(main.extensions, main.extensions);
7562
});
76-
77-
const compile = async provider => {
78-
return {
79-
state: await provider.main({
80-
config: {
81-
rewritePaths: {
82-
'typescript/': 'fixtures/'
83-
}
84-
}
85-
}).compile()
86-
};
87-
};
88-
89-
test('worker(): load rewritten paths files', withProvider, async (t, provider) => {
90-
const {state} = await compile(provider);
91-
const {stdout, stderr} = await execa.node(
92-
path.join(__dirname, 'fixtures/install-and-load'),
93-
['ava-3', JSON.stringify(state), path.join(__dirname, 'typescript', 'file.ts')],
94-
{cwd: path.join(__dirname, 'fixtures')}
95-
);
96-
if (stderr.length > 0) {
97-
t.log(stderr);
98-
}
99-
100-
t.snapshot(stdout);
101-
});

test/snapshots/compilation.js.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Snapshot report for `test/compilation.js`
2+
3+
The actual snapshot is saved in `compilation.js.snap`.
4+
5+
Generated by [AVA](https://avajs.dev).
6+
7+
## worker(): load rewritten paths files
8+
9+
> Snapshot 1
10+
11+
'logged in file.js'
12+
13+
## worker(): runs compiled files
14+
15+
> Snapshot 1
16+
17+
'logged in typescript.ts'

test/snapshots/compilation.js.snap

151 Bytes
Binary file not shown.

test/snapshots/protocol-ava-3.js.md

+22
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,25 @@ Generated by [AVA](https://avajs.dev).
8989
> Snapshot 1
9090
9191
'logged in file.js'
92+
93+
## main() config validation: throw when config contains keys other than 'extensions', 'rewritePaths' or 'compile'
94+
95+
> Snapshot 1
96+
97+
Error {
98+
message: 'Unexpected Typescript configuration for AVA. See https://github.com/avajs/typescript/blob/v${pkg.version}/README.md for allowed values.',
99+
}
100+
101+
## main() config validation: throw when config.compile is not a boolean
102+
103+
> Snapshot 1
104+
105+
Error {
106+
message: 'Unexpected Typescript configuration for AVA. See https://github.com/avajs/typescript/blob/v${pkg.version}/README.md for allowed values.',
107+
}
108+
109+
> Snapshot 2
110+
111+
Error {
112+
message: 'Unexpected Typescript configuration for AVA. See https://github.com/avajs/typescript/blob/v${pkg.version}/README.md for allowed values.',
113+
}

test/snapshots/protocol-ava-3.js.snap

61 Bytes
Binary file not shown.

test/tsconfig.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"outDir": "fixtures/compiled"
4+
},
5+
"include": [
6+
"fixtures"
7+
]
8+
}

0 commit comments

Comments
 (0)