Jest In Case

I don't know about you, but lots of times when I write even slightly generic functions, I have lots of test cases that are basically the same test over and over with different values.

Having to write them out manually one at a time is way too verbose, and not being able to scan through them quickly means you miss cases.

import {add} from "./math";

test("add(1, 1)", () => {
  let augend = 1;
  let addend = 1;
  expect(add(augend, addend)).toEqual(2);
});

test("add(2, 1)", () => {
  let augend = 2;
  let addend = 1;
  expect(add(augend, addend)).toEqual(3);
});

test("add(4, 1)", () => {
  let augend = 4;
  let addend = 1;
  expect(add(augend, addend)).toEqual(5);
});

// ugh... what do you mean I have to do work?

So what do you do? Maybe you just deal with it and copy and paste the same thing over and over. Or maybe you create a little helper:

import {add} from "./math";

function testCase(name, addend, augend, total) {
  test(name, () => {
    expect(add(addend, augend)).toEqual(total);
  });
}

testCase("add(1, 1)", 1, 1, 2);
testCase("add(2, 1)", 2, 1, 3);
testCase("add(3, 1)", 3, 1, 4);
testCase("add(4, 1)", 4, 1, 5);

Doing this immediately makes our test cases easier to scan. You can generate tons of test cases and it won't matter.

But now you have another problem: What if you want to focus on just one of those cases? Previously you could use Jest's test.only

test.only("add(1, 1)", () => {
  // ...
});

Introducing jest-in-case

In order to make it easier to work with tons of test cases like this you can now use jest-in-case with Jest.

import {add} from "./math";
import cases from "jest-in-case";

cases("add(augend, addend)", opts => {
  expect(add(opts.addend, opts.augend)).toEqual(opts.total);
}, {
  "add(1, 1)": { augend: 1, addend: 1, total: 2 },
  "add(2, 1)": { augend: 2, addend: 1, total: 3 },
  "add(3, 1)": { augend: 3, addend: 1, total: 4 },
  "add(4, 1)": { augend: 4, addend: 1, total: 5 },
});

Now if you want to focus on just one test, you can pass only: true

cases("add(augend, addend)", ..., {
  "add(1, 1)": { augend: 1, addend: 1, total: 2 },
  "add(2, 1)": { augend: 2, addend: 1, total: 3, only: true },
  "add(3, 1)": { augend: 3, addend: 1, total: 4 },
});

Or if you want to skip a test, you can pass skip: true

cases("add(augend, addend)", ..., {
  "add(1, 1)": { augend: 1, addend: 1, total: 2 },
  "add(2, 1)": { augend: 2, addend: 1, total: 3, skip: true },
  "add(3, 1)": { augend: 3, addend: 1, total: 4 },
});

If you'd prefer, you can also write your test cases as an array with name properties.

cases("add(augend, addend)", ..., [
  { name: "add(1, 1)", augend: 1, addend: 1, total: 2 },
  { name: "add(2, 1)", augend: 2, addend: 1, total: 3 },
  { name: "add(3, 1)", augend: 3, addend: 1, total: 4 },
]);

You write your tester function just like any other Jest test. It's just provided with the opts that make up your test case.

cases("title", opts => {
  expect(opts.foo).toEqual(opts.bar);
}, {
  "name": { foo: 1, bar: 1 }
});

Async tests work the same too. You can use either promises or callbacks:

cases("title", async opts => {
  let result = await doSomethingAsync(opts.input);
  expect(result).toEqual(opts.result);
}, ...);

cases("title", (opts, done) => {
  doSomethingAsync(opts.input).then(result => {
    expect(result).toEqual(opts.result);
    done();
  });
}, ...);

Plz download, star, like, subscribe, tell me what you think in the comment section, call your mother, punch a nazi, hold the people you care about close and never let go.

yarn add --dev jest-in-case

Repository → thinkmill/jest-in-case