Skip to content

Commit b3d70b0

Browse files
committed
Add built-in debug command
Fixes #1505.
1 parent fef2ef6 commit b3d70b0

File tree

9 files changed

+171
-111
lines changed

9 files changed

+171
-111
lines changed

docs/05-command-line.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
Translations: [Français](https://github.com/avajs/ava-docs/blob/master/fr_FR/docs/05-command-line.md)
44

55
```console
6-
$ npx ava --help
76
ava <files>
7+
ava debug <file>
88
ava reset-cache
99

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

1415
Positionals:

docs/recipes/debugging-with-chrome-devtools.md

+23-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,32 @@
22

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

5-
Use [inspect-process](https://github.com/jaridmargolin/inspect-process) to easily launch a debugging session with Chrome DevTools.
5+
**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.**
6+
7+
You can debug your tests using [Chrome DevTools](https://developers.google.com/web/tools/chrome-devtools).
8+
9+
Open Chrome, then navigate to <chrome://inspect/>. Click the *Open dedicated DevTools for Node* link within the *Devices* section.
10+
11+
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.
12+
13+
Now run a specific test file:
614

715
```console
8-
$ npm install --global inspect-process
16+
npx ava debug test.js
917
```
1018

19+
The DevTools should connect automatically and your tests will run. Use DevTools to set breakpoints, or use the `debugger` keyword.
20+
21+
Run with the `--break` option to ensure the DevTools hit a breakpoint right before the test file is loaded:
22+
1123
```console
12-
$ inspect node_modules/ava/profile.js some/test/file.js
24+
npx ava debug --break test.js
1325
```
26+
27+
You can also customize the port. It defaults to `9229`:
28+
29+
```console
30+
npx ava debug --port 9230 test.js
31+
```
32+
33+
You'll have to add a connection for this port in the *Connection* tab. AVA only binds to `localhost`.

docs/recipes/debugging-with-vscode.md

+52-45
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,65 @@
22

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

5-
## Setup
6-
7-
In the sidebar click the `Debug` handle.
8-
9-
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.
10-
11-
Add following to the `configurations` object:
12-
13-
```json
14-
{
15-
"type": "node",
16-
"request": "launch",
17-
"name": "Run AVA test",
18-
"program": "${workspaceFolder}/node_modules/ava/profile.js",
19-
"args": [
20-
"${file}"
21-
],
22-
"skipFiles": [
23-
"<node_internals>/**/*.js"
24-
]
25-
}
26-
```
27-
28-
Save this configuration after you added it.
29-
30-
## Debug
31-
32-
> **Note:** The file you want to debug, must be open and active
33-
34-
> **Note:** The breakpoints in VSCode are a bit buggy sometimes (especially with async code). `debugger;` always works fine.
35-
36-
Set breakpoints in the code **or** write `debugger;` at the point where it should stop.
37-
38-
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.
5+
**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.**
6+
7+
You can debug your tests using [Visual Studio Code](https://code.visualstudio.com/).
8+
9+
## Creating a launch configuration
10+
11+
1. Open a workspace for your project.
12+
1. In the sidebar click the *Debug* handle.
13+
1. Create a `launch.json` file.
14+
1. Select the Node.js environment.
15+
1. Add following to the `configurations` object:
16+
17+
```json
18+
{
19+
"type": "node",
20+
"request": "launch",
21+
"name": "Debug AVA test file",
22+
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/ava",
23+
"runtimeArgs": [
24+
"debug",
25+
"--break",
26+
"${file}"
27+
],
28+
"port": 9229,
29+
"outputCapture": "std",
30+
"skipFiles": [
31+
"<node_internals>/**/*.js"
32+
]
33+
}
34+
```
35+
1. Save your changes to the `launch.json` file.
36+
37+
## Using the debugger
38+
39+
Open the file(s) you want to debug. You can set breakpoints or use the `debugger` keyword.
40+
41+
Now, *with a test file open*, from the *Debug* menu run the *Debug AVA test file* configuration.
3942

4043
## Serial debugging
4144

4245
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:
4346

4447
```json
4548
{
46-
"type": "node",
47-
"request": "launch",
48-
"name": "Run AVA test serially",
49-
"program": "${workspaceFolder}/node_modules/ava/profile.js",
50-
"args": [
51-
"${file}",
52-
"--serial"
53-
],
54-
"skipFiles": [
55-
"<node_internals>/**/*.js"
56-
]
49+
"type": "node",
50+
"request": "launch",
51+
"name": "Debug AVA test file",
52+
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/ava",
53+
"runtimeArgs": [
54+
"debug",
55+
"--break",
56+
"--serial",
57+
"${file}"
58+
],
59+
"port": 9229,
60+
"outputCapture": "std",
61+
"skipFiles": [
62+
"<node_internals>/**/*.js"
63+
]
5764
}
5865
```
5966

docs/recipes/debugging-with-webstorm.md

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

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

5+
**This recipe is outdated.**
6+
7+
---
8+
59
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.
610

711

lib/api.js

+1-28
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ const isCi = require('is-ci');
99
const resolveCwd = require('resolve-cwd');
1010
const debounce = require('lodash/debounce');
1111
const Bluebird = require('bluebird');
12-
const getPort = require('get-port');
1312
const arrify = require('arrify');
1413
const makeDir = require('make-dir');
1514
const ms = require('ms');
@@ -269,7 +268,6 @@ class Api extends Emittery {
269268
return;
270269
}
271270

272-
const execArgv = await this._computeForkExecArgv();
273271
const options = {
274272
...apiOptions,
275273
babelState,
@@ -283,7 +281,7 @@ class Api extends Emittery {
283281
options.updateSnapshots = true;
284282
}
285283

286-
const worker = fork(file, options, execArgv);
284+
const worker = fork(file, options, process.execArgv);
287285
runStatus.observeWorker(worker, file);
288286

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

319317
return cacheDir;
320318
}
321-
322-
async _computeForkExecArgv() {
323-
const execArgv = this.options.testOnlyExecArgv || process.execArgv;
324-
if (execArgv.length === 0) {
325-
return Promise.resolve(execArgv);
326-
}
327-
328-
// --inspect-brk is used in addition to --inspect to break on first line and wait
329-
const inspectArgIndex = execArgv.findIndex(arg => /^--inspect(?:-brk)?(?:$|=)/.test(arg));
330-
if (inspectArgIndex === -1) {
331-
return Promise.resolve(execArgv);
332-
}
333-
334-
const port = await getPort();
335-
const forkExecArgv = execArgv.slice();
336-
let flagName = '--inspect';
337-
const oldValue = forkExecArgv[inspectArgIndex];
338-
if (oldValue.includes('brk')) {
339-
flagName += '-brk';
340-
}
341-
342-
forkExecArgv[inspectArgIndex] = `${flagName}=${port}`;
343-
344-
return forkExecArgv;
345-
}
346319
}
347320

348321
module.exports = Api;

lib/cli.js

+55-7
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ exports.run = async () => { // eslint-disable-line complexity
8787
confError = error;
8888
}
8989

90+
let debug = null;
9091
let resetCache = false;
9192
const {argv} = yargs
9293
.parserConfiguration({
@@ -105,6 +106,7 @@ exports.run = async () => { // eslint-disable-line complexity
105106
'unknown-options-as-args': false
106107
})
107108
.usage('$0 <files>')
109+
.usage('$0 debug <file>')
108110
.usage('$0 reset-cache')
109111
.options({
110112
color: {
@@ -120,6 +122,31 @@ exports.run = async () => { // eslint-disable-line complexity
120122
describe: 'Paths to individual test files. Leave empty if you want AVA to search for files instead.',
121123
type: 'string'
122124
}))
125+
.command(
126+
'debug',
127+
'Activate Node.js inspector and run the test file',
128+
yargs => yargs.options(FLAGS).options({
129+
break: {
130+
description: 'Break before the test file is loaded',
131+
type: 'boolean'
132+
},
133+
port: {
134+
default: 9229,
135+
description: 'Port on which you can connect to the inspector',
136+
type: 'number'
137+
}
138+
}).positional('file', {
139+
demand: true,
140+
describe: 'Path to an individual test file',
141+
type: 'string'
142+
}),
143+
argv => {
144+
debug = {
145+
break: argv.break === true,
146+
files: argv._.slice(1),
147+
port: argv.port
148+
};
149+
})
123150
.command(
124151
'reset-cache',
125152
'Reset AVA\'s compilation cache and exit',
@@ -160,12 +187,28 @@ exports.run = async () => { // eslint-disable-line complexity
160187
return;
161188
}
162189

163-
if (argv.watch && argv.tap && !conf.tap) {
164-
exit('The TAP reporter is not available when using watch mode.');
190+
if (argv.watch) {
191+
if (argv.tap && !conf.tap) {
192+
exit('The TAP reporter is not available when using watch mode.');
193+
}
194+
195+
if (isCi) {
196+
exit('Watch mode is not available in CI, as it prevents AVA from terminating.');
197+
}
198+
199+
if (debug !== null) {
200+
exit('Watch mode is not available when debugging.');
201+
}
165202
}
166203

167-
if (argv.watch && isCi) {
168-
exit('Watch mode is not available in CI, as it prevents AVA from terminating.');
204+
if (debug !== null) {
205+
if (argv.tap && !conf.tap) {
206+
exit('The TAP reporter is not available when debugging.');
207+
}
208+
209+
if (isCi) {
210+
exit('Debugging is not available in CI.');
211+
}
169212
}
170213

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

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

246-
const input = argv._;
289+
const input = debug ? debug.files : argv._;
247290
const resolveTestsFrom = input.length === 0 ? projectDir : process.cwd();
248291
const files = input.map(file => path.relative(resolveTestsFrom, path.resolve(process.cwd(), file)));
249292

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

308+
if (debug !== null && files.length !== 1) {
309+
exit('Provide the path to the test file you wish to debug');
310+
}
311+
265312
const api = new Api({
266313
babelProvider,
267314
cacheEnabled: combined.cache !== false,
268315
color: combined.color,
269316
compileEnhancements: combined.compileEnhancements !== false,
270317
concurrency: combined.concurrency || 0,
318+
debug,
271319
experiments,
272320
extensions,
273321
failFast: combined.failFast,
@@ -288,12 +336,12 @@ exports.run = async () => { // eslint-disable-line complexity
288336
});
289337

290338
let reporter;
291-
if (combined.tap && !combined.watch) {
339+
if (combined.tap && !combined.watch && debug === null) {
292340
reporter = new TapReporter({
293341
reportStream: process.stdout,
294342
stdStream: process.stderr
295343
});
296-
} else if (combined.verbose || isCi || !process.stdout.isTTY) {
344+
} else if (debug !== null || combined.verbose || isCi || !process.stdout.isTTY) {
297345
reporter = new VerboseReporter({
298346
reportStream: process.stdout,
299347
stdStream: process.stderr,

lib/worker/subprocess.js

+7
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ ipc.options.then(options => {
128128
// to make sure we also track dependencies with custom require hooks
129129
dependencyTracking.install(testPath);
130130

131+
if (options.debug) {
132+
require('inspector').open(options.debug.port, '127.0.0.1', true);
133+
if (options.debug.break) {
134+
debugger; // eslint-disable-line no-debugger
135+
}
136+
}
137+
131138
require(testPath);
132139

133140
if (accessedRunner) {

0 commit comments

Comments
 (0)