Mocha JSON Report(er)
In Mocha, popular JavaScript test framework, you can change the default spec reporter. There are a few options included by default, you can also install various 3rd party reporters you can find e.g. in NPM repository. However, if you want to process test results, JSON is probably a format to go and the default JSON reporter should get you all important info.
To configure Mocha, you can use .mocharc.json
. To use the JSON reporter, add the following two properties to the file:
{
"reporter": "json",
"reporterOptions": [
"output=./results.json"
]
}
After you run your tests, you should see results.json
file in the root of the project. A sample output can look like:
{
"stats": {
"suites": 1,
"tests": 7,
"passes": 6,
"pending": 0,
"failures": 1,
"start": "2022-11-11T19:43:36.376Z",
"end": "2022-11-11T19:43:36.381Z",
"duration": 5
},
"tests": [
{
"title": "return string",
"fullTitle": "formatDay() return string",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 1,
"currentRetry": 0,
"speed": "fast",
"err": {}
},
{
"title": "return correct format",
"fullTitle": "formatDay() return correct format",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 0,
"currentRetry": 0,
"speed": "fast",
"err": {}
},
{
"title": "month undefined",
"fullTitle": "formatDay() month undefined",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 0,
"currentRetry": 0,
"speed": "fast",
"err": {}
},
{
"title": "month null",
"fullTitle": "formatDay() month null",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 1,
"currentRetry": 0,
"err": {
"message": "expected undefined to equal 2",
"showDiff": true,
"expected": 2,
"operator": "strictEqual",
"stack": "AssertionError: expected undefined to equal 2\n at Context.<anonymous> (file:///home/pavel/testing/useful/tests/formatDay.test.js:28:39)\n at process.processImmediate (node:internal/timers:471:21)"
}
},
{
"title": "month primitive",
"fullTitle": "formatDay() month primitive",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 0,
"currentRetry": 0,
"speed": "fast",
"err": {}
},
{
"title": "month string",
"fullTitle": "formatDay() month string",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 0,
"currentRetry": 0,
"speed": "fast",
"err": {}
},
{
"title": "month object",
"fullTitle": "formatDay() month object",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 0,
"currentRetry": 0,
"speed": "fast",
"err": {}
}
],
"pending": [],
"failures": [
{
"title": "month null",
"fullTitle": "formatDay() month null",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 1,
"currentRetry": 0,
"err": {
"message": "expected undefined to equal 2",
"showDiff": true,
"expected": 2,
"operator": "strictEqual",
"stack": "AssertionError: expected undefined to equal 2\n at Context.<anonymous> (file:///home/pavel/testing/useful/tests/formatDay.test.js:28:39)\n at process.processImmediate (node:internal/timers:471:21)"
}
}
],
"passes": [
{
"title": "return string",
"fullTitle": "formatDay() return string",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 1,
"currentRetry": 0,
"speed": "fast",
"err": {}
},
{
"title": "return correct format",
"fullTitle": "formatDay() return correct format",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 0,
"currentRetry": 0,
"speed": "fast",
"err": {}
},
{
"title": "month undefined",
"fullTitle": "formatDay() month undefined",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 0,
"currentRetry": 0,
"speed": "fast",
"err": {}
},
{
"title": "month primitive",
"fullTitle": "formatDay() month primitive",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 0,
"currentRetry": 0,
"speed": "fast",
"err": {}
},
{
"title": "month string",
"fullTitle": "formatDay() month string",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 0,
"currentRetry": 0,
"speed": "fast",
"err": {}
},
{
"title": "month object",
"fullTitle": "formatDay() month object",
"file": "/home/pavel/testing/useful/tests/formatDay.test.js",
"duration": 0,
"currentRetry": 0,
"speed": "fast",
"err": {}
}
]
}
There’s the stats
object with some summary information about the whole test run. If you need to check that no tests have failed, you can check the stats.failures
value. A good thing is that if there’s been a failure in hooks, Mocha will increment this value as well.
tests
array includes all executed tests — failed, passed, and pending (skipped). If a test failed, details will be in the err
object. One caveat is that if a test is skipped, the corresponding object will have no duration
property.
If you want only passed tests, parse passed
array. I don’t know why objects in this array have the err
property, though. If tests passed, I’d expect this object to be empty, so at this point, I have no idea if the property is included just for the consistency sake (but then why not include duration
with skipped tests?).
failures
array is interesting because it containes both failed tests and other parts like failed hooks. If you want to get all failures encountered during a test run, parsing this array is a way to go.
Finally pending
array should include skipped tests. Mocha marks everything skipped as pending.
That said, if you need to parse this file because, for example, you want to send the results somewhere else (e.g. to some monitoring platform like New Relic), then I’d say get all failures from failures
and then get only passed and skipped tests from tests
, e.g.:
const isFailed = (testCase) => (Object.keys(testCase.err).length === 0 ? false : true);
That way, you won’t end up having failed tests reported twice.