1 | <div align="center">
|
2 | <h1>jest-each</h1>
|
3 | Jest Parameterised Testing
|
4 | </div>
|
5 |
|
6 | <hr />
|
7 |
|
8 | [![version](https://img.shields.io/npm/v/jest-each.svg?style=flat-square)](https://www.npmjs.com/package/jest-each) [![downloads](https://img.shields.io/npm/dm/jest-each.svg?style=flat-square)](http://npm-stat.com/charts.html?package=jest-each&from=2017-03-21) [![MIT License](https://img.shields.io/npm/l/jest-each.svg?style=flat-square)](https://github.com/facebook/jest/blob/master/LICENSE)
|
9 |
|
10 | A parameterised testing library for [Jest](https://jestjs.io/) inspired by [mocha-each](https://github.com/ryym/mocha-each).
|
11 |
|
12 | jest-each allows you to provide multiple arguments to your `test`/`describe` which results in the test/suite being run once per row of parameters.
|
13 |
|
14 | ## Features
|
15 |
|
16 | - `.test` to runs multiple tests with parameterised data
|
17 | - Also under the alias: `.it`
|
18 | - `.test.only` to only run the parameterised tests
|
19 | - Also under the aliases: `.it.only` or `.fit`
|
20 | - `.test.skip` to skip the parameterised tests
|
21 | - Also under the aliases: `.it.skip` or `.xit` or `.xtest`
|
22 | - `.test.concurrent`
|
23 | - Also under the alias: `.it.concurrent`
|
24 | - `.test.concurrent.only`
|
25 | - Also under the alias: `.it.concurrent.only`
|
26 | - `.test.concurrent.skip`
|
27 | - Also under the alias: `.it.concurrent.skip`
|
28 | - `.describe` to runs test suites with parameterised data
|
29 | - `.describe.only` to only run the parameterised suite of tests
|
30 | - Also under the aliases: `.fdescribe`
|
31 | - `.describe.skip` to skip the parameterised suite of tests
|
32 | - Also under the aliases: `.xdescribe`
|
33 | - Asynchronous tests with `done`
|
34 | - Unique test titles with [`printf` formatting](https://nodejs.org/api/util.html#util_util_format_format_args):
|
35 | - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format).
|
36 | - `%s`- String.
|
37 | - `%d`- Number.
|
38 | - `%i` - Integer.
|
39 | - `%f` - Floating point value.
|
40 | - `%j` - JSON.
|
41 | - `%o` - Object.
|
42 | - `%#` - Index of the test case.
|
43 | - `%%` - single percent sign ('%'). This does not consume an argument.
|
44 | - Unique test titles by injecting properties of test case object
|
45 | - 🖖 Spock like data tables with [Tagged Template Literals](#tagged-template-literal-of-rows)
|
46 |
|
47 | ---
|
48 |
|
49 | - [Demo](#demo)
|
50 | - [Installation](#installation)
|
51 | - [Importing](#importing)
|
52 | - APIs
|
53 | - [Array of Rows](#array-of-rows)
|
54 | - [Usage](#usage)
|
55 | - [Tagged Template Literal of rows](#tagged-template-literal-of-rows)
|
56 | - [Usage](#usage-1)
|
57 |
|
58 | ## Demo
|
59 |
|
60 | #### Tests without jest-each
|
61 |
|
62 | ![Current jest tests](assets/default-demo.gif)
|
63 |
|
64 | #### Tests can be re-written with jest-each to:
|
65 |
|
66 | **`.test`**
|
67 |
|
68 | ![Current jest tests](assets/test-demo.gif)
|
69 |
|
70 | **`.test` with Tagged Template Literals**
|
71 |
|
72 | ![Current jest tests](assets/tagged-template-literal.gif)
|
73 |
|
74 | **`.describe`**
|
75 |
|
76 | ![Current jest tests](assets/describe-demo.gif)
|
77 |
|
78 | ## Installation
|
79 |
|
80 | `npm i --save-dev jest-each`
|
81 |
|
82 | `yarn add -D jest-each`
|
83 |
|
84 | ## Importing
|
85 |
|
86 | jest-each is a default export so it can be imported with whatever name you like.
|
87 |
|
88 | ```js
|
89 | // es6
|
90 | import each from 'jest-each';
|
91 | ```
|
92 |
|
93 | ```js
|
94 | // es5
|
95 | const each = require('jest-each').default;
|
96 | ```
|
97 |
|
98 | ## Array of rows
|
99 |
|
100 | ### API
|
101 |
|
102 | #### `each([parameters]).test(name, testFn)`
|
103 |
|
104 | ##### `each`:
|
105 |
|
106 | - parameters: `Array` of Arrays with the arguments that are passed into the `testFn` for each row
|
107 | - _Note_ If you pass in a 1D array of primitives, internally it will be mapped to a table i.e. `[1, 2, 3] -> [[1], [2], [3]]`
|
108 |
|
109 | ##### `.test`:
|
110 |
|
111 | - name: `String` the title of the `test`.
|
112 | - Generate unique test titles by positionally injecting parameters with [`printf` formatting](https://nodejs.org/api/util.html#util_util_format_format_args):
|
113 | - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format).
|
114 | - `%s`- String.
|
115 | - `%d`- Number.
|
116 | - `%i` - Integer.
|
117 | - `%f` - Floating point value.
|
118 | - `%j` - JSON.
|
119 | - `%o` - Object.
|
120 | - `%#` - Index of the test case.
|
121 | - `%%` - single percent sign ('%'). This does not consume an argument.
|
122 | - Or generate unique test titles by injecting properties of test case object with `$variable`
|
123 | - To inject nested object values use you can supply a keyPath i.e. `$variable.path.to.value`
|
124 | - You can use `$#` to inject the index of the test case
|
125 | - You cannot use `$variable` with the `printf` formatting except for `%%`
|
126 | - testFn: `Function` the test logic, this is the function that will receive the parameters of each row as function arguments
|
127 |
|
128 | #### `each([parameters]).describe(name, suiteFn)`
|
129 |
|
130 | ##### `each`:
|
131 |
|
132 | - parameters: `Array` of Arrays with the arguments that are passed into the `suiteFn` for each row
|
133 | - _Note_ If you pass in a 1D array of primitives, internally it will be mapped to a table i.e. `[1, 2, 3] -> [[1], [2], [3]]`
|
134 |
|
135 | ##### `.describe`:
|
136 |
|
137 | - name: `String` the title of the `describe`
|
138 | - Generate unique test titles by positionally injecting parameters with [`printf` formatting](https://nodejs.org/api/util.html#util_util_format_format_args):
|
139 | - `%p` - [pretty-format](https://www.npmjs.com/package/pretty-format).
|
140 | - `%s`- String.
|
141 | - `%d`- Number.
|
142 | - `%i` - Integer.
|
143 | - `%f` - Floating point value.
|
144 | - `%j` - JSON.
|
145 | - `%o` - Object.
|
146 | - `%#` - Index of the test case.
|
147 | - `%%` - single percent sign ('%'). This does not consume an argument.
|
148 | - Or generate unique test titles by injecting properties of test case object with `$variable`
|
149 | - To inject nested object values use you can supply a keyPath i.e. `$variable.path.to.value`
|
150 | - You can use `$#` to inject the index of the test case
|
151 | - You cannot use `$variable` with the `printf` formatting except for `%%`
|
152 | - suiteFn: `Function` the suite of `test`/`it`s to be ran, this is the function that will receive the parameters in each row as function arguments
|
153 |
|
154 | ### Usage
|
155 |
|
156 | #### `.test(name, fn)`
|
157 |
|
158 | Alias: `.it(name, fn)`
|
159 |
|
160 | ```js
|
161 | each([
|
162 | [1, 1, 2],
|
163 | [1, 2, 3],
|
164 | [2, 1, 3],
|
165 | ]).test('returns the result of adding %d to %d', (a, b, expected) => {
|
166 | expect(a + b).toBe(expected);
|
167 | });
|
168 | ```
|
169 |
|
170 | ```js
|
171 | each([
|
172 | {a: 1, b: 1, expected: 2},
|
173 | {a: 1, b: 2, expected: 3},
|
174 | {a: 2, b: 1, expected: 3},
|
175 | ]).test('returns the result of adding $a to $b', ({a, b, expected}) => {
|
176 | expect(a + b).toBe(expected);
|
177 | });
|
178 | ```
|
179 |
|
180 | #### `.test.only(name, fn)`
|
181 |
|
182 | Aliases: `.it.only(name, fn)` or `.fit(name, fn)`
|
183 |
|
184 | ```js
|
185 | each([
|
186 | [1, 1, 2],
|
187 | [1, 2, 3],
|
188 | [2, 1, 3],
|
189 | ]).test.only('returns the result of adding %d to %d', (a, b, expected) => {
|
190 | expect(a + b).toBe(expected);
|
191 | });
|
192 | ```
|
193 |
|
194 | #### `.test.skip(name, fn)`
|
195 |
|
196 | Aliases: `.it.skip(name, fn)` or `.xit(name, fn)` or `.xtest(name, fn)`
|
197 |
|
198 | ```js
|
199 | each([
|
200 | [1, 1, 2],
|
201 | [1, 2, 3],
|
202 | [2, 1, 3],
|
203 | ]).test.skip('returns the result of adding %d to %d', (a, b, expected) => {
|
204 | expect(a + b).toBe(expected);
|
205 | });
|
206 | ```
|
207 |
|
208 | #### `.test.concurrent(name, fn)`
|
209 |
|
210 | Aliases: `.it.concurrent(name, fn)`
|
211 |
|
212 | ```js
|
213 | each([
|
214 | [1, 1, 2],
|
215 | [1, 2, 3],
|
216 | [2, 1, 3],
|
217 | ]).test.concurrent(
|
218 | 'returns the result of adding %d to %d',
|
219 | (a, b, expected) => {
|
220 | expect(a + b).toBe(expected);
|
221 | },
|
222 | );
|
223 | ```
|
224 |
|
225 | #### `.test.concurrent.only(name, fn)`
|
226 |
|
227 | Aliases: `.it.concurrent.only(name, fn)`
|
228 |
|
229 | ```js
|
230 | each([
|
231 | [1, 1, 2],
|
232 | [1, 2, 3],
|
233 | [2, 1, 3],
|
234 | ]).test.concurrent.only(
|
235 | 'returns the result of adding %d to %d',
|
236 | (a, b, expected) => {
|
237 | expect(a + b).toBe(expected);
|
238 | },
|
239 | );
|
240 | ```
|
241 |
|
242 | #### `.test.concurrent.skip(name, fn)`
|
243 |
|
244 | Aliases: `.it.concurrent.skip(name, fn)`
|
245 |
|
246 | ```js
|
247 | each([
|
248 | [1, 1, 2],
|
249 | [1, 2, 3],
|
250 | [2, 1, 3],
|
251 | ]).test.concurrent.skip(
|
252 | 'returns the result of adding %d to %d',
|
253 | (a, b, expected) => {
|
254 | expect(a + b).toBe(expected);
|
255 | },
|
256 | );
|
257 | ```
|
258 |
|
259 | #### Asynchronous `.test(name, fn(done))`
|
260 |
|
261 | Alias: `.it(name, fn(done))`
|
262 |
|
263 | ```js
|
264 | each([['hello'], ['mr'], ['spy']]).test(
|
265 | 'gives 007 secret message: %s',
|
266 | (str, done) => {
|
267 | const asynchronousSpy = message => {
|
268 | expect(message).toBe(str);
|
269 | done();
|
270 | };
|
271 | callSomeAsynchronousFunction(asynchronousSpy)(str);
|
272 | },
|
273 | );
|
274 | ```
|
275 |
|
276 | #### `.describe(name, fn)`
|
277 |
|
278 | ```js
|
279 | each([
|
280 | [1, 1, 2],
|
281 | [1, 2, 3],
|
282 | [2, 1, 3],
|
283 | ]).describe('.add(%d, %d)', (a, b, expected) => {
|
284 | test(`returns ${expected}`, () => {
|
285 | expect(a + b).toBe(expected);
|
286 | });
|
287 |
|
288 | test('does not mutate first arg', () => {
|
289 | a + b;
|
290 | expect(a).toBe(a);
|
291 | });
|
292 |
|
293 | test('does not mutate second arg', () => {
|
294 | a + b;
|
295 | expect(b).toBe(b);
|
296 | });
|
297 | });
|
298 | ```
|
299 |
|
300 | ```js
|
301 | each([
|
302 | {a: 1, b: 1, expected: 2},
|
303 | {a: 1, b: 2, expected: 3},
|
304 | {a: 2, b: 1, expected: 3},
|
305 | ]).describe('.add($a, $b)', ({a, b, expected}) => {
|
306 | test(`returns ${expected}`, () => {
|
307 | expect(a + b).toBe(expected);
|
308 | });
|
309 |
|
310 | test('does not mutate first arg', () => {
|
311 | a + b;
|
312 | expect(a).toBe(a);
|
313 | });
|
314 |
|
315 | test('does not mutate second arg', () => {
|
316 | a + b;
|
317 | expect(b).toBe(b);
|
318 | });
|
319 | });
|
320 | ```
|
321 |
|
322 | #### `.describe.only(name, fn)`
|
323 |
|
324 | Aliases: `.fdescribe(name, fn)`
|
325 |
|
326 | ```js
|
327 | each([
|
328 | [1, 1, 2],
|
329 | [1, 2, 3],
|
330 | [2, 1, 3],
|
331 | ]).describe.only('.add(%d, %d)', (a, b, expected) => {
|
332 | test(`returns ${expected}`, () => {
|
333 | expect(a + b).toBe(expected);
|
334 | });
|
335 | });
|
336 | ```
|
337 |
|
338 | #### `.describe.skip(name, fn)`
|
339 |
|
340 | Aliases: `.xdescribe(name, fn)`
|
341 |
|
342 | ```js
|
343 | each([
|
344 | [1, 1, 2],
|
345 | [1, 2, 3],
|
346 | [2, 1, 3],
|
347 | ]).describe.skip('.add(%d, %d)', (a, b, expected) => {
|
348 | test(`returns ${expected}`, () => {
|
349 | expect(a + b).toBe(expected);
|
350 | });
|
351 | });
|
352 | ```
|
353 |
|
354 | ---
|
355 |
|
356 | ## Tagged Template Literal of rows
|
357 |
|
358 | ### API
|
359 |
|
360 | #### `each[tagged template].test(name, suiteFn)`
|
361 |
|
362 | ```js
|
363 | each`
|
364 | a | b | expected
|
365 | ${1} | ${1} | ${2}
|
366 | ${1} | ${2} | ${3}
|
367 | ${2} | ${1} | ${3}
|
368 | `.test('returns $expected when adding $a to $b', ({a, b, expected}) => {
|
369 | expect(a + b).toBe(expected);
|
370 | });
|
371 | ```
|
372 |
|
373 | ##### `each` takes a tagged template string with:
|
374 |
|
375 | - First row of variable name column headings separated with `|`
|
376 | - One or more subsequent rows of data supplied as template literal expressions using `${value}` syntax.
|
377 |
|
378 | ##### `.test`:
|
379 |
|
380 | - name: `String` the title of the `test`, use `$variable` in the name string to inject test values into the test title from the tagged template expressions
|
381 | - To inject nested object values use you can supply a keyPath i.e. `$variable.path.to.value`
|
382 | - You can use `$#` to inject the index of the table row.
|
383 | - testFn: `Function` the test logic, this is the function that will receive the parameters of each row as function arguments
|
384 |
|
385 | #### `each[tagged template].describe(name, suiteFn)`
|
386 |
|
387 | ```js
|
388 | each`
|
389 | a | b | expected
|
390 | ${1} | ${1} | ${2}
|
391 | ${1} | ${2} | ${3}
|
392 | ${2} | ${1} | ${3}
|
393 | `.describe('$a + $b', ({a, b, expected}) => {
|
394 | test(`returns ${expected}`, () => {
|
395 | expect(a + b).toBe(expected);
|
396 | });
|
397 |
|
398 | test('does not mutate first arg', () => {
|
399 | a + b;
|
400 | expect(a).toBe(a);
|
401 | });
|
402 |
|
403 | test('does not mutate second arg', () => {
|
404 | a + b;
|
405 | expect(b).toBe(b);
|
406 | });
|
407 | });
|
408 | ```
|
409 |
|
410 | ##### `each` takes a tagged template string with:
|
411 |
|
412 | - First row of variable name column headings separated with `|`
|
413 | - One or more subsequent rows of data supplied as template literal expressions using `${value}` syntax.
|
414 |
|
415 | ##### `.describe`:
|
416 |
|
417 | - name: `String` the title of the `test`, use `$variable` in the name string to inject test values into the test title from the tagged template expressions
|
418 | - To inject nested object values use you can supply a keyPath i.e. `$variable.path.to.value`
|
419 | - suiteFn: `Function` the suite of `test`/`it`s to be ran, this is the function that will receive the parameters in each row as function arguments
|
420 |
|
421 | ### Usage
|
422 |
|
423 | #### `.test(name, fn)`
|
424 |
|
425 | Alias: `.it(name, fn)`
|
426 |
|
427 | ```js
|
428 | each`
|
429 | a | b | expected
|
430 | ${1} | ${1} | ${2}
|
431 | ${1} | ${2} | ${3}
|
432 | ${2} | ${1} | ${3}
|
433 | `.test('returns $expected when adding $a to $b', ({a, b, expected}) => {
|
434 | expect(a + b).toBe(expected);
|
435 | });
|
436 | ```
|
437 |
|
438 | #### `.test.only(name, fn)`
|
439 |
|
440 | Aliases: `.it.only(name, fn)` or `.fit(name, fn)`
|
441 |
|
442 | ```js
|
443 | each`
|
444 | a | b | expected
|
445 | ${1} | ${1} | ${2}
|
446 | ${1} | ${2} | ${3}
|
447 | ${2} | ${1} | ${3}
|
448 | `.test.only('returns $expected when adding $a to $b', ({a, b, expected}) => {
|
449 | expect(a + b).toBe(expected);
|
450 | });
|
451 | ```
|
452 |
|
453 | #### `.test.skip(name, fn)`
|
454 |
|
455 | Aliases: `.it.skip(name, fn)` or `.xit(name, fn)` or `.xtest(name, fn)`
|
456 |
|
457 | ```js
|
458 | each`
|
459 | a | b | expected
|
460 | ${1} | ${1} | ${2}
|
461 | ${1} | ${2} | ${3}
|
462 | ${2} | ${1} | ${3}
|
463 | `.test.skip('returns $expected when adding $a to $b', ({a, b, expected}) => {
|
464 | expect(a + b).toBe(expected);
|
465 | });
|
466 | ```
|
467 |
|
468 | #### Asynchronous `.test(name, fn(done))`
|
469 |
|
470 | Alias: `.it(name, fn(done))`
|
471 |
|
472 | ```js
|
473 | each`
|
474 | str
|
475 | ${'hello'}
|
476 | ${'mr'}
|
477 | ${'spy'}
|
478 | `.test('gives 007 secret message: $str', ({str}, done) => {
|
479 | const asynchronousSpy = message => {
|
480 | expect(message).toBe(str);
|
481 | done();
|
482 | };
|
483 | callSomeAsynchronousFunction(asynchronousSpy)(str);
|
484 | });
|
485 | ```
|
486 |
|
487 | #### `.describe(name, fn)`
|
488 |
|
489 | ```js
|
490 | each`
|
491 | a | b | expected
|
492 | ${1} | ${1} | ${2}
|
493 | ${1} | ${2} | ${3}
|
494 | ${2} | ${1} | ${3}
|
495 | `.describe('$a + $b', ({a, b, expected}) => {
|
496 | test(`returns ${expected}`, () => {
|
497 | expect(a + b).toBe(expected);
|
498 | });
|
499 |
|
500 | test('does not mutate first arg', () => {
|
501 | a + b;
|
502 | expect(a).toBe(a);
|
503 | });
|
504 |
|
505 | test('does not mutate second arg', () => {
|
506 | a + b;
|
507 | expect(b).toBe(b);
|
508 | });
|
509 | });
|
510 | ```
|
511 |
|
512 | #### `.describe.only(name, fn)`
|
513 |
|
514 | Aliases: `.fdescribe(name, fn)`
|
515 |
|
516 | ```js
|
517 | each`
|
518 | a | b | expected
|
519 | ${1} | ${1} | ${2}
|
520 | ${1} | ${2} | ${3}
|
521 | ${2} | ${1} | ${3}
|
522 | `.describe.only('$a + $b', ({a, b, expected}) => {
|
523 | test(`returns ${expected}`, () => {
|
524 | expect(a + b).toBe(expected);
|
525 | });
|
526 | });
|
527 | ```
|
528 |
|
529 | #### `.describe.skip(name, fn)`
|
530 |
|
531 | Aliases: `.xdescribe(name, fn)`
|
532 |
|
533 | ```js
|
534 | each`
|
535 | a | b | expected
|
536 | ${1} | ${1} | ${2}
|
537 | ${1} | ${2} | ${3}
|
538 | ${2} | ${1} | ${3}
|
539 | `.describe.skip('$a + $b', ({a, b, expected}) => {
|
540 | test(`returns ${expected}`, () => {
|
541 | expect(a + b).toBe(expected);
|
542 | });
|
543 | });
|
544 | ```
|
545 |
|
546 | ## License
|
547 |
|
548 | MIT
|