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