Skip to content

Commit 6654704

Browse files
TG199mark-wiemer
andauthored
docs: migrate third party UIs wiki page to docs (#5434)
Co-authored-by: Mark Wiemer <[email protected]>
1 parent 55fd22a commit 6654704

File tree

4 files changed

+464
-0
lines changed

4 files changed

+464
-0
lines changed

docs-next/astro.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ export default defineConfig({
149149
label: "Third party reporters",
150150
slug: "explainers/third-party-reporters",
151151
},
152+
{
153+
label: "Third party UIs",
154+
slug: "explainers/third-party-uis",
155+
},
152156
],
153157
label: "Explainers",
154158
},
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
---
2+
description: Create custom Mocha UIs.
3+
title: Third party UIs
4+
---
5+
6+
Mocha allows you to define custom UIs with the same power as those readily available. When defining UIs locally, you need to `--require` the file in question, along with specifying the `--ui`. However, when published as an npm module, you can use the ui flag as you would any other interface, such as bdd, tdd, etc.
7+
8+
Creating a Third Party UI involves listening for the `pre-require` event emitted by the root suite. It passes a Mocha context object on which you can install the various functions necessary for the UI. Your UI will need to manage the organization and nesting of suites and tests itself, along with marking suites as skipped/pending if this is behavior you chose to expose.
9+
10+
In this first brief example, we'll create an interface with only a single function: `test`
11+
12+
``` javascript
13+
var Mocha = require('mocha');
14+
Suite = require('mocha/lib/suite'),
15+
Test = require('mocha/lib/test');
16+
17+
/**
18+
* A simple UI that only exposes a single function: test
19+
*/
20+
module.exports = Mocha.interfaces['simple-ui'] = function(suite) {
21+
suite.on('pre-require', function(context, file, mocha) {
22+
var common = require('mocha/lib/interfaces/common')([suite], context);
23+
24+
context.run = mocha.options.delay && common.runWithSuite(suite);
25+
26+
/**
27+
* Describes a specification or test-case with the given `title`
28+
* and callback `fn` acting as a thunk.
29+
*/
30+
context.test = function(title, fn) {
31+
var test = new Test(title, fn);
32+
test.file = file;
33+
suite.addTest(test);
34+
35+
return test;
36+
};
37+
});
38+
};
39+
```
40+
41+
``` javascript
42+
test('pass', function() {
43+
// pass
44+
});
45+
46+
test('fail', function() {
47+
throw new Error('oops!');
48+
});
49+
```
50+
51+
```
52+
$ # Install dependencies
53+
$ npm install mocha
54+
$ mocha --require ./simple-ui.js --ui simple-ui test.js
55+
56+
57+
✓ pass
58+
1) fail
59+
60+
1 passing (4ms)
61+
1 failing
62+
63+
1) fail:
64+
Error: oops!
65+
at Context.<anonymous> (/Users/danielstjules/Desktop/example/test.js:6:9)
66+
...
67+
```
68+
69+
In this next example, we'll be extending the [TDD interface](https://github.com/mochajs/mocha/blob/master/lib/interfaces/tdd.js) with a comment function that simply prints the passed text. That is, `comment('This is a comment');` would print the string.
70+
71+
``` javascript
72+
var Mocha = require('mocha');
73+
Suite = require('mocha/lib/suite'),
74+
Test = require('mocha/lib/test'),
75+
escapeRe = require('escape-string-regexp');
76+
77+
/**
78+
* This example is identical to the TDD interface, but with the addition of a
79+
* "comment" function:
80+
* https://github.com/mochajs/mocha/blob/master/lib/interfaces/tdd.js
81+
*/
82+
module.exports = Mocha.interfaces['example-ui'] = function(suite) {
83+
var suites = [suite];
84+
85+
suite.on('pre-require', function(context, file, mocha) {
86+
var common = require('mocha/lib/interfaces/common')(suites, context);
87+
88+
/**
89+
* Use all existing hook logic common to UIs. Common logic can be found in
90+
* https://github.com/mochajs/mocha/blob/master/lib/interfaces/common.js
91+
*/
92+
context.setup = common.beforeEach;
93+
context.teardown = common.afterEach;
94+
context.suiteSetup = common.before;
95+
context.suiteTeardown = common.after;
96+
context.run = mocha.options.delay && common.runWithSuite(suite);
97+
98+
/**
99+
* Our addition. A comment function that creates a pending test and
100+
* adds an isComment attribute to the test for identification by a
101+
* third party, custom reporter. The comment will be printed just like
102+
* a pending test. But any custom reporter could check for the isComment
103+
* attribute on a test to modify its presentation.
104+
*/
105+
context.comment = function(title) {
106+
var suite, comment;
107+
108+
suite = suites[0];
109+
comment = new Test(title, null);
110+
111+
comment.pending = true;
112+
comment.isComment = true;
113+
comment.file = file;
114+
suite.addTest(comment);
115+
116+
return comment;
117+
};
118+
119+
// Remaining logic is from the tdd interface, but is necessary for a
120+
// complete example
121+
// https://github.com/mochajs/mocha/blob/master/lib/interfaces/tdd.js
122+
123+
/**
124+
* The default TDD suite functionality. Describes a suite with the
125+
* given title and callback, fn`, which may contain nested suites
126+
* and/or tests.
127+
*/
128+
context.suite = function(title, fn) {
129+
var suite = Suite.create(suites[0], title);
130+
131+
suite.file = file;
132+
suites.unshift(suite);
133+
fn.call(suite);
134+
suites.shift();
135+
136+
return suite;
137+
};
138+
139+
/**
140+
* The default TDD pending suite functionality.
141+
*/
142+
context.suite.skip = function(title, fn) {
143+
var suite = Suite.create(suites[0], title);
144+
145+
suite.pending = true;
146+
suites.unshift(suite);
147+
fn.call(suite);
148+
suites.shift();
149+
};
150+
151+
/**
152+
* Default TDD exclusive test-case logic.
153+
*/
154+
context.suite.only = function(title, fn) {
155+
var suite = context.suite(title, fn);
156+
mocha.grep(suite.fullTitle());
157+
};
158+
159+
/**
160+
* Default TDD test-case logic. Describes a specification or test-case
161+
* with the given `title` and callback `fn` acting as a thunk.
162+
*/
163+
context.test = function(title, fn) {
164+
var suite, test;
165+
166+
suite = suites[0];
167+
if (suite.pending) fn = null;
168+
test = new Test(title, fn);
169+
test.file = file;
170+
suite.addTest(test);
171+
172+
return test;
173+
};
174+
175+
/**
176+
* Exclusive test-case.
177+
*/
178+
context.test.only = function(title, fn) {
179+
var test, reString;
180+
181+
test = context.test(title, fn);
182+
reString = '^' + escapeRe(test.fullTitle()) + '$';
183+
mocha.grep(new RegExp(reString));
184+
};
185+
186+
/**
187+
* Defines the skip behavior for a test.
188+
*/
189+
context.test.skip = common.test.skip;
190+
});
191+
};
192+
```
193+
194+
``` javascript
195+
suite('Example', function() {
196+
comment("Here's the addition we made to the UI");
197+
198+
test('passing test', function() {
199+
// Pass
200+
});
201+
202+
test('failing test', function() {
203+
throw new Error('it failed!');
204+
});
205+
});
206+
```
207+
208+
```
209+
$ # install both dependencies
210+
$ npm install mocha escape-string-regexp
211+
$ # Run our example
212+
$ mocha --require ./example-ui.js --ui example-ui test.js
213+
214+
215+
Example
216+
- Here's the addition we made to the UI
217+
✓ passing test
218+
1) failing test
219+
220+
221+
1 passing (5ms)
222+
1 pending
223+
1 failing
224+
225+
1) Example failing test:
226+
Error: it failed!
227+
at Context.<anonymous> (/Users/danielstjules/Desktop/example/test.js:11:11)
228+
at callFn (/Users/danielstjules/Desktop/example/node_modules/mocha/lib/runnable.js:266:21)
229+
at Test.Runnable.run
230+
....
231+
```

docs/api-tutorials/jsdoc.tutorials.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@
1919
},
2020
"third-party-reporters": {
2121
"title": "Third party reporters"
22+
},
23+
"third-party-uis": {
24+
"title": "Third party UIs"
2225
}
2326
}

0 commit comments

Comments
 (0)