Skip to content

Commit 52b9a5f

Browse files
committed
refactor: use constants for event names instead of string literals
- also a few other string literals got replaced, but not error messages nor codes - supporting refactors: - move the suite "GC" function into the `Suite` prototype - move stats collector init to `Mocha#run` due to circular reference with `Runner` - rename a couple fixture files lacking proper extension - rename variable in integration test helpers - add `utils.createMap()` and `utils.defineConstants()` - add `test/integration/fixtures` to `.eslintignore` so no fixture linting occurs whatsoever - consolidated use of `object.assign` polyfill into `utils` module - some docstring fixes/consistency - adds `EVENT_DELAY_END` emitted from `Runner` for reporter use - specifically did NOT refactor event names from Node.js incl. `error` and `uncaughtException` - add custom reporter tutorial to API documentation - automatically injects reporter example into tutorial via `markdown-magic` - add `docs.preprocess.api` script - add JSDoc configuration to support tutorials - sort JSDoc config object because fussy - fix broken custom assertion
1 parent 29aa611 commit 52b9a5f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1185
-380
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ mocha.js
44
docs/
55
out/
66
!lib/mocha.js
7+
test/integration/fixtures
78
!.*.js

.wallaby.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,14 @@ module.exports = () => {
3838
const runningMocha = wallaby.testFramework;
3939
runningMocha.timeout(200);
4040
// to expose it/describe etc. on the mocha under test
41-
const mochaUnderTest = new (require('./'))();
42-
mochaUnderTest.suite.emit('pre-require', global, '', mochaUnderTest);
41+
const MochaUnderTest = require('./');
42+
const mochaUnderTest = new MochaUnderTest();
43+
mochaUnderTest.suite.emit(
44+
MochaUnderTest.Suite.constants.EVENT_FILE_PRE_REQUIRE,
45+
global,
46+
'',
47+
mochaUnderTest
48+
);
4349
// to make test/node-unit/color.spec.js pass, we need to run mocha in the project's folder context
4450
const childProcess = require('child_process');
4551
const execFile = childProcess.execFile;
@@ -53,6 +59,7 @@ module.exports = () => {
5359
return execFile.apply(this, arguments);
5460
};
5561
require('./test/setup');
56-
}
62+
},
63+
debug: true
5764
};
5865
};
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
Mocha allows you to define and use custom reporters install via `npm`.
2+
3+
For example, if `mocha-foo-reporter` was published to the npm registry, you could install it via `npm install mocha-foo-reporter --save-dev`, then use it via `mocha --reporter mocha-foo-reporter`.
4+
5+
## Example Custom Reporter
6+
7+
If you're looking to get started quickly, here's an example of a custom reporter:
8+
9+
<!-- AUTO-GENERATED-CONTENT:START (file:src=../../test/integration/fixtures/simple-reporter.js&header=// my-reporter.js)' -->
10+
11+
```js
12+
// my-reporter.js
13+
'use strict';
14+
15+
const Mocha = require('mocha');
16+
const {
17+
EVENT_RUN_BEGIN,
18+
EVENT_RUN_END,
19+
EVENT_TEST_FAIL,
20+
EVENT_TEST_PASS,
21+
EVENT_SUITE_BEGIN,
22+
EVENT_SUITE_END
23+
} = Mocha.Runner.constants;
24+
25+
// this reporter outputs test results, indenting two spaces per suite
26+
class MyReporter {
27+
constructor(runner) {
28+
this._indents = 0;
29+
const stats = runner.stats;
30+
31+
runner
32+
.once(EVENT_RUN_BEGIN, () => {
33+
console.log('start');
34+
})
35+
.on(EVENT_SUITE_BEGIN, () => {
36+
this.increaseIndent();
37+
})
38+
.on(EVENT_SUITE_END, () => {
39+
this.decreaseIndent();
40+
})
41+
.on(EVENT_TEST_PASS, test => {
42+
// Test#fullTitle() returns the suite name(s)
43+
// prepended to the test title
44+
console.log(`${this.indent()}pass: ${test.fullTitle()}`);
45+
})
46+
.on(EVENT_TEST_FAIL, (test, err) => {
47+
console.log(
48+
`${this.indent()}fail: ${test.fullTitle()} - error: ${err.message}`
49+
);
50+
})
51+
.once(EVENT_RUN_END, () => {
52+
console.log(`end: ${stats.passes}/${stats.passes + stats.failures} ok`);
53+
});
54+
}
55+
56+
indent() {
57+
return Array(this._indents).join(' ');
58+
}
59+
60+
increaseIndent() {
61+
this._indents++;
62+
}
63+
64+
decreaseIndent() {
65+
this._indents--;
66+
}
67+
}
68+
69+
module.exports = MyReporter;
70+
```
71+
72+
<!-- AUTO-GENERATED-CONTENT:END -->
73+
74+
To use this reporter, execute `mocha --reporter /path/to/my-reporter.js`.
75+
76+
For further examples, the built-in reporter implementations are the [best place to look](https://github.com/mochajs/mocha/tree/master/lib/reporters). The [integration tests](https://github.com/mochajs/mocha/tree/master/test/reporters) may also be helpful.
77+
78+
## The `Base` Reporter Class
79+
80+
[Base] is an "abstract" class. It contains console-specific settings and utilities, commonly used by built-in reporters. Browsing the built-in reporter implementations, you may often see static properties of [Base] referenced.
81+
82+
It's often useful--but not necessary--for a custom reporter to extend [Base].
83+
84+
## Statistics
85+
86+
Mocha adds a `stats` property of type [StatsCollector](/api/module-lib_stats-collector.html) to the reporter's `Runner` instance (passed as first argument to constructor).
87+
88+
## Events
89+
90+
A reporter should listen for events emitted from the `runner` (a singleton instance of [Runner]).
91+
92+
The event names are exported from the `constants` property of `Mocha.Runner`:
93+
94+
| Constant | Event Name | Event Arguments | Description |
95+
| -------------------- | ----------- | --------------- | ------------------------------------------------------------------------------------------- |
96+
| `EVENT_RUN_BEGIN` | `start` | _(n/a)_ | Execution will begin. |
97+
| `EVENT_RUN_END` | `end` | _(n/a)_ | All [Suite]s, [Test]s and [Hook]s have completed execution. |
98+
| `EVENT_DELAY_BEGIN` | `waiting` | _(n/a)_ | Waiting for `global.run()` to be called; only emitted when [delay] option is `true`. |
99+
| `EVENT_DELAY_END` | `ready` | _(n/a)_ | User called `global.run()` and the root suite is ready to execute. |
100+
| `EVENT_SUITE_BEGIN` | `suite` | `Suite` | The [Hook]s and [Test]s within a [Suite] will be executed, including any nested [Suite]s. |
101+
| `EVENT_SUITE_END` | `suite end` | `Suite` | The [Hook]s, [Test]s, and nested [Suite]s within a [Suite] have completed execution. |
102+
| `EVENT_HOOK_BEGIN` | `hook` | `Hook` | A [Hook] will be executed. |
103+
| `EVENT_HOOK_END` | `hook end` | `Hook` | A [Hook] has completed execution. |
104+
| `EVENT_TEST_BEGIN` | `test` | `Test` | A [Test] will be executed. |
105+
| `EVENT_TEST_END` | `test end` | `Test` | A [Test] has completed execution. |
106+
| `EVENT_TEST_FAIL` | `fail` | `Test`, `Error` | A [Test] has failed or thrown an exception. |
107+
| `EVENT_TEST_PASS` | `pass` | `Test` | A [Test] has passed. |
108+
| `EVENT_TEST_PENDING` | `pending` | `Test` | A [Test] was skipped. |
109+
| `EVENT_TEST_RETRY` | `retry` | `Test`, `Error` | A [Test] failed, but is about to be retried; only emitted if the `retry` option is nonzero. |
110+
111+
**Please use these constants** instead of the event names in your own reporter! This will ensure compatibility with future versions of Mocha.
112+
113+
> It's important to understand that all `Suite` callbacks will be run _before_ the [Runner] emits `EVENT_RUN_BEGIN`. Hooks and tests, however, won't run until _after_ the [Runner] emits `EVENT_RUN_BEGIN`.
114+
115+
[runner]: /api/mocha.runner
116+
[test]: /api/mocha.test
117+
[hook]: /api/mocha.hook
118+
[suite]: /api/mocha.suite
119+
[base]: /api/mocha.reporters.base
120+
[delay]: /#delayed-root-suite
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"custom-reporter": {
3+
"title": "Create a Custom Reporter"
4+
}
5+
}

jsdoc.conf.json

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
11
{
2-
"tags": {
3-
"allowUnknownTags": true
2+
"markdown": {
3+
"hardwrap": true,
4+
"parser": "gfm"
45
},
5-
"source": {
6-
"include": ["lib/", "./docs/API.md", "bin"]
6+
"mocha-docdash": {
7+
"sort": true,
8+
"static": false
79
},
8-
"plugins": ["plugins/markdown"],
910
"opts": {
10-
"encoding": "utf8",
11-
"template": "node_modules/@mocha/docdash",
1211
"destination": "docs/_dist/api",
12+
"encoding": "utf8",
1313
"recurse": true,
14+
"template": "node_modules/@mocha/docdash",
15+
"tutorials": "docs/api-tutorials",
1416
"verbose": true
1517
},
16-
"markdown": {
17-
"parser": "gfm",
18-
"hardwrap": true
18+
"plugins": ["plugins/markdown"],
19+
"source": {
20+
"include": ["lib/", "./docs/API.md", "bin"]
21+
},
22+
"tags": {
23+
"allowUnknownTags": true
1924
},
2025
"templates": {
2126
"cleverLinks": false,
22-
"monospaceLinks": false,
2327
"default": {
24-
"outputSourceFiles": true,
25-
"includeDate": false
26-
}
28+
"includeDate": false,
29+
"outputSourceFiles": true
2730
},
28-
"mocha-docdash": {
29-
"static": false,
30-
"sort": true
31+
"monospaceLinks": false
3132
}
3233
}

lib/browser/growl.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*/
1111
var Date = global.Date;
1212
var setTimeout = global.setTimeout;
13+
var EVENT_RUN_END = require('../runner').constants.EVENT_RUN_END;
1314

1415
/**
1516
* Checks if browser notification support exists.
@@ -53,7 +54,7 @@ exports.notify = function(runner) {
5354
.catch(notPermitted);
5455
};
5556

56-
runner.once('end', sendNotification);
57+
runner.once(EVENT_RUN_END, sendNotification);
5758
};
5859

5960
/**

lib/growl.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
const os = require('os');
99
const path = require('path');
1010
const {sync: which} = require('which');
11+
const {EVENT_RUN_END} = require('./runner').constants;
1112

1213
/**
1314
* @summary
@@ -41,7 +42,7 @@ exports.isCapable = () => {
4142
* @param {Runner} runner - Runner instance.
4243
*/
4344
exports.notify = runner => {
44-
runner.once('end', () => {
45+
runner.once(EVENT_RUN_END, () => {
4546
display(runner);
4647
});
4748
};

lib/interfaces/bdd.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
'use strict';
22

33
var Test = require('../test');
4+
var EVENT_FILE_PRE_REQUIRE = require('../suite').constants
5+
.EVENT_FILE_PRE_REQUIRE;
46

57
/**
68
* BDD-style interface:
@@ -22,7 +24,7 @@ var Test = require('../test');
2224
module.exports = function bddInterface(suite) {
2325
var suites = [suite];
2426

25-
suite.on('pre-require', function(context, file, mocha) {
27+
suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) {
2628
var common = require('./common')(suites, context, mocha);
2729

2830
context.before = common.before;

lib/interfaces/exports.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ var Test = require('../test');
2222
module.exports = function(suite) {
2323
var suites = [suite];
2424

25-
suite.on('require', visit);
25+
suite.on(Suite.constants.EVENT_FILE_REQUIRE, visit);
2626

2727
function visit(obj, file) {
2828
var suite;

lib/interfaces/qunit.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
'use strict';
22

33
var Test = require('../test');
4+
var EVENT_FILE_PRE_REQUIRE = require('../suite').constants
5+
.EVENT_FILE_PRE_REQUIRE;
46

57
/**
68
* QUnit-style interface:
@@ -30,7 +32,7 @@ var Test = require('../test');
3032
module.exports = function qUnitInterface(suite) {
3133
var suites = [suite];
3234

33-
suite.on('pre-require', function(context, file, mocha) {
35+
suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) {
3436
var common = require('./common')(suites, context, mocha);
3537

3638
context.before = common.before;

0 commit comments

Comments
 (0)