Skip to content

Add built-in debug command 🎉 #2316

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/05-command-line.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
Translations: [Français](https://github.com/avajs/ava-docs/blob/master/fr_FR/docs/05-command-line.md)

```console
$ npx ava --help
ava <files>
ava debug <file>
ava reset-cache

Commands:
ava Run tests [default]
ava debug Activate Node.js inspector and run the test file
ava reset-cache Reset AVA's compilation cache and exit

Positionals:
Expand Down
26 changes: 23 additions & 3 deletions docs/recipes/debugging-with-chrome-devtools.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,32 @@

Translations: [Français](https://github.com/avajs/ava-docs/blob/master/fr_FR/docs/recipes/debugging-with-chrome-devtools.md)

Use [inspect-process](https://github.com/jaridmargolin/inspect-process) to easily launch a debugging session with Chrome DevTools.
**This recipe describes the new `inspect` command in the upcoming AVA 3 release. See the [AVA 2](https://github.com/avajs/ava/blob/v2.4.0/docs/recipes/debugging-with-chrome-devtools.md) documentation instead.**

You can debug your tests using [Chrome DevTools](https://developers.google.com/web/tools/chrome-devtools).

Open Chrome, then navigate to <chrome://inspect/>. Click the *Open dedicated DevTools for Node* link within the *Devices* section.

In the *DevTools for Node* window, navigate to *Sources* and in the left-hand column select *Filesystem*. Add your project directory to the workspace. Make sure to grant permission.

Now run a specific test file:

```console
$ npm install --global inspect-process
npx ava debug test.js
```

The DevTools should connect automatically and your tests will run. Use DevTools to set breakpoints, or use the `debugger` keyword.

Run with the `--break` option to ensure the DevTools hit a breakpoint right before the test file is loaded:

```console
$ inspect node_modules/ava/profile.js some/test/file.js
npx ava debug --break test.js
```

You can also customize the port. It defaults to `9229`:

```console
npx ava debug --port 9230 test.js
```

You'll have to add a connection for this port in the *Connection* tab. AVA only binds to `localhost`.
97 changes: 52 additions & 45 deletions docs/recipes/debugging-with-vscode.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,65 @@

Translations: [Français](https://github.com/avajs/ava-docs/blob/master/fr_FR/docs/recipes/debugging-with-vscode.md)

## Setup

In the sidebar click the `Debug` handle.

Add a new configuration in the dropdown menu next to the green `Debug` button: `Add configuration`. This will open `launch.json` with all debug configurations.

Add following to the `configurations` object:

```json
{
"type": "node",
"request": "launch",
"name": "Run AVA test",
"program": "${workspaceFolder}/node_modules/ava/profile.js",
"args": [
"${file}"
],
"skipFiles": [
"<node_internals>/**/*.js"
]
}
```

Save this configuration after you added it.

## Debug

> **Note:** The file you want to debug, must be open and active

> **Note:** The breakpoints in VSCode are a bit buggy sometimes (especially with async code). `debugger;` always works fine.

Set breakpoints in the code **or** write `debugger;` at the point where it should stop.

Hit the green `Debug` button next to the list of configurations on the top left in the `Debug` view. Once the breakpoint is hit, you can evaluate variables and step through the code.
**This recipe describes the new `inspect` command in the upcoming AVA 3 release. See the [AVA 2](https://github.com/avajs/ava/blob/v2.4.0/docs/recipes/debugging-with-vscode.md) documentation instead.**

You can debug your tests using [Visual Studio Code](https://code.visualstudio.com/).

## Creating a launch configuration

1. Open a workspace for your project.
1. In the sidebar click the *Debug* handle.
1. Create a `launch.json` file.
1. Select the Node.js environment.
1. Add following to the `configurations` object:

```json
{
"type": "node",
"request": "launch",
"name": "Debug AVA test file",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/ava",
"runtimeArgs": [
"debug",
"--break",
"${file}"
],
"port": 9229,
"outputCapture": "std",
"skipFiles": [
"<node_internals>/**/*.js"
]
}
```
1. Save your changes to the `launch.json` file.

## Using the debugger

Open the file(s) you want to debug. You can set breakpoints or use the `debugger` keyword.

Now, *with a test file open*, from the *Debug* menu run the *Debug AVA test file* configuration.

## Serial debugging

By default AVA runs tests concurrently. This may complicate debugging. Add a configuration with the `--serial` argument so AVA runs only one test at a time:

```json
{
"type": "node",
"request": "launch",
"name": "Run AVA test serially",
"program": "${workspaceFolder}/node_modules/ava/profile.js",
"args": [
"${file}",
"--serial"
],
"skipFiles": [
"<node_internals>/**/*.js"
]
"type": "node",
"request": "launch",
"name": "Debug AVA test file",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/ava",
"runtimeArgs": [
"debug",
"--break",
"--serial",
"${file}"
],
"port": 9229,
"outputCapture": "std",
"skipFiles": [
"<node_internals>/**/*.js"
]
}
```

Expand Down
4 changes: 4 additions & 0 deletions docs/recipes/debugging-with-webstorm.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

Translations: [Français](https://github.com/avajs/ava-docs/blob/master/fr_FR/docs/recipes/debugging-with-webstorm.md)

**This recipe is outdated.**

---

Starting with version 2016.2, [WebStorm](https://www.jetbrains.com/webstorm/) and other JetBrains IDEs (IntelliJ IDEA Ultimate, PHPStorm, PyCharm Professional, and RubyMine with installed Node.js plugin) allow you to debug AVA tests.


Expand Down
29 changes: 1 addition & 28 deletions lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const isCi = require('is-ci');
const resolveCwd = require('resolve-cwd');
const debounce = require('lodash/debounce');
const Bluebird = require('bluebird');
const getPort = require('get-port');
const arrify = require('arrify');
const makeDir = require('make-dir');
const ms = require('ms');
Expand Down Expand Up @@ -269,7 +268,6 @@ class Api extends Emittery {
return;
}

const execArgv = await this._computeForkExecArgv();
const options = {
...apiOptions,
babelState,
Expand All @@ -283,7 +281,7 @@ class Api extends Emittery {
options.updateSnapshots = true;
}

const worker = fork(file, options, execArgv);
const worker = fork(file, options, process.execArgv);
runStatus.observeWorker(worker, file);

pendingWorkers.add(worker);
Expand Down Expand Up @@ -318,31 +316,6 @@ class Api extends Emittery {

return cacheDir;
}

async _computeForkExecArgv() {
const execArgv = this.options.testOnlyExecArgv || process.execArgv;
if (execArgv.length === 0) {
return Promise.resolve(execArgv);
}

// --inspect-brk is used in addition to --inspect to break on first line and wait
const inspectArgIndex = execArgv.findIndex(arg => /^--inspect(?:-brk)?(?:$|=)/.test(arg));
if (inspectArgIndex === -1) {
return Promise.resolve(execArgv);
}

const port = await getPort();
const forkExecArgv = execArgv.slice();
let flagName = '--inspect';
const oldValue = forkExecArgv[inspectArgIndex];
if (oldValue.includes('brk')) {
flagName += '-brk';
}

forkExecArgv[inspectArgIndex] = `${flagName}=${port}`;

return forkExecArgv;
}
}

module.exports = Api;
62 changes: 55 additions & 7 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ exports.run = async () => { // eslint-disable-line complexity
confError = error;
}

let debug = null;
let resetCache = false;
const {argv} = yargs
.parserConfiguration({
Expand All @@ -105,6 +106,7 @@ exports.run = async () => { // eslint-disable-line complexity
'unknown-options-as-args': false
})
.usage('$0 <files>')
.usage('$0 debug <file>')
.usage('$0 reset-cache')
.options({
color: {
Expand All @@ -120,6 +122,31 @@ exports.run = async () => { // eslint-disable-line complexity
describe: 'Paths to individual test files. Leave empty if you want AVA to search for files instead.',
type: 'string'
}))
.command(
'debug',
'Activate Node.js inspector and run the test file',
yargs => yargs.options(FLAGS).options({
break: {
description: 'Break before the test file is loaded',
type: 'boolean'
},
port: {
default: 9229,
description: 'Port on which you can connect to the inspector',
type: 'number'
}
}).positional('file', {
demand: true,
describe: 'Path to an individual test file',
type: 'string'
}),
argv => {
debug = {
break: argv.break === true,
files: argv._.slice(1),
port: argv.port
};
})
.command(
'reset-cache',
'Reset AVA\'s compilation cache and exit',
Expand Down Expand Up @@ -160,12 +187,28 @@ exports.run = async () => { // eslint-disable-line complexity
return;
}

if (argv.watch && argv.tap && !conf.tap) {
exit('The TAP reporter is not available when using watch mode.');
if (argv.watch) {
if (argv.tap && !conf.tap) {
exit('The TAP reporter is not available when using watch mode.');
}

if (isCi) {
exit('Watch mode is not available in CI, as it prevents AVA from terminating.');
}

if (debug !== null) {
exit('Watch mode is not available when debugging.');
}
}

if (argv.watch && isCi) {
exit('Watch mode is not available in CI, as it prevents AVA from terminating.');
if (debug !== null) {
if (argv.tap && !conf.tap) {
exit('The TAP reporter is not available when debugging.');
}

if (isCi) {
exit('Debugging is not available in CI.');
}
}

const combined = {...conf};
Expand Down Expand Up @@ -243,7 +286,7 @@ exports.run = async () => { // eslint-disable-line complexity

const match = combined.match === '' ? [] : arrify(combined.match);

const input = argv._;
const input = debug ? debug.files : argv._;
const resolveTestsFrom = input.length === 0 ? projectDir : process.cwd();
const files = input.map(file => path.relative(resolveTestsFrom, path.resolve(process.cwd(), file)));

Expand All @@ -262,12 +305,17 @@ exports.run = async () => { // eslint-disable-line complexity
}
}

if (debug !== null && files.length !== 1) {
exit('Provide the path to the test file you wish to debug');
}

const api = new Api({
babelProvider,
cacheEnabled: combined.cache !== false,
color: combined.color,
compileEnhancements: combined.compileEnhancements !== false,
concurrency: combined.concurrency || 0,
debug,
experiments,
extensions,
failFast: combined.failFast,
Expand All @@ -288,12 +336,12 @@ exports.run = async () => { // eslint-disable-line complexity
});

let reporter;
if (combined.tap && !combined.watch) {
if (combined.tap && !combined.watch && debug === null) {
reporter = new TapReporter({
reportStream: process.stdout,
stdStream: process.stderr
});
} else if (combined.verbose || isCi || !process.stdout.isTTY) {
} else if (debug !== null || combined.verbose || isCi || !process.stdout.isTTY) {
reporter = new VerboseReporter({
reportStream: process.stdout,
stdStream: process.stderr,
Expand Down
7 changes: 7 additions & 0 deletions lib/worker/subprocess.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ ipc.options.then(options => {
// to make sure we also track dependencies with custom require hooks
dependencyTracking.install(testPath);

if (options.debug) {
require('inspector').open(options.debug.port, '127.0.0.1', true);
if (options.debug.break) {
debugger; // eslint-disable-line no-debugger
}
}

require(testPath);

if (accessedRunner) {
Expand Down
Loading