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

+1
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

+10-3
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
};

docs/api-tutorials/custom-reporter.md

+120
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
+5
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

+18-17
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

+2-1
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

+2-1
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

+3-1
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

+1-1
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

+3-1
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;

lib/interfaces/tdd.js

+3-1
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
* TDD-style interface:
@@ -30,7 +32,7 @@ var Test = require('../test');
3032
module.exports = function(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.setup = common.beforeEach;

lib/mocha.js

+12-7
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ var builtinReporters = require('./reporters');
1212
var growl = require('./growl');
1313
var utils = require('./utils');
1414
var mocharc = require('./mocharc.json');
15-
var assign = require('object.assign').getPolyfill();
1615
var errors = require('./errors');
16+
var Suite = require('./suite');
17+
var createStatsCollector = require('./stats-collector');
1718
var createInvalidReporterError = errors.createInvalidReporterError;
1819
var createInvalidInterfaceError = errors.createInvalidInterfaceError;
20+
var EVENT_FILE_PRE_REQUIRE = Suite.constants.EVENT_FILE_PRE_REQUIRE;
21+
var EVENT_FILE_POST_REQUIRE = Suite.constants.EVENT_FILE_POST_REQUIRE;
22+
var EVENT_FILE_REQUIRE = Suite.constants.EVENT_FILE_REQUIRE;
1923

2024
exports = module.exports = Mocha;
2125

@@ -51,7 +55,7 @@ exports.Context = require('./context');
5155
* @memberof Mocha
5256
*/
5357
exports.Runner = require('./runner');
54-
exports.Suite = require('./suite');
58+
exports.Suite = Suite;
5559
exports.Hook = require('./hook');
5660
exports.Test = require('./test');
5761

@@ -88,7 +92,7 @@ exports.Test = require('./test');
8892
* @param {boolean} [options.useInlineDiffs] - Use inline diffs?
8993
*/
9094
function Mocha(options) {
91-
options = assign({}, mocharc, options || {});
95+
options = utils.assign({}, mocharc, options || {});
9296
this.files = [];
9397
this.options = options;
9498
// root suite
@@ -276,7 +280,7 @@ Mocha.prototype.ui = function(name) {
276280
}
277281
this._ui = this._ui(this.suite);
278282

279-
this.suite.on('pre-require', function(context) {
283+
this.suite.on(EVENT_FILE_PRE_REQUIRE, function(context) {
280284
exports.afterEach = context.afterEach || context.teardown;
281285
exports.after = context.after || context.suiteTeardown;
282286
exports.beforeEach = context.beforeEach || context.setup;
@@ -313,9 +317,9 @@ Mocha.prototype.loadFiles = function(fn) {
313317
var suite = this.suite;
314318
this.files.forEach(function(file) {
315319
file = path.resolve(file);
316-
suite.emit('pre-require', global, file, self);
317-
suite.emit('require', require(file), file, self);
318-
suite.emit('post-require', global, file, self);
320+
suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self);
321+
suite.emit(EVENT_FILE_REQUIRE, require(file), file, self);
322+
suite.emit(EVENT_FILE_POST_REQUIRE, global, file, self);
319323
});
320324
fn && fn();
321325
};
@@ -759,6 +763,7 @@ Mocha.prototype.run = function(fn) {
759763
var options = this.options;
760764
options.files = this.files;
761765
var runner = new exports.Runner(suite, options.delay);
766+
createStatsCollector(runner);
762767
var reporter = new this._reporter(runner, options);
763768
runner.ignoreLeaks = options.ignoreLeaks !== false;
764769
runner.fullStackTrace = options.fullStackTrace;

lib/reporters/base.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ var diff = require('diff');
1111
var milliseconds = require('ms');
1212
var utils = require('../utils');
1313
var supportsColor = process.browser ? null : require('supports-color');
14+
var constants = require('../runner').constants;
15+
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
16+
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
1417

1518
/**
1619
* Expose `Base`.
@@ -274,7 +277,7 @@ function Base(runner) {
274277
this.stats = runner.stats; // assigned so Reporters keep a closer reference
275278
this.runner = runner;
276279

277-
runner.on('pass', function(test) {
280+
runner.on(EVENT_TEST_PASS, function(test) {
278281
if (test.duration > test.slow()) {
279282
test.speed = 'slow';
280283
} else if (test.duration > test.slow() / 2) {
@@ -284,7 +287,7 @@ function Base(runner) {
284287
}
285288
});
286289

287-
runner.on('fail', function(test, err) {
290+
runner.on(EVENT_TEST_FAIL, function(test, err) {
288291
if (showDiff(err)) {
289292
stringifyDiffObjs(err);
290293
}

0 commit comments

Comments
 (0)