Vitest with async fixtures and it.for/it.each
Pretty often in Val Town’s vitest test suite we have some scenario where we want to set up some data in the database and then use the test.each method to test different operations on the database. We finally did the work of figuring out how to represent this nicely today and came up with something like this:
import { describe, it as _it, expect } from "vitest";
describe("tests", () => {
const it = _it.extend<{
time: number;
}>({
// biome-ignore lint/correctness/noEmptyPattern: vitest is strict about this param
time: async ({}, use) => {
use(await Promise.resolve(Date.now()));
},
});
c.for([[1, 2]])("should work", ([a, b], { time }) => {
expect(a).toEqual(1);
expect(b).toEqual(2);
expect(time).toBeTypeOf("number");
});
});This required a few different bits of understanding:
it.foris a betterit.each. We were usingit.each, but it doesn't support text context.- Test context is a pretty decent way of storing fixtures. Before we were using
beforeEachandbeforeAlland assigning to variables that we'd refer to in test cases.it.extendis a bit smoother than that. - Still, manually repeating the types of the fixtures in
it.extendis an annoyance, probably cause by the fact that you calluse(value)instead ofreturn valueto assign fixtures. There's probably a good reason why they did that, but nevertheless I'd prefer to have these fixture values inferred. - Vitest is pretty wild in that it does static analysis checks, which is why I had to disable a biome rule here for that empty object pattern: vitest insists in destructuring, and biome does not like empty object destructuring.