Skip to content

Commit c25f5c8

Browse files
committed
Docs: Improve callback docs and integrate js-reporters events spec
== Integrate js-reporters spec == Keep the link to the js-reporters project for now, but no longer rely on it for discovery. The spec was written for implementors, which makes it a suboptimal reading experience for end-users. It also suffered from numerous nullable properties that in practice with QUnit are either never null or always null. In our docs, I've left these off or explicitly described them in their reliable non-null form to avoid any doubt or confusion over how or why they behave a certain way. Note that as of js-reporters 2.0, much of the spec has been removed which QUnit currently still implements for compatibility (such as upfront recursively declared child suites). These have not been documented and will be removed in QUnit 3.0. Ref https://github.com/js-reporters/js-reporters/releases/tag/v2.0.0. The integration of the spec, rather than improving or creating a page in the js-reporters repo for end-users, is motivated by qunitjs/js-reporters#133, in which I conclude that for now it is a better use of our effort for any re-usable cross-framework reporters to consume TAP rather than tight runtime coupling. This also has the benefit of not pushing down the "serialize actual value" and "format a diff" problems down to end-consumers, which in practice are often done poorly or not at all. == Document unofficial `done` details == For `done()`, the `details.modules` property was added by commit 168b048 in QUnit 1.16 (2014) for internal use by HTML Reporter. It was never documented, however. It originally came with a `test` property as well, but that hasn't been in use since commit 43a3d87 in QUnit 2.7 (2018). Keep this for now since it's not adding delay or complexity, but I've left a note to remove this in QUnit 3.0. Document the rest as now-officially supported, with retroactive changelog. Also document the oft-overlooked caveat with the legacy assertion counts exposed from `QUnit.done()`. I believe the community has large moved away from using the data provided by this callback. For example, gruntjs/grunt-contrib-qunit#137. Recommend `on('runEnd')` instead.
1 parent 2e05357 commit c25f5c8

File tree

12 files changed

+215
-55
lines changed

12 files changed

+215
-55
lines changed

docs/assert/expect.md

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
layout: page-api
33
title: assert.expect()
4-
excerpt: Specify how many assertions are expected to run within a test.
4+
excerpt: Specify how many assertions are expected in a test.
55
groups:
66
- assert
77
redirect_from:
@@ -11,20 +11,61 @@ version_added: "1.0.0"
1111

1212
`expect( amount )`
1313

14-
Specify how many assertions are expected to run within a test.
14+
Specify how many assertions are expected in a test.
1515

1616
| name | description |
1717
|------|-------------|
18-
| `amount` | Number of assertions in this test. |
18+
| `amount` | Number of expected assertions in this test. |
1919

20-
To ensure that an explicit number of assertions are run within any test, use `assert.expect()` to register an expected count. If the number of assertions run does not match the expected count, the test will fail.
20+
This is most commonly used as `assert.expect(0)`, which indicates that a test may pass making any assertions. This means the test is only used to verify that the code to completion without any uncaught errors. This is is essentially the inverse of [`assert.throws()`](./throws.md).
21+
22+
It can also be used to explicitly require a certain number of assertions to be recorded in a given test. If afterwards the number of assertions does not match the expected count, the test will fail.
23+
24+
It is recommended to test asynchronous code with [`assert.step()`](./step.md) or [`assert.async()`](./async.md) instead.
2125

2226
## Examples
2327

24-
Establish an expected assertion count
28+
### Example: No assertions
29+
30+
A test without any assertions:
31+
32+
```js
33+
QUnit.test('example', function (assert) {
34+
assert.expect(0);
35+
36+
var android = new Robot();
37+
android.up(2);
38+
android.down(2);
39+
android.left();
40+
android.right();
41+
android.left();
42+
android.right();
43+
android.attack();
44+
android.jump();
45+
});
46+
```
47+
48+
### Example: Custom assert
49+
50+
If you use a generic assertion library that throws when an expectation is not met, you can use `assert.expect(0)` if there are no other assertions needed in the test.
51+
52+
```js
53+
QUnit.test('example', function (assert) {
54+
assert.expect(0);
55+
56+
var android = new Robot(database);
57+
android.run();
58+
59+
database.assertNoOpenConnections();
60+
});
61+
```
62+
63+
### Example: Explicit count
64+
65+
Require an explicit assertion count.
2566

2667
```js
27-
QUnit.test('a test', function (assert) {
68+
QUnit.test('example', function (assert) {
2869
assert.expect(2);
2970

3071
function calc (x, operation) {

docs/callbacks/QUnit.begin.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
layout: page-api
33
title: QUnit.begin()
4-
excerpt: Register a callback to fire whenever the test suite begins.
4+
excerpt: Register a callback to fire when the test run begins.
55
groups:
66
- callbacks
77
redirect_from:
@@ -11,21 +11,25 @@ version_added: "1.0.0"
1111

1212
`QUnit.begin( callback )`
1313

14-
Register a callback to fire whenever the test suite begins. The callback may be an async function, or a function that returns a promise, which will be waited for before the next callback is handled.
14+
Register a callback to fire when the test run begins. The callback may be an async function, or a function that returns a Promise, which will be waited for before the next callback is handled.
1515

1616
The callback will be called once, before QUnit runs any tests.
1717

1818
| parameter | description |
1919
|-----------|-------------|
20-
| callback (function) | Callback to execute. Provides a single argument with the callback Details object |
20+
| `callback` (function) | Callback to execute, called with a `details` object. |
2121

2222
### Details object
2323

24-
Passed to the callback:
25-
2624
| property | description |
2725
|-----------|-------------|
28-
| `totalTests` | The number of total tests in the test suite |
26+
| `totalTests` (number) | Number of registered tests |
27+
| `modules` (array) | List of registered modules,<br>as `{ name: string }` objects. |
28+
29+
## Changelog
30+
31+
| [QUnit 1.16](https://github.com/qunitjs/qunit/releases/tag/1.16.0) | Added `details.modules` property, containing `{ name: string }` objects.
32+
| [QUnit 1.15](https://github.com/qunitjs/qunit/releases/tag/1.15.0) | Added `details.totalTests` property.
2933

3034
## Examples
3135

docs/callbacks/QUnit.done.md

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
layout: page-api
33
title: QUnit.done()
4-
excerpt: Register a callback to fire whenever the test suite ends.
4+
excerpt: Register a callback to fire when the test run has ended.
55
groups:
66
- callbacks
77
redirect_from:
@@ -11,37 +11,42 @@ version_added: "1.0.0"
1111

1212
`QUnit.done( callback )`
1313

14-
Register a callback to fire whenever the test suite ends. The callback may be an async function, or a function that return a promise which will be waited for before the next callback is handled.
14+
Register a callback to fire when the test run has ended. The callback may be an async function, or a function that return a Promise which will be waited for before the next callback is handled.
1515

1616
| parameter | description |
1717
|-----------|-------------|
18-
| callback (function) | Callback to execute. Provides a single argument with the callback Details object |
18+
| `callback` (function) | Callback to execute, called with a `details` object:
1919

2020
### Details object
2121

22-
Passed to the callback:
23-
2422
| property | description |
2523
|-----------|-------------|
26-
| `failed` (number) | The number of failed assertions |
27-
| `passed` (number) | The number of passed assertions |
28-
| `total` (number) | The total number of assertions |
29-
| `runtime` (number) | The time in milliseconds it took tests to run from start to finish. |
24+
| `failed` (number) | Number of failed assertions |
25+
| `passed` (number) | Number of passed assertions |
26+
| `total` (number) | Total number of assertions |
27+
| `runtime` (number) | Duration of the test run in milliseconds |
3028

31-
## Examples
29+
<div class="note note--warning" markdown="1">
3230

33-
Register a callback that logs test results to the console.
31+
Use of `details` is __deprecated__ and it's recommended to use [`QUnit.on('runEnd')`](./QUnit.on.md) instead.
3432

35-
```js
36-
QUnit.done(details => {
37-
console.log(
38-
`Total: ${details.total} Failed: ${details.failed} ` +
39-
`Passed: ${details.passed} Runtime: ${details.runtime}`
40-
);
41-
});
42-
```
33+
Caveats:
34+
35+
* This callback reports the **internal assertion count**.
36+
37+
* The default browser and CLI interfaces for QUnit and other popular test frameworks, and most CI integrations, report the number of tests. Reporting the number _assertions_ may be confusing to developers.
38+
39+
* Failed assertions of a [`test.todo()`](../QUnit/test.todo.md) test are reported exactly as such. While rare, this means that a test run and all tests within it may be reported as passing, while internally there were some failed assertions. Unfortunately, this internal detail is exposed for compatibility reasons.
40+
41+
</div>
42+
43+
## Changelog
44+
45+
| [QUnit 2.2](https://github.com/qunitjs/qunit/releases/tag/2.2.0) | Deprecate `details` parameter in favour of `QUnit.on('runEnd')`.
46+
47+
## Examples
4348

44-
Using classic ES5 syntax:
49+
Register a callback that logs internal assertion counts.
4550

4651
```js
4752
QUnit.done(function (details) {

docs/callbacks/QUnit.log.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ version_added: "1.0.0"
1313

1414
Register a callback to fire whenever an assertion completes.
1515

16-
This is one of several callbacks QUnit provides. It's intended for continuous integration scenarios.
17-
1816
**NOTE: The QUnit.log() callback does not handle promises and MUST be synchronous.**
1917

2018
| parameter | description |

docs/callbacks/QUnit.on.md

Lines changed: 116 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,127 @@ version_added: "2.2.0"
99

1010
`QUnit.on( eventName, callback )`
1111

12-
Register a callback to fire whenever the specified event is emitted. Conforms to the [js-reporters standard](https://github.com/js-reporters/js-reporters).
12+
Register a callback to fire whenever a specified event is emitted.
1313

14-
Use this to listen for events related to the test suite's execution. Available event names and corresponding data payloads are defined in the [js-reporters specification](https://github.com/js-reporters/js-reporters).
14+
This API implements the [js-reporters CRI standard](https://github.com/js-reporters/js-reporters/blob/v2.1.0/spec/cri-draft.adoc), and is the primary interface for use by continuous integration plugins and other reporting software.
1515

16-
**NOTE: The QUnit.on() callback does not handle promises and MUST be synchronous.**
16+
| type | parameter | description
17+
|--|--|--
18+
| `string` | `eventName` | Name of an event.
19+
| `Function` | `callback`| A callback function.
1720

18-
| parameter | description |
19-
|-----------|-------------|
20-
| eventName (string) | The name of the event for which to execute the provided callback. |
21-
| callback (function) | Callback to execute. Receives a single argument representing the data for the event. |
21+
## The `runStart` event
2222

23-
## Examples
23+
The `runStart` event indicates the beginning of a test run. It is emitted exactly once, and before any other events.
2424

25-
Printing results of a test suite.
25+
| `Object` | `testCounts` | Aggregate counts about tests.
26+
| `number` | `testCounts.total` | Total number of registered tests.
27+
28+
```js
29+
QUnit.on('runStart', runStart => {
30+
console.log(`Test plan: ${runStart.testCounts.total}`);
31+
});
32+
```
33+
## The `suiteStart` event
34+
35+
The `suiteStart` event indicates the beginning of a module. It is eventually be followed by a corresponding `suiteEnd` event.
36+
37+
| `string` | `name` | Name of the module.
38+
| `Array<string>` | `fullName`| List of one or more strings, containing (in order) the names of any ancestor modules and the name of the current module.
39+
40+
```js
41+
QUnit.on('suiteStart', suiteStart => {
42+
console.log('suiteStart', suiteStart);
43+
// name: 'my module'
44+
// fullName: ['grandparent', 'parent', 'my module']
45+
});
46+
```
47+
48+
## The `suiteEnd` event
49+
50+
The `suiteEnd` event indicates the end of a module. It is emitted after its corresponding `suiteStart` event.
51+
52+
| `string` | `name` | Name of the module.
53+
| `Array<string>` | `fullName`| List of one or more strings, containing (in order) the names of any ancestor modules and the name of the current module.
54+
| `string` | `status` | Aggregate result of tests in this module, one of:<br>`failed`: at least one test has failed; <br>`passed`: there were no failing tests, which means there were only tests with a passed, skipped, or todo status.
55+
| `number` | `runtime` | Duration of the module in milliseconds.
56+
57+
```js
58+
QUnit.on('suiteEnd', suiteEnd => {
59+
console.log(suiteEnd);
60+
//
61+
});
62+
```
63+
64+
## The `testStart` event
65+
66+
The `testStart` event indicates the beginning of a test. It is eventually followed by a corresponding `testEnd` event.
67+
68+
| `string` | `name` | Name of the test.
69+
| `string|null` | `moduleName` | The module the test belongs to, or null for a global test.
70+
| `Array<string>` | `fullName` | List (in order) of the names of any ancestor modules and the name of the test itself.
71+
72+
```js
73+
QUnit.on('testStart', testStart => {
74+
console.log(testStart);
75+
// name: 'my test'
76+
// moduleName: 'my module'
77+
// fullName: ['parent', 'my module', 'my test']
78+
79+
// name: 'global test'
80+
// moduleName: null
81+
// fullName: ['global test']
82+
});
83+
```
84+
85+
## The `testEnd` event
86+
87+
The `testEnd` event indicates the end of a test. It is emitted after its corresponding `testStart` event.
88+
89+
Properties of a testEnd object:
90+
91+
| `string` | `name` | Name of the test.
92+
| `string|null` | `moduleName` | The module the test belongs to, or null for a global test.
93+
| `Array<string>` | `fullName` | List (in order) of the names of any ancestor modules and the name of the test itself.
94+
| `string` | `status` | Result of the test, one of:<br>`passed`: all assertions passed or no assertions found;<br>`failed`: at least one assertion failed or it is a [todo test](../QUnit/test.todo.md) that no longer has any failing assertions;<br>`skipped`: the test was intentionally not run; or<br>`todo`: the test is "todo" and still has a failing assertion.
95+
| `number` | `runtime` | Duration of the test in milliseconds.
96+
| `Array<FailedAssertion>` | `errors` | For tests with status `failed` or `todo`, there will be at least one failed assertion. However, the list may be empty if the status is `failed` due to a "todo" test having no failed assertions.<br><br>Note that all negative test outcome communicate their details in this manner. For example, timeouts, uncaught errors, and [global pollution](../config/noglobals.md) also synthesize a failed assertion.
97+
98+
Properties of a FailedAssertion object:
99+
100+
| `boolean` | `passed` | False for a failed assertion.
101+
| `string|undefined` | `message` | Description of what the assertion checked.
102+
| `any` | `actual` | The actual value passed to the assertion.
103+
| `any` | `expected` | The expected value passed to the assertion.
104+
| `string|undefined` | `stack` | Stack trace, may be undefined if the result came from an old web browsers.
105+
106+
```js
107+
QUnit.on('testEnd', testEnd => {
108+
if (testEnd.status === 'failed') {
109+
console.error('Failed! ' + testEnd.fullName.join(' > '));
110+
testEnd.errors.forEach(assertion => {
111+
console.error(assertion);
112+
// message: speedometer
113+
// actual: 75
114+
// expected: 88
115+
// stack: at dmc.test.js:12
116+
});
117+
}
118+
});
119+
```
120+
121+
## The `runEnd` event
122+
123+
The `runEnd` event indicates the end of a test run. It is emitted exactly once.
124+
125+
| `string` | `status` | Aggregate result of all tests, one of:<br>`failed`: at least one test failed or a global error ocurred;<br>`passed`: there were no failed tests, which means there were only tests with a passed, skipped, or todo status. If [`QUnit.config.failOnZeroTests`](../config/failOnZeroTests.md) is disabled, then the run may also pass if there were no tests.
126+
| `Object` | `testCounts` | Aggregate counts about tests:
127+
| `number` | `testCounts.passed` | Number of passed tests.
128+
| `number` | `testCounts.failed` | Number of failed tests.
129+
| `number` | `testCounts.skipped` | Number of skipped tests.
130+
| `number` | `testCounts.todo` | Number of todo tests.
131+
| `number` | `testCounts.total` | Total number of tests, equal to the sum of the above properties.
132+
| `number` | `runtime` | Total duration of the run in milliseconds.
26133

27134
```js
28135
QUnit.on('runEnd', runEnd => {

docs/extension/QUnit.dump.parse.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ layout: page-api
33
title: QUnit.dump.parse()
44
excerpt: Extensible data dumping and string serialization.
55
groups:
6-
- extension
6+
- extension
77
redirect_from:
88
- "/QUnit.dump.parse/"
99
- "/QUnit.jsDump.parse/"

docs/extension/QUnit.extend.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ layout: page-api
33
title: QUnit.extend()
44
excerpt: Copy the properties from one object into a target object.
55
groups:
6-
- extension
7-
- deprecated
6+
- extension
7+
- deprecated
88
redirect_from:
99
- "/config/QUnit.extend/"
1010
version_added: "1.0.0"
@@ -15,13 +15,13 @@ version_deprecated: "2.12.0"
1515

1616
Copy the properties defined by a mixin object into a target object.
1717

18+
<p class="note note--warning" markdown="1">This method is __deprecated__ and it's recommended to use [`Object.assign()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) instead.</p>
19+
1820
| name | description |
1921
|------|-------------|
2022
| `target` | An object whose properties are to be modified |
2123
| `mixin` | An object describing which properties should be modified |
2224

23-
<p class="note note--warning" markdown="1">This method is __deprecated__ and it's recommended to use [`Object.assign()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) instead.</p>
24-
2525
This method will modify the `target` object to contain the "own" properties defined by the `mixin`. If the `mixin` object specifies the value of any attribute as `undefined`, this property will instead be removed from the `target` object.
2626

2727
## Examples

docs/extension/QUnit.push.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ layout: page-api
33
title: QUnit.push()
44
excerpt: Report the result of a custom assertion.
55
groups:
6-
- extension
7-
- deprecated
6+
- extension
7+
- deprecated
88
redirect_from:
99
- "/config/QUnit.push/"
1010
version_added: "1.0.0"
@@ -15,15 +15,15 @@ version_deprecated: "2.1.0"
1515

1616
Report the result of a custom assertion.
1717

18+
<p class="note note--warning" markdown="1">This method is __deprecated__ and it's recommended to use [`pushResult`](../assert/pushResult.md) in the assertion context instead.</p>
19+
1820
| name | description |
1921
|------|-------------|
2022
| `result` (boolean) | Result of the assertion |
2123
| `actual` | Expression being tested |
2224
| `expected` | Known comparison value |
2325
| `message` (string) | A short description of the assertion |
2426

25-
<p class="note note--warning" markdown="1">This method is __deprecated__ and it's recommended to use [`pushResult`](../assert/pushResult.md) in the assertion context instead.</p>
26-
2727
`QUnit.push` reflects to the current running test, and it may leak assertions in asynchronous mode. Checkout [`assert.pushResult()`](../assert/pushResult.md) to set a proper custom assertion.
2828

2929
Invoking `QUnit.push` allows to create a readable expectation that is not defined by any of QUnit's built-in assertions.

0 commit comments

Comments
 (0)