# jest-in-case turns one tester function into a table of named tests

> jest-in-case is a tiny MIT licensed Jest helper that runs the same tester function over an array of options or an object of keyed options, turning each entry into a separate named test, including support for only and skip. It is a single index.js file with no runtime dependencies, and its own tooling still points at Jest 23 and Flow.

**atlassian/jest-in-case** — Jest utility for creating variations of the same test

- Repository: https://github.com/atlassian/jest-in-case
- Website: http://thejameskyle.com/jest-in-case.html
- Stars: 1,062 · Forks: 21
- Language: JavaScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/atlassian-jest-in-case

## One tester function, called once per row

The whole idea of jest-in-case is a function that takes a title, a tester and a set of test cases, and then calls the tester once for every case, registering a separate Jest test for each one. The call signature is cases(title, tester, testCases). The tester receives the options for that row, and whatever it asserts becomes the body of that test.

The point is that the assertion logic is written once. In a conventional test file, a table of inputs usually turns into a forEach loop inside a single test, which means the first failure stops the run and the remaining rows are never tried. Here each row becomes its own test with its own name, so a failure tells you which row failed and the rows after it still run. That difference in failure reporting is the reason to reach for a helper at all.

The implementation is correspondingly small. The package publishes a single file, index.js, and the files array in the package metadata contains only index.js. There is no runtime dependency at all, which means the helper cannot break your install and cannot pull a second copy of Jest into your tree.

## Two shapes of test case, one of them implicit about names

The test cases argument accepts two forms, and the choice between them is about where the test name lives.

The first is an array of objects, each carrying a name property alongside the data. In that form the name is a field like any other, which means the same object holds both the label and the parameters:

```js
cases('add(augend, addend)', opts => {
  expect(add(opts.augend, opts.addend)).toBe(opts.total);
}, [
  { name: '1 + 1 = 2', augend: 1, addend: 1, total: 2 },
  { name: '2 + 1 = 3', augend: 2, addend: 1, total: 3 },
]);
```

The second form is an object of objects, where the key becomes the name and the value holds the data only. The keys are free text, so a case can be labelled the way a human would describe it, such as '1 - 1 = 0', with no name field in the payload. The practical difference is that the array form allows a name to be computed or omitted, while the object form makes the label part of the structure and keeps the data free of it.

## name, only and skip are reserved inside your case objects

Inside a test case you can put whatever properties you want, with three exceptions: name, only and skip. Each has a defined behaviour. The name is passed to test(name, fn) and becomes the name of the test in the report. When only is set to true the helper uses Jest's test.only function, and when skip is set to true it uses test.skip.

That reserved set is a real constraint on your data model. A function under test that legitimately takes a parameter called name, or a payload with a skip flag of its own, cannot use those keys here without the helper interpreting them. The escape is to rename the field in the test data, which is usually a one line change and occasionally a reminder that the parameter is doing two jobs.

The only and skip behaviour is the part that has no equivalent in a hand written loop, and it is worth knowing how it interacts with the rest of the file. Setting only to true on one row focuses that row, and the documentation is clear that name, only and skip are the three reserved keys, with the example showing the same reserved values across several rows. The cost of the feature is the reservation of two ordinary words in your data.

## The tester keeps Jest's async and done conventions

The tester function works like a function passed to Jest's test function, with one difference: it has a prepended argument holding the options for that row. Everything else behaves as you would expect, including asynchronous testers.

An async tester is passed straight through, so awaiting inside it is the normal pattern:

```js
cases('async functions', async opts => {
  let result = await somethingAsync(opts.input);
  expect(result).toEqual(opts.result);
}, {
  'test 1': { ... },
});
```

The done callback style also works, with the options in front of the callback:

```js
cases('done callback', (opts, done) => {
  somethingAsync(opts.input, result => {
    expect(result).toEqual(result);
    done();
  });
}, {
  'test 1': { ... },
});
```

So the helper does not impose an asynchronous style of its own, and a test file can mix a synchronous tester, an async tester and a done callback tester within the same suite. That matters more than it sounds: helpers that force a particular async convention end up fighting the rest of a codebase, and this one keeps the argument order compatible with what Jest already does.

## Install and write the first table test

The library is installed as a development dependency:

```bash
yarn add --dev jest-in-case
```

Then import it in the test file, either as an ES module import or with require:

```js
import cases from 'jest-in-case';
// or
const cases = require('jest-in-case');
```

A complete first case looks like this, with the title, the tester and the rows:

```js
cases('subtract(minuend, subtrahend)', opts => {
  expect(subtract(opts.minuend, opts.subtrahend)).toBe(opts.difference);
}, {
  '1 - 1 = 0': { minuend: 1, subtrahend: 1, difference: 0 },
  '2 - 1 = 1': { minuend: 2, subtrahend: 1, difference: 1 },
});
```

Run the suite with the usual Jest command, which is what the package's own test script does:

```bash
jest
```

The script defined in the package metadata is simply jest, and the development dependencies include jest ^23.6.0 and flow-bin ^0.53.1. You should see one test entry per row in the report, each carrying the name from the key or from the name field.

## A single file package with an old toolchain and no releases

The metadata describes a package that has not moved much. The version is 1.0.2, the engine requirement is node >=4, and the development dependencies still point at jest ^23.6.0 and flow-bin ^0.53.1 from the era when the package was first written. The package metadata also records the repository as Thinkmill/jest-in-case, while the code now lives in the Atlassian organisation, which is the sort of detail that tells you the project changed hands without being rewritten.

The repository itself is small and conventional: index.js, test.js, package.json, yarn.lock, LICENSE, README.md, a .flowconfig and a flow-typed/ directory. The presence of Flow configuration and typed definitions is worth noting for a project written in plain JavaScript, since it means the API shape was described in types for editors even though the shipped file is untyped JavaScript.

There are no GitHub releases, so the published version on the registry is the only version, and the repository is not archived with the last push on 2026-09-11. The licence is MIT, which means no obligations beyond keeping the notice, and a consumer's upgrade cost is effectively zero because the package is a single file with no dependencies and no configuration to migrate.

The honest assessment is that this is a finished utility rather than a growing library. The API is small enough to read in a minute, and the main risk in adopting it is not the code but the assumption it makes about the Jest version in your project, since it calls test.only and test.skip on your behalf.

## Conclusion

jest-in-case suits a Jest codebase with table driven tests where each row needs its own name and where a handful of rows have to be skipped or focused while debugging. It is the wrong tool for a project that already standardises on Jest's own table runner, and it is worth weighing against a plain forEach over the same array, since the library only earns its place by handling the naming and the only and skip cases for you. Verify first that your Jest version still accepts the test.only and test.skip calls it makes on your behalf, since the package pins jest ^23.6.0 as a development dependency and the repository has no published releases after version 1.0.2.

## FAQ

### What does jest-in-case do?

It is a Jest utility for creating variations of the same test. You call cases(title, tester, testCases) and it registers one named Jest test per entry, calling your tester function with that entry's options.

### How do I install jest-in-case?

Add it as a development dependency, for example yarn add --dev jest-in-case. The package ships a single index.js file and declares no runtime dependencies.

### Can jest-in-case skip or focus individual test cases?

Yes. A case with only set to true is run through Jest's test.only, and a case with skip set to true is run through test.skip. The name, only and skip keys are reserved and cannot be used as your own data fields.

### Does jest-in-case support async tests and the done callback?

Both are supported, because the tester behaves like a function passed to Jest's test function with the options prepended. An async tester can await inside, and a done callback tester receives opts before the callback.

## Sources

- [atlassian/jest-in-case on GitHub](https://github.com/atlassian/jest-in-case)
- [Issues](https://github.com/atlassian/jest-in-case/issues)
- [License: MIT](https://github.com/atlassian/jest-in-case/blob/master/LICENSE)
- [Project website](http://thejameskyle.com/jest-in-case.html)
- [README](https://github.com/atlassian/jest-in-case/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/atlassian-jest-in-case
