Skip to content

Commit

Permalink
renames, rearranging constants
Browse files Browse the repository at this point in the history
- much destructuring
- many renames
- adds `EVENT_DELAY_END` emitted from `Runner` for reporter use; needs tests
- consolidated use of `object.assign` polyfill into `utils` module
- some docstring fixes/consistency
- add `utils.createMap()` and `utils.defineConstants()`; needs more tests
- fix broken custom assertion
- don't needlessly extend `Base` reporter in simple reporter example
  • Loading branch information
boneskull committed Jan 22, 2019
1 parent a585f07 commit 9642e60
Show file tree
Hide file tree
Showing 39 changed files with 653 additions and 429 deletions.
13 changes: 10 additions & 3 deletions .wallaby.js
Expand Up @@ -38,8 +38,14 @@ module.exports = () => {
const runningMocha = wallaby.testFramework;
runningMocha.timeout(200);
// to expose it/describe etc. on the mocha under test
const mochaUnderTest = new (require('./'))();
mochaUnderTest.suite.emit('pre-require', global, '', mochaUnderTest);
const MochaUnderTest = require('./');
const mochaUnderTest = new MochaUnderTest();
mochaUnderTest.suite.emit(
MochaUnderTest.Suite.constants.EVENT_FILE_PRE_REQUIRE,
global,
'',
mochaUnderTest
);
// to make test/node-unit/color.spec.js pass, we need to run mocha in the project's folder context
const childProcess = require('child_process');
const execFile = childProcess.execFile;
Expand All @@ -53,6 +59,7 @@ module.exports = () => {
return execFile.apply(this, arguments);
};
require('./test/setup');
}
},
debug: true
};
};
75 changes: 43 additions & 32 deletions docs/api-tutorials/custom-reporter.md
Expand Up @@ -11,44 +11,42 @@ If you're looking to get started quickly, here's an example of a custom reporter

const Mocha = require('mocha');
const {
RUNNER_EVENT_BEGIN,
RUNNER_EVENT_END,
RUNNER_EVENT_FAIL,
RUNNER_EVENT_PASS,
RUNNER_EVENT_SUITE_BEGIN,
RUNNER_EVENT_SUITE_END
EVENT_RUN_BEGIN,
EVENT_RUN_END,
EVENT_TEST_FAIL,
EVENT_TEST_PASS,
EVENT_SUITE_BEGIN,
EVENT_SUITE_END
} = Mocha.Runner.constants;
const Base = Mocha.reporters.Base;

// this reporter outputs test results, indenting two spaces per suite
class MyReporter extends Base {
class MyReporter {
constructor(runner) {
super(runner);

this._indents = 0;

runner
.once(RUNNER_EVENT_BEGIN, () => {
.once(EVENT_RUN_BEGIN, () => {
console.log('start');
})
.on(RUNNER_EVENT_SUITE_BEGIN, () => {
.on(EVENT_SUITE_BEGIN, () => {
this.increaseIndent();
})
.on(RUNNER_EVENT_SUITE_END, () => {
.on(EVENT_SUITE_END, () => {
this.decreaseIndent();
})
.on(RUNNER_EVENT_PASS, test => {
.on(EVENT_TEST_PASS, test => {
// Test#fullTitle() returns the suite name(s)
// prepended to the test title
console.log(`${this.indent()}pass: ${test.fullTitle()}`);
})
.on(RUNNER_EVENT_FAIL, (test, err) => {
.on(EVENT_TEST_FAIL, (test, err) => {
console.log(
`${this.indent()}fail: ${test.fullTitle()} - error: ${err.message}`
);
})
.once(RUNNER_EVENT_END, () => {
// Base reporter has a `stats` property
.once(EVENT_RUN_END, () => {
console.log(
`end: ${this.stats.passes}/${this.stats.passes +
this.stats.failures} ok`
Expand Down Expand Up @@ -78,33 +76,46 @@ To use this reporter, execute `mocha --reporter /path/to/my-reporter.js`.

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.

## The `Base` Reporter Class

[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.

It's often useful--but not necessary--for a custom reporter to extend [Base].

## Statistics

Mocha adds a `stats` property of type [StatsCollector](/api/module-lib_stats-collector.html) to each reporter instance immediately following instantiation.

## Events

A reporter should listen for events emitted from the `runner` (an instance of [Runner]).
A reporter should listen for events emitted from the `runner` (a singleton instance of [Runner]).

The event names are exported from the `constants` property of `Mocha.Runner`:

| Constant | Event Name | Event Arguments | Description |
| -------------------------- | ----------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RUNNER_EVENT_BEGIN` | `start` | _(n/a)_ | Execution will begin. Corresponding "end" event is `RUNNER_EVENT_END`. |
| `RUNNER_EVENT_END` | `end` | _(n/a)_ | All [Suite]s, [Test]s and [Hook]s have completed execution. Corresponding "begin" event is `RUNNER_EVENT_BEGIN`. |
| `RUNNER_EVENT_SUITE_BEGIN` | `suite` | `Suite` | The [Hook]s and [Test]s within a [Suite] are about to be executed. Any nested [Suite]s will also be executed. Corresponding "end" event is `RUNNER_EVENT_SUITE_END`. |
| `RUNNER_EVENT_SUITE_END` | `suite end` | `Suite` | The [Hook]s, [Test]s, and nested [Suite]s within a [Suite] have completed execution. Corresponding "begin" event is `RUNNER_EVENT_SUITE_BEGIN`. |
| `RUNNER_EVENT_HOOK_BEGIN` | `hook` | `Hook` | A [Hook] will execute. Corresponding "end" event is `RUNNER_EVENT_HOOK_END`. |
| `RUNNER_EVENT_HOOK_END` | `hook end` | `Hook` | A [Hook] has completed execution. Corresponding "begin" event is `RUNNER_EVENT_HOOK_BEGIN`. |
| `RUNNER_EVENT_TEST_BEGIN` | `test` | `Test` | A [Test] will execute. Corresponding "end" event is `RUNNER_EVENT_TEST_END`. |
| `RUNNER_EVENT_TEST_END` | `test end` | `Test` | A [Test] has completed execution. Corresponding "begin" event is `RUNNER_EVENT_TEST_BEGIN`. |
| `RUNNER_EVENT_FAIL` | `fail` | `Test`, `Error` | A [Test] has failed or thrown an exception. |
| `RUNNER_EVENT_PASS` | `pass` | `Test` | A [Test] has passed. |
| `RUNNER_EVENT_PENDING` | `pending` | `Test` | A [Test] was skipped. |
| `RUNNER_EVENT_RETRY` | `retry` | `Test`, `Error` | A [Test] failed, but is about to be retried; only emitted if the `retry` option is nonzero. |
| `RUNNER_EVENT_WAITING` | `waiting` | _(n/a)_ | Waiting for `global.run()` to be called; only emitted when `delay` option is `true`. |
| Constant | Event Name | Event Arguments | Description |
| -------------------- | ----------- | --------------- | ------------------------------------------------------------------------------------------- |
| `EVENT_RUN_BEGIN` | `start` | _(n/a)_ | Execution will begin. |
| `EVENT_RUN_END` | `end` | _(n/a)_ | All [Suite]s, [Test]s and [Hook]s have completed execution. |
| `EVENT_DELAY_BEGIN` | `waiting` | _(n/a)_ | Waiting for `global.run()` to be called; only emitted when [delay] option is `true`. |
| `EVENT_DELAY_END` | `ready` | _(n/a)_ | User called `global.run()` and the root suite is ready to execute. |
| `EVENT_SUITE_BEGIN` | `suite` | `Suite` | The [Hook]s and [Test]s within a [Suite] will be executed, including any nested [Suite]s. |
| `EVENT_SUITE_END` | `suite end` | `Suite` | The [Hook]s, [Test]s, and nested [Suite]s within a [Suite] have completed execution. |
| `EVENT_HOOK_BEGIN` | `hook` | `Hook` | A [Hook] will be executed. |
| `EVENT_HOOK_END` | `hook end` | `Hook` | A [Hook] has completed execution. |
| `EVENT_TEST_BEGIN` | `test` | `Test` | A [Test] will be executed. |
| `EVENT_TEST_END` | `test end` | `Test` | A [Test] has completed execution. |
| `EVENT_TEST_FAIL` | `fail` | `Test`, `Error` | A [Test] has failed or thrown an exception. |
| `EVENT_TEST_PASS` | `pass` | `Test` | A [Test] has passed. |
| `EVENT_TEST_PENDING` | `pending` | `Test` | A [Test] was skipped. |
| `EVENT_TEST_RETRY` | `retry` | `Test`, `Error` | A [Test] failed, but is about to be retried; only emitted if the `retry` option is nonzero. |

**Please use these constants** instead of the event names in your own reporter! This will ensure compatibility with future versions of Mocha.

> It's important to understand that all suite callbacks will be run _before_ the [Runner] emits `RUNNER_EVENT_BEGIN`. Hooks and tests, however, won't run until _after_ the [Runner] emits `RUNNER_EVENT_BEGIN`.
> 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`.
[runner]: /api/mocha.runner
[test]: /api/mocha.test
[hook]: /api/mocha.hook
[suite]: /api/mocha.suite
[base]: /api/mocha.reporters.base
[delay]: /#delayed-root-suite
4 changes: 2 additions & 2 deletions lib/browser/growl.js
Expand Up @@ -10,7 +10,7 @@
*/
var Date = global.Date;
var setTimeout = global.setTimeout;
var RUNNER_EVENT_END = require('../runner').constants.RUNNER_EVENT_END;
var EVENT_RUN_END = require('../runner').constants.EVENT_RUN_END;

/**
* Checks if browser notification support exists.
Expand Down Expand Up @@ -54,7 +54,7 @@ exports.notify = function(runner) {
.catch(notPermitted);
};

runner.once(RUNNER_EVENT_END, sendNotification);
runner.once(EVENT_RUN_END, sendNotification);
};

/**
Expand Down
4 changes: 2 additions & 2 deletions lib/growl.js
Expand Up @@ -8,7 +8,7 @@
const os = require('os');
const path = require('path');
const {sync: which} = require('which');
const {RUNNER_EVENT_END} = require('./runner').constants;
const {EVENT_RUN_END} = require('./runner').constants;

/**
* @summary
Expand Down Expand Up @@ -42,7 +42,7 @@ exports.isCapable = () => {
* @param {Runner} runner - Runner instance.
*/
exports.notify = runner => {
runner.once(RUNNER_EVENT_END, () => {
runner.once(EVENT_RUN_END, () => {
display(runner);
});
};
Expand Down
9 changes: 3 additions & 6 deletions lib/interfaces/bdd.js
@@ -1,7 +1,8 @@
'use strict';

var Test = require('../test');
var Suite = require('../suite');
var EVENT_FILE_PRE_REQUIRE = require('../suite').constants
.EVENT_FILE_PRE_REQUIRE;

/**
* BDD-style interface:
Expand All @@ -23,11 +24,7 @@ var Suite = require('../suite');
module.exports = function bddInterface(suite) {
var suites = [suite];

suite.on(Suite.constants.EVENT_FILE_PRE_REQUIRE, function(
context,
file,
mocha
) {
suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) {
var common = require('./common')(suites, context, mocha);

context.before = common.before;
Expand Down
9 changes: 3 additions & 6 deletions lib/interfaces/qunit.js
@@ -1,7 +1,8 @@
'use strict';

var Test = require('../test');
var Suite = require('../suite');
var EVENT_FILE_PRE_REQUIRE = require('../suite').constants
.EVENT_FILE_PRE_REQUIRE;

/**
* QUnit-style interface:
Expand Down Expand Up @@ -31,11 +32,7 @@ var Suite = require('../suite');
module.exports = function qUnitInterface(suite) {
var suites = [suite];

suite.on(Suite.constants.EVENT_FILE_PRE_REQUIRE, function(
context,
file,
mocha
) {
suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) {
var common = require('./common')(suites, context, mocha);

context.before = common.before;
Expand Down
9 changes: 3 additions & 6 deletions lib/interfaces/tdd.js
@@ -1,7 +1,8 @@
'use strict';

var Test = require('../test');
var Suite = require('../suite');
var EVENT_FILE_PRE_REQUIRE = require('../suite').constants
.EVENT_FILE_PRE_REQUIRE;

/**
* TDD-style interface:
Expand Down Expand Up @@ -31,11 +32,7 @@ var Suite = require('../suite');
module.exports = function(suite) {
var suites = [suite];

suite.on(Suite.constants.EVENT_FILE_PRE_REQUIRE, function(
context,
file,
mocha
) {
suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) {
var common = require('./common')(suites, context, mocha);

context.setup = common.beforeEach;
Expand Down
14 changes: 8 additions & 6 deletions lib/mocha.js
Expand Up @@ -12,12 +12,14 @@ var builtinReporters = require('./reporters');
var growl = require('./growl');
var utils = require('./utils');
var mocharc = require('./mocharc.json');
var assign = require('object.assign').getPolyfill();
var errors = require('./errors');
var Suite = require('./suite');
var createStatsCollector = require('./stats-collector');
var createInvalidReporterError = errors.createInvalidReporterError;
var createInvalidInterfaceError = errors.createInvalidInterfaceError;
var EVENT_FILE_PRE_REQUIRE = Suite.constants.EVENT_FILE_PRE_REQUIRE;
var EVENT_FILE_POST_REQUIRE = Suite.constants.EVENT_FILE_POST_REQUIRE;
var EVENT_FILE_REQUIRE = Suite.constants.EVENT_FILE_REQUIRE;

exports = module.exports = Mocha;

Expand Down Expand Up @@ -90,7 +92,7 @@ exports.Test = require('./test');
* @param {boolean} [options.useInlineDiffs] - Use inline diffs?
*/
function Mocha(options) {
options = assign({}, mocharc, options || {});
options = utils.assign({}, mocharc, options || {});
this.files = [];
this.options = options;
// root suite
Expand Down Expand Up @@ -278,7 +280,7 @@ Mocha.prototype.ui = function(name) {
}
this._ui = this._ui(this.suite);

this.suite.on(Suite.constants.EVENT_FILE_PRE_REQUIRE, function(context) {
this.suite.on(EVENT_FILE_PRE_REQUIRE, function(context) {
exports.afterEach = context.afterEach || context.teardown;
exports.after = context.after || context.suiteTeardown;
exports.beforeEach = context.beforeEach || context.setup;
Expand Down Expand Up @@ -315,9 +317,9 @@ Mocha.prototype.loadFiles = function(fn) {
var suite = this.suite;
this.files.forEach(function(file) {
file = path.resolve(file);
suite.emit(Suite.constants.EVENT_FILE_PRE_REQUIRE, global, file, self);
suite.emit(Suite.constants.EVENT_FILE_REQUIRE, require(file), file, self);
suite.emit(Suite.constants.EVENT_FILE_POST_REQUIRE, global, file, self);
suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self);
suite.emit(EVENT_FILE_REQUIRE, require(file), file, self);
suite.emit(EVENT_FILE_POST_REQUIRE, global, file, self);
});
fn && fn();
};
Expand Down
8 changes: 4 additions & 4 deletions lib/reporters/base.js
Expand Up @@ -12,8 +12,8 @@ var milliseconds = require('ms');
var utils = require('../utils');
var supportsColor = process.browser ? null : require('supports-color');
var constants = require('../runner').constants;
var RUNNER_EVENT_PASS = constants.RUNNER_EVENT_PASS;
var RUNNER_EVENT_FAIL = constants.RUNNER_EVENT_FAIL;
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;

/**
* Expose `Base`.
Expand Down Expand Up @@ -277,7 +277,7 @@ function Base(runner) {
this.stats = runner.stats; // assigned so Reporters keep a closer reference
this.runner = runner;

runner.on(RUNNER_EVENT_PASS, function(test) {
runner.on(EVENT_TEST_PASS, function(test) {
if (test.duration > test.slow()) {
test.speed = 'slow';
} else if (test.duration > test.slow() / 2) {
Expand All @@ -287,7 +287,7 @@ function Base(runner) {
}
});

runner.on(RUNNER_EVENT_FAIL, function(test, err) {
runner.on(EVENT_TEST_FAIL, function(test, err) {
if (showDiff(err)) {
stringifyDiffObjs(err);
}
Expand Down
16 changes: 8 additions & 8 deletions lib/reporters/doc.js
Expand Up @@ -9,10 +9,10 @@
var Base = require('./base');
var utils = require('../utils');
var constants = require('../runner').constants;
var RUNNER_EVENT_PASS = constants.RUNNER_EVENT_PASS;
var RUNNER_EVENT_FAIL = constants.RUNNER_EVENT_FAIL;
var RUNNER_EVENT_SUITE_BEGIN = constants.RUNNER_EVENT_SUITE_BEGIN;
var RUNNER_EVENT_SUITE_END = constants.RUNNER_EVENT_SUITE_END;
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN;
var EVENT_SUITE_END = constants.EVENT_SUITE_END;

/**
* Expose `Doc`.
Expand All @@ -38,7 +38,7 @@ function Doc(runner) {
return Array(indents).join(' ');
}

runner.on(RUNNER_EVENT_SUITE_BEGIN, function(suite) {
runner.on(EVENT_SUITE_BEGIN, function(suite) {
if (suite.root) {
return;
}
Expand All @@ -49,7 +49,7 @@ function Doc(runner) {
console.log('%s<dl>', indent());
});

runner.on(RUNNER_EVENT_SUITE_END, function(suite) {
runner.on(EVENT_SUITE_END, function(suite) {
if (suite.root) {
return;
}
Expand All @@ -59,13 +59,13 @@ function Doc(runner) {
--indents;
});

runner.on(RUNNER_EVENT_PASS, function(test) {
runner.on(EVENT_TEST_PASS, function(test) {
console.log('%s <dt>%s</dt>', indent(), utils.escape(test.title));
var code = utils.escape(utils.clean(test.body));
console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
});

runner.on(RUNNER_EVENT_FAIL, function(test, err) {
runner.on(EVENT_TEST_FAIL, function(test, err) {
console.log(
'%s <dt class="error">%s</dt>',
indent(),
Expand Down

0 comments on commit 9642e60

Please sign in to comment.