'List all mocha tests without executing them
Is there a way in mochajs to list all tests collected by test runner without executing them?
E.g. if there are specs that look like:
describe('First', function() {
it('should test something', function() {
...
})
});
describe('Second', function() {
it('should test something else', function() {
...
})
});
then I want to get console output similar to an output produced by test reporters, but without executing actual tests, like this:
First
should test something
Second
should test something else
UPD:
Currently I'm extracting all describes and its with regex, but looking for a cleaner solution.
Solution 1:[1]
The mocha-list-tests package is useful, but only works for BDD style describe() and it(), and it breaks if you .skip() any tests because it mocks it().
One way to do this yourself if you need to overcome either of those things, or get other information on the tests, is to exploit Mocha's root before() hook. This will be executed after Mocha has loaded all files but before it executes any tests, so all the information you need exists at that point.
This way, it is pretty easy to patch in a --list-only command line option to switch the behaviour of your test run without having to add or change anything else.
The key is that this in the before() hook is Mocha's Context, and the .test of that refers to the hook itself. So this.test.parent refers to the root suite. From there, you can walk down the tree of .suites arrays, and .tests arrays of each suite.
Having collected whatever you want, you have to then output that and exit the process to stop Mocha from continuing.
Plain Text Example
Given root.js:
#!/bin/env mocha
before(function() {
if(process.argv.includes('--list-only')) {
inspectSuite(this.test.parent, 0);
process.exit(0);
}
// else let Mocha carry on as normal...
});
function inspectSuite(suite, depth) {
console.log(indent(`Suite ${suite.title || '(root)'}`, depth));
suite.suites.forEach(suite => inspectSuite(suite, depth +1));
suite.tests.forEach(test => inspectTest(test, depth +1));
}
function inspectTest(test, depth) {
console.log(indent(`Test ${test.title}`, depth));
}
function indent(text, by) {
return ' '.repeat(by) + text;
}
And test.js:
#!/bin/env mocha
describe('foo', function() {
describe('bar', function() {
it('should do something', function() {
// ...
});
});
describe('baz', function() {
it.skip('should do something else', function() {
// ...
});
it('should do another thing', function() {
// ...
});
});
});
Then running mocha as normal would give you the test results you expect:
foo
bar
? should do something
baz
- should do something else
? should do another thing
2 passing (8ms)
1 pending
But running mocha --list-only would give you (without running any tests):
Suite (root)
Suite foo
Suite bar
Test should do something
Suite baz
Test should do something else
Test should do another thing
JSON Example
root.js
#!/bin/env mocha
before(function() {
let suites = 0;
let tests = 0;
let pending = 0;
let root = mapSuite(this.test.parent);
process.stdout.write(JSON.stringify({suites, tests, pending, root}, null, ' '));
process.exit(0);
function mapSuite(suite) {
suites += +!suite.root;
return {
title: suite.root ? '(root)' : suite.title,
suites: suite.suites.map(mapSuite),
tests: suite.tests.map(mapTest)
};
}
function mapTest(test) {
++tests;
pending += +test.pending;
return {
title: test.title,
pending: test.pending
};
}
});
With the same test script as before would give you:
{
"suites": 3,
"tests": 3,
"pending": 1,
"root": {
"title": "(root)",
"suites": [
{
"title": "foo",
"suites": [
{
"title": "bar",
"suites": [],
"tests": [
{
"title": "should do something",
"pending": false
}
]
},
{
"title": "baz",
"suites": [],
"tests": [
{
"title": "should do something else",
"pending": true
},
{
"title": "should do another thing",
"pending": false
}
]
}
],
"tests": []
}
],
"tests": []
}
}
Solution 2:[2]
Wrap all your describe blocks in a describe block and skip it.
describe.skip('Outline', function() {
describe('First', function() {
it('should test something', function() {
...
})
});
describe('Second', function() {
it('should test something else', function() {
...
})
});
});
Solution 3:[3]
As of mocha@9, the dry-run option (PR here) has been added.
If you want to list (and programmatically make use of) all tests, you want to enable dry-run and probably the json reporter + an output filepath like so:
{
"dry-run": true,
"reporter": "json",
"reporterOptions": [
"output": "./test-report.json"
]
}
How to produce a test list that we can use programmatically?
If you want to use the test output programmatically:
As of this commit (Aug 2021), you can just provide the output file config option, and then read the json file from your test processing program.
tough luck.
Turns out, the JSON reporter, contrary to its name, does not produce pure JSON (as discussed in this outstanding Mocha issue).
As a workaround, I wrote a little script (gist here), that works like so:
- Store mocha output to file:
npm run test > tests-raw.json- Or:
yarn test > tests-raw.json - Or:
mocha --dry-run --reporter=json ... > tests-raw.json
- Or:
- Convert the output:
./mocha-list-tests.js tests-raw.json tests.json - The file
tests.jsonnow contains an array of all the test result objects. Each call tomochathat was recorded should yield one such object.
More Config Options
I could not find much documentation on the exact output format, but it's mostly just two things:
stats- basic overall statstests- all found tests (see Test#serialize method)failures,pending,passes- you probably don't care about these if you only want to list tests.
Solution 4:[4]
mocha-list-tests package
I kid you not, there is a separate package for that: https://www.npmjs.com/package/mocha-list-tests
npm install mocha mocha-list-tests
node ./node_modules/mocha-list-tests/mocha-list-tests.js main.js
Sample output:
{
"suites": [
"a1",
"a2"
],
"tests": [
"a1.a11",
"a1.a12",
"a2.a21",
"a2.a22"
],
"tree": {
"a1": {
"a11": true,
"a12": true
},
"a2": {
"a21": true,
"a22": true
}
}
}
for this test file:
main.js
#!/usr/bin/env node
const assert = require('assert');
const fs = require('fs');
describe('a1', function() {
it('a11', function() {
assert.equal(1, 1);
fs.writeFileSync('abc', 'def', 'utf8');
});
it('a12', function() {
assert.equal(1, 2);
});
});
describe('a2', function() {
it('a21', function() {
assert.equal(1, 1);
});
it('a22', function() {
assert.equal(1, 2);
});
});
The file abc was not created, so I know that tests were not executed.
This is likely using the API Mocha mentioned at: https://github.com/mochajs/mocha/wiki/Using-Mocha-programmatically
Teste in [email protected], [email protected], Node v10.15.1.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | dNitro |
| Solution 3 | |
| Solution 4 | Ciro Santilli Путлер Капут å…四事 |
