Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: avajs/ava
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v3.0.0
Choose a base ref
...
head repository: avajs/ava
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v3.1.0
Choose a head ref
  • 3 commits
  • 12 files changed
  • 2 contributors

Commits on Jan 21, 2020

  1. Remove v2 configuration from TypeScript recipe

    Fixes #2376
    jhechtf authored and novemberborn committed Jan 21, 2020

    Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    91a0086 View commit details

Commits on Jan 26, 2020

  1. Rudimentary support for loading TypeScript test files

    * Generalize providers rather than supporting just the Babel one
    
    * Add rudimentary TypeScript support
    novemberborn authored Jan 26, 2020

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    e4fef0c View commit details
  2. 3.1.0

    novemberborn committed Jan 26, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    novemberborn Mark Wubben
    Copy the full SHA
    56338dc View commit details
Showing with 160 additions and 116 deletions.
  1. +2 −0 docs/06-configuration.md
  2. +71 −76 docs/recipes/typescript.md
  3. +17 −6 eslint-plugin-helper.js
  4. +6 −3 lib/api.js
  5. +21 −7 lib/cli.js
  6. +4 −4 lib/extensions.js
  7. +7 −4 lib/{babel-manager.js → provider-manager.js}
  8. +19 −9 lib/worker/subprocess.js
  9. +1 −1 package-lock.json
  10. +1 −1 package.json
  11. +5 −2 test/api.js
  12. +6 −3 test/helper/report.js
2 changes: 2 additions & 0 deletions docs/06-configuration.md
Original file line number Diff line number Diff line change
@@ -61,6 +61,8 @@ Note that providing files on the CLI overrides the `files` option.

Provide the `babel` option (and install [`@ava/babel`](https://github.com/avajs/babel) as an additional dependency) to enable Babel compilation.

Provide the `typescript` option (and install [`@ava/typescript`](https://github.com/avajs/typescript) as an additional dependency) to enable (rudimentary) TypeScript support.

## Using `ava.config.*` files

Rather than specifying the configuration in the `package.json` file you can use `ava.config.js` or `ava.config.cjs` files.
147 changes: 71 additions & 76 deletions docs/recipes/typescript.md
Original file line number Diff line number Diff line change
@@ -4,86 +4,15 @@ Translations: [Español](https://github.com/avajs/ava-docs/blob/master/es_ES/doc

AVA comes bundled with a TypeScript definition file. This allows developers to leverage TypeScript for writing tests.

This guide assumes you've already set up TypeScript for your project. Note that AVA's definition has been tested with version 3.7.5.

## Configuring AVA to compile TypeScript files on the fly

You can configure AVA to recognize TypeScript files. Then, with `ts-node` installed, you can compile them on the fly.

`package.json`:
Out of the box AVA does not load TypeScript test files, however. Rudimentary support is available via the [`@ava/typescript`] package. You can also use AVA with [`ts-node`]. Read on for details.

```json
{
"ava": {
"compileEnhancements": false,
"extensions": [
"ts"
],
"require": [
"ts-node/register"
]
}
}
```

It's worth noting that with this configuration tests will fail if there are TypeScript build errors. If you want to test while ignoring these errors you can use `ts-node/register/transpile-only` instead of `ts-node/register`.

### Using module path mapping

`ts-node` [does not support module path mapping](https://github.com/TypeStrong/ts-node/issues/138), however you can use [`tsconfig-paths`](https://github.com/dividab/tsconfig-paths#readme).

Once installed, add the `tsconfig-paths/register` entry to the `require` section of AVA's config:

`package.json`:

```json
{
"ava": {
"compileEnhancements": false,
"extensions": [
"ts"
],
"require": [
"ts-node/register",
"tsconfig-paths/register"
]
}
}
```

Then you can start using module aliases:

`tsconfig.json`:
```json
{
"baseUrl": ".",
"paths": {
"@helpers/*": ["helpers/*"]
}
}
```

Test:

```ts
import myHelper from '@helpers/myHelper';

// Rest of the file
```

## Compiling TypeScript files before running AVA
This guide assumes you've already set up TypeScript for your project. Note that AVA's definition has been tested with version 3.7.5.

Add a `test` script in the `package.json` file. It will compile the project first and then run AVA.
## Enabling AVA's TypeScript support

```json
{
"scripts": {
"test": "tsc && ava"
}
}
```
Currently, AVA's TypeScript support is designed to work for projects that precompile TypeScript. Please see [`@ava/typescript`] for setup instructions.

Make sure that AVA runs your built TypeScript files.
Read on until the end to learn how to use [`ts-node`] with AVA.

## Writing tests

@@ -223,3 +152,69 @@ test('throwsAsync', async t => {
```

Note that, despite the typing, the assertion returns `undefined` if it fails. Typing the assertions as returning `Error | undefined` didn't seem like the pragmatic choice.

## On the fly compilation using `ts-node`

If [`@ava/typescript`] doesn't do the trick you can use [`ts-node`]. Make sure it's installed and then configure AVA to recognize TypeScript files and register [`ts-node`]:

`package.json`:

```json
{
"ava": {
"extensions": [
"ts"
],
"require": [
"ts-node/register"
]
}
}
```

It's worth noting that with this configuration tests will fail if there are TypeScript build errors. If you want to test while ignoring these errors you can use `ts-node/register/transpile-only` instead of `ts-node/register`.

### Using module path mapping

`ts-node` [does not support module path mapping](https://github.com/TypeStrong/ts-node/issues/138), however you can use [`tsconfig-paths`](https://github.com/dividab/tsconfig-paths#readme).

Once installed, add the `tsconfig-paths/register` entry to the `require` section of AVA's config:

`package.json`:

```json
{
"ava": {
"extensions": [
"ts"
],
"require": [
"ts-node/register",
"tsconfig-paths/register"
]
}
}
```

Then you can start using module aliases:

`tsconfig.json`:
```json
{
"baseUrl": ".",
"paths": {
"@helpers/*": ["helpers/*"]
}
}
```

Test:

```ts
import myHelper from '@helpers/myHelper';

// Rest of the file
```

[`@ava/typescript`]: https://github.com/avajs/typescript
[`ts-node`]: https://www.npmjs.com/package/ts-node
23 changes: 17 additions & 6 deletions eslint-plugin-helper.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict';
const babelManager = require('./lib/babel-manager');
const normalizeExtensions = require('./lib/extensions');
const {classify, hasExtension, isHelperish, matches, normalizeFileForMatching, normalizeGlobs, normalizePatterns} = require('./lib/globs');
const loadConfig = require('./lib/load-config');
const providerManager = require('./lib/provider-manager');

const configCache = new Map();
const helperCache = new Map();
@@ -14,22 +14,33 @@ function load(projectDir, overrides) {
}

let conf;
let babelProvider;
let providers;
if (configCache.has(projectDir)) {
({conf, babelProvider} = configCache.get(projectDir));
({conf, providers} = configCache.get(projectDir));
} else {
conf = loadConfig({resolveFrom: projectDir});

providers = [];
if (Reflect.has(conf, 'babel')) {
babelProvider = babelManager({projectDir}).main({config: conf.babel});
providers.push({
type: 'babel',
main: providerManager.babel(projectDir).main({config: conf.babel})
});
}

configCache.set(projectDir, {conf, babelProvider});
if (Reflect.has(conf, 'typescript')) {
providers.push({
type: 'typescript',
main: providerManager.typescript(projectDir).main({config: conf.typescript})
});
}

configCache.set(projectDir, {conf, providers});
}

const extensions = overrides && overrides.extensions ?
normalizeExtensions(overrides.extensions) :
normalizeExtensions(conf.extensions, babelProvider);
normalizeExtensions(conf.extensions, providers);

let helperPatterns = [];
if (overrides && overrides.helpers !== undefined) {
9 changes: 6 additions & 3 deletions lib/api.js
Original file line number Diff line number Diff line change
@@ -185,8 +185,11 @@ class Api extends Emittery {
}
});

const {babelProvider} = this.options;
const babelState = babelProvider === undefined ? null : await babelProvider.compile({cacheDir, files: testFiles});
const {providers = []} = this.options;
const providerStates = (await Promise.all(providers.map(async ({type, main}) => {
const state = await main.compile({cacheDir, files: testFiles});
return state === null ? null : {type, state};
}))).filter(state => state !== null);

// Resolve the correct concurrency value.
let concurrency = Math.min(os.cpus().length, isCi ? 2 : Infinity);
@@ -208,7 +211,7 @@ class Api extends Emittery {

const options = {
...apiOptions,
babelState,
providerStates,
recordNewSnapshots: !isCi,
// If we're looking for matches, run every single test process in exclusive-only mode
runOnlyExclusive: apiOptions.match.length > 0 || runtimeOptions.runOnlyExclusive === true
28 changes: 21 additions & 7 deletions lib/cli.js
Original file line number Diff line number Diff line change
@@ -256,11 +256,11 @@ exports.run = async () => { // eslint-disable-line complexity
const MiniReporter = require('./reporters/mini');
const TapReporter = require('./reporters/tap');
const Watcher = require('./watcher');
const babelManager = require('./babel-manager');
const normalizeExtensions = require('./extensions');
const {normalizeGlobs, normalizePatterns} = require('./globs');
const normalizeNodeArguments = require('./node-arguments');
const validateEnvironmentVariables = require('./environment-variables');
const providerManager = require('./provider-manager');

let pkg;
try {
@@ -279,10 +279,24 @@ exports.run = async () => { // eslint-disable-line complexity
js: defaultModuleType
};

let babelProvider;
const providers = [];
if (Reflect.has(conf, 'babel')) {
try {
babelProvider = babelManager({projectDir}).main({config: conf.babel});
providers.push({
type: 'babel',
main: providerManager.babel(projectDir).main({config: conf.babel})
});
} catch (error) {
exit(error.message);
}
}

if (Reflect.has(conf, 'typescript')) {
try {
providers.push({
type: 'typescript',
main: providerManager.typescript(projectDir).main({config: conf.typescript})
});
} catch (error) {
exit(error.message);
}
@@ -297,7 +311,7 @@ exports.run = async () => { // eslint-disable-line complexity

let extensions;
try {
extensions = normalizeExtensions(conf.extensions, babelProvider);
extensions = normalizeExtensions(conf.extensions, providers);
} catch (error) {
exit(error.message);
}
@@ -328,22 +342,22 @@ exports.run = async () => { // eslint-disable-line complexity
const filter = normalizePatterns(input.map(fileOrPattern => path.relative(projectDir, path.resolve(process.cwd(), fileOrPattern))));

const api = new Api({
babelProvider,
cacheEnabled: combined.cache !== false,
chalkOptions,
concurrency: combined.concurrency || 0,
debug,
environmentVariables,
experiments,
extensions,
failFast: combined.failFast,
failWithoutAssertions: combined.failWithoutAssertions !== false,
globs,
moduleTypes,
environmentVariables,
match,
moduleTypes,
nodeArguments,
parallelRuns,
projectDir,
providers,
ranFromCli: true,
require: arrify(combined.require),
serial: combined.serial,
8 changes: 4 additions & 4 deletions lib/extensions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = (configuredExtensions, babelProvider) => {
module.exports = (configuredExtensions, providers = []) => {
// Combine all extensions possible for testing. Remove duplicate extensions.
const duplicates = new Set();
const seen = new Set();
@@ -16,15 +16,15 @@ module.exports = (configuredExtensions, babelProvider) => {
combine(configuredExtensions);
}

if (babelProvider !== undefined) {
combine(babelProvider.extensions);
for (const {main} of providers) {
combine(main.extensions);
}

if (duplicates.size > 0) {
throw new Error(`Unexpected duplicate extensions in options: '${[...duplicates].join('\', \'')}'.`);
}

// Unless the default was used by `babelProvider`, as long as the extensions aren't explicitly set, set the default.
// Unless the default was used by providers, as long as the extensions aren't explicitly set, set the default.
if (configuredExtensions === undefined) {
if (!seen.has('cjs')) {
seen.add('cjs');
11 changes: 7 additions & 4 deletions lib/babel-manager.js → lib/provider-manager.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
const pkg = require('../package.json');
const globs = require('./globs');

module.exports = ({projectDir}) => {
function load(providerModule, projectDir) {
const ava = {version: pkg.version};
const makeProvider = require('@ava/babel');
const makeProvider = require(providerModule);

let fatal;
const provider = makeProvider({
negotiateProtocol(identifiers, {version}) {
if (!identifiers.includes('ava-3')) {
fatal = new Error(`This version of AVA (${ava.version}) is not compatible with@ava/babel@${version}`);
fatal = new Error(`This version of AVA (${ava.version}) is not compatible with ${providerModule}@${version}`);
return null;
}

@@ -30,4 +30,7 @@ module.exports = ({projectDir}) => {
}

return provider;
};
}

exports.babel = projectDir => load('@ava/babel', projectDir);
exports.typescript = projectDir => load('@ava/typescript', projectDir);
Loading