Parameterised tests for Jest that enable running the same test multiple times with different data sets using arrays or tagged template literals
npx @tessl/cli install tessl/npm-jest-each@30.1.00
# jest-each
1
2
jest-each is a parameterized testing library that enables running the same test multiple times with different data sets. It provides two main approaches: array-based parameterization and tagged template literal syntax with readable table formatting. The library integrates seamlessly with all Jest test functions and modifiers.
3
4
## Package Information
5
6
- **Package Name**: jest-each
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install jest-each`
10
11
## Core Imports
12
13
```typescript
14
import each from "jest-each";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const each = require("jest-each").default;
21
```
22
23
Named imports:
24
25
```typescript
26
import each, { bind } from "jest-each";
27
```
28
29
## Basic Usage
30
31
### Array Format
32
33
```typescript
34
import each from "jest-each";
35
36
// Array of arrays
37
each([
38
[1, 2, 3],
39
[4, 5, 9],
40
[7, 8, 15]
41
]).test('adds %i + %i to equal %i', (a, b, expected) => {
42
expect(a + b).toBe(expected);
43
});
44
45
// Array of objects
46
each([
47
{ name: 'John', age: 25 },
48
{ name: 'Jane', age: 30 }
49
]).test('user $name is $age years old', ({ name, age }) => {
50
expect(typeof name).toBe('string');
51
expect(typeof age).toBe('number');
52
});
53
```
54
55
### Template Literal Format
56
57
```typescript
58
each`
59
a | b | expected
60
${1} | ${2} | ${3}
61
${4} | ${5} | ${9}
62
${7} | ${8} | ${15}
63
`.test('adds $a + $b to equal $expected', ({ a, b, expected }) => {
64
expect(a + b).toBe(expected);
65
});
66
```
67
68
## Capabilities
69
70
### Main Each Function
71
72
Creates parameterized test functions that work with all Jest test methods and modifiers.
73
74
```typescript { .api }
75
/**
76
* Main function to create parameterized tests using arrays or template literals
77
* @param table - Test data as array of arrays, array of objects, or template literal
78
* @param data - Additional template data when using template literals
79
* @returns Object with Jest test methods (test, it, describe, etc.)
80
*/
81
function each(table: EachTable, ...data: TemplateData): {
82
test: EachTestFunction;
83
it: EachTestFunction;
84
describe: EachDescribeFunction;
85
xit: EachTestFunction;
86
fit: EachTestFunction;
87
xtest: EachTestFunction;
88
fdescribe: EachDescribeFunction;
89
xdescribe: EachDescribeFunction;
90
};
91
92
type EachTable = ArrayTable | TemplateTable;
93
type ArrayTable = Table | Row;
94
type Table = ReadonlyArray<Row>;
95
type Row = ReadonlyArray<unknown>;
96
type TemplateTable = TemplateStringsArray;
97
type TemplateData = ReadonlyArray<unknown>;
98
```
99
100
### With Global Context
101
102
Creates each function bound to a specific global context for custom Jest environments.
103
104
```typescript { .api }
105
/**
106
* Creates each function bound to specific global context
107
* @param g - Global Jest context object
108
* @returns Function that accepts table and returns test methods
109
*/
110
each.withGlobal: (g: Global) => (table: EachTable, ...data: TemplateData) => ReturnType<typeof each>;
111
112
interface Global {
113
test: TestFunction;
114
it: TestFunction;
115
describe: DescribeFunction;
116
xit: TestFunction;
117
fit: TestFunction;
118
xtest: TestFunction;
119
fdescribe: DescribeFunction;
120
xdescribe: DescribeFunction;
121
}
122
```
123
124
### Test Function Interface
125
126
All returned test functions support Jest's standard interface with modifiers.
127
128
```typescript { .api }
129
interface EachTestFunction {
130
/**
131
* Creates a parameterized test
132
* @param title - Test title with optional placeholders
133
* @param testFn - Test function receiving parameters from data table
134
* @param timeout - Optional timeout in milliseconds
135
*/
136
(title: string, testFn: EachTestFn<TestFn>, timeout?: number): void;
137
138
/** Run only this test */
139
only: EachTestFunction;
140
141
/** Skip this test */
142
skip: EachTestFunction;
143
144
/** Concurrent test execution */
145
concurrent: EachConcurrentTestFunction;
146
}
147
148
interface EachConcurrentTestFunction {
149
(title: string, testFn: EachTestFn<ConcurrentTestFn>, timeout?: number): void;
150
only: EachConcurrentTestFunction;
151
skip: EachConcurrentTestFunction;
152
}
153
154
interface EachDescribeFunction {
155
/**
156
* Creates a parameterized describe block
157
* @param title - Describe title with optional placeholders
158
* @param suiteFn - Suite function receiving parameters from data table
159
* @param timeout - Optional timeout in milliseconds
160
*/
161
(title: string, suiteFn: EachTestFn<BlockFn>, timeout?: number): void;
162
163
/** Run only this describe block */
164
only: EachDescribeFunction;
165
166
/** Skip this describe block */
167
skip: EachDescribeFunction;
168
}
169
170
type EachTestFn<T extends TestCallback> = (...args: ReadonlyArray<any>) => ReturnType<T>;
171
```
172
173
### Bind Function (Advanced)
174
175
Core binding function for creating custom parameterized test functions.
176
177
```typescript { .api }
178
/**
179
* Creates parameterized test functions by binding to Jest global methods
180
* @param cb - Global Jest callback function to bind to
181
* @param supportsDone - Whether the callback supports done callback (default: true)
182
* @param needsEachError - Whether to pass error context (default: false)
183
* @returns Function that accepts table data and returns bound test function
184
*/
185
function bind<EachCallback extends TestCallback>(
186
cb: GlobalCallback,
187
supportsDone?: boolean,
188
needsEachError?: boolean
189
): EachTestFn<any>;
190
191
type GlobalCallback = (
192
testName: string,
193
fn: ConcurrentTestFn,
194
timeout?: number,
195
eachError?: Error
196
) => void;
197
198
type TestCallback = BlockFn | TestFn | ConcurrentTestFn;
199
```
200
201
## Title Formatting and Interpolation
202
203
### Printf-Style Placeholders
204
205
jest-each supports printf-style placeholders for automatic value formatting in test titles:
206
207
- `%s` - String formatting
208
- `%d`, `%i` - Integer formatting
209
- `%f` - Float formatting
210
- `%j` - JSON formatting
211
- `%o`, `%O` - Object formatting
212
- `%p` - Pretty-print formatting (with depth control)
213
- `%#` - Zero-based index placeholder
214
- `%$` - One-based index placeholder
215
216
```typescript
217
each([
218
[1, 2, 3],
219
[4, 5, 9]
220
]).test('test %# adds %i + %i to equal %i', (a, b, expected) => {
221
expect(a + b).toBe(expected);
222
});
223
// Results in: "test 0 adds 1 + 2 to equal 3", "test 1 adds 4 + 5 to equal 9"
224
```
225
226
### Template Variable Interpolation
227
228
When using template literals or object arrays, variables can be interpolated using `$variable` syntax:
229
230
```typescript
231
each`
232
name | age | status
233
${'John'} | ${25} | ${'active'}
234
${'Jane'} | ${30} | ${'inactive'}
235
`.test('user $name (age $age) is $status', ({ name, age, status }) => {
236
expect(typeof name).toBe('string');
237
});
238
```
239
240
### Object Property Access
241
242
Template variables support deep property access using dot notation:
243
244
```typescript
245
each([
246
{ user: { profile: { name: 'John' }, age: 25 } },
247
{ user: { profile: { name: 'Jane' }, age: 30 } }
248
]).test('user $user.profile.name is $user.age years old', ({ user }) => {
249
expect(user).toBeDefined();
250
});
251
```
252
253
## Data Table Formats
254
255
### Array of Arrays
256
257
Most basic format for simple parameter lists:
258
259
```typescript
260
each([
261
[1, 2, 3], // First test case
262
[4, 5, 9], // Second test case
263
[7, 8, 15] // Third test case
264
]).test('adds %i + %i to equal %i', (a, b, expected) => {
265
expect(a + b).toBe(expected);
266
});
267
```
268
269
### Array of Objects
270
271
Provides named parameters for better readability:
272
273
```typescript
274
each([
275
{ input: 'hello', expected: 5 },
276
{ input: 'world', expected: 5 },
277
{ input: '', expected: 0 }
278
]).test('$input has length $expected', ({ input, expected }) => {
279
expect(input.length).toBe(expected);
280
});
281
```
282
283
### Single Column Arrays
284
285
For tests with single parameters:
286
287
```typescript
288
each([1, 2, 3, 4, 5]).test('number %i is defined', (num) => {
289
expect(num).toBeDefined();
290
expect(typeof num).toBe('number');
291
});
292
```
293
294
### Template Literals
295
296
Tabular format with column headers for maximum readability:
297
298
```typescript
299
each`
300
operation | a | b | expected
301
${'add'} | ${1} | ${2} | ${3}
302
${'sub'} | ${5} | ${3} | ${2}
303
${'mul'} | ${3} | ${4} | ${12}
304
`.test('$operation: $a and $b equals $expected', ({ operation, a, b, expected }) => {
305
switch (operation) {
306
case 'add':
307
expect(a + b).toBe(expected);
308
break;
309
case 'sub':
310
expect(a - b).toBe(expected);
311
break;
312
case 'mul':
313
expect(a * b).toBe(expected);
314
break;
315
}
316
});
317
```
318
319
## Jest Integration
320
321
### Test Methods
322
323
All Jest test methods are supported:
324
325
```typescript
326
each(testData).test('test title', testFn); // Standard test
327
each(testData).test.only('test title', testFn); // Run only this test
328
each(testData).test.skip('test title', testFn); // Skip this test
329
each(testData).test.concurrent('test title', testFn); // Concurrent execution
330
331
each(testData).it('test title', testFn); // Alias for test
332
each(testData).xit('test title', testFn); // Skip test (alias)
333
each(testData).fit('test title', testFn); // Focus test (alias)
334
each(testData).xtest('test title', testFn); // Skip test (alias)
335
```
336
337
### Describe Blocks
338
339
Parameterized describe blocks for grouping related tests:
340
341
```typescript
342
each([
343
{ type: 'user', endpoint: '/users' },
344
{ type: 'post', endpoint: '/posts' }
345
]).describe('$type API', ({ type, endpoint }) => {
346
test('should fetch all items', async () => {
347
const response = await api.get(endpoint);
348
expect(response.status).toBe(200);
349
});
350
351
test('should create new item', async () => {
352
const response = await api.post(endpoint, { name: 'Test' });
353
expect(response.status).toBe(201);
354
});
355
});
356
```
357
358
### Concurrent Test Execution
359
360
Support for concurrent test execution with proper typing:
361
362
```typescript
363
each([
364
{ url: '/api/users/1' },
365
{ url: '/api/users/2' },
366
{ url: '/api/users/3' }
367
]).test.concurrent('fetches data from $url', async ({ url }) => {
368
const response = await fetch(url);
369
expect(response.status).toBe(200);
370
});
371
```
372
373
### Done Callback Support
374
375
Automatic detection and support for Jest's done callback:
376
377
```typescript
378
each([
379
{ delay: 100 },
380
{ delay: 200 }
381
]).test('async test with $delay ms delay', ({ delay }, done) => {
382
setTimeout(() => {
383
expect(delay).toBeGreaterThan(0);
384
done();
385
}, delay);
386
});
387
```
388
389
## Error Handling and Validation
390
391
### Table Validation
392
393
Comprehensive validation with descriptive error messages:
394
395
```typescript
396
// Invalid: empty array
397
each([]).test('title', () => {}); // Throws: "Error: .each called with an empty Array of table data."
398
399
// Invalid: tagged template with no data
400
each``.test('title', () => {}); // Throws: "Error: .each called with an empty Tagged Template Literal of table data."
401
402
// Invalid: not an array or template literal
403
each("invalid").test('title', () => {}); // Throws: ".each must be called with an Array or Tagged Template Literal."
404
```
405
406
### Template Table Validation
407
408
Validation for template literal format and argument count:
409
410
```typescript
411
// Invalid: mismatched arguments
412
each`
413
a | b
414
${1} | ${2}
415
${3} // Missing second argument
416
`.test('title', () => {}); // Throws error with missing argument details
417
```
418
419
## Types
420
421
```typescript { .api }
422
// Core types for data tables
423
type Col = unknown;
424
type Row = ReadonlyArray<Col>;
425
type Table = ReadonlyArray<Row>;
426
type ArrayTable = Table | Row;
427
type TemplateTable = TemplateStringsArray;
428
type TemplateData = ReadonlyArray<unknown>;
429
type EachTable = ArrayTable | TemplateTable;
430
431
// Test function types
432
type ValidTestReturnValues = void | undefined;
433
type TestReturnValue = ValidTestReturnValues | Promise<unknown>;
434
type DoneFn = (reason?: string | Error) => void;
435
436
type TestFn = PromiseReturningTestFn | GeneratorReturningTestFn | DoneTakingTestFn;
437
type PromiseReturningTestFn = (this: TestContext) => TestReturnValue;
438
type DoneTakingTestFn = (this: TestContext, done: DoneFn) => ValidTestReturnValues;
439
type ConcurrentTestFn = () => Promise<unknown>;
440
type BlockFn = () => void;
441
442
// Generic test function type for parameterized tests
443
type EachTestFn<EachCallback extends TestCallback> = (
444
...args: ReadonlyArray<any>
445
) => ReturnType<EachCallback>;
446
447
// Template and interpolation types
448
type Template = Record<string, unknown>;
449
type Templates = Array<Template>;
450
type Headings = Array<string>;
451
452
// Internal test case representation
453
type EachTests = ReadonlyArray<{
454
title: string;
455
arguments: ReadonlyArray<unknown>;
456
}>;
457
```