testing-base
Testing patterns and conventions for packages/base tests
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Testing patterns and conventions for packages/base tests
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
| name | testing-base |
| description | Testing patterns and conventions for packages/base tests |
Tests in @fncts/base use a custom testing layer over Vitest. Assertions are expressed through a pipeable .assert() method on values, combined with assertion-building helpers. Suites run concurrently by default and property-based testing is woven in via Gen generators.
Testing globals (suite, test) are provided by @fncts/test wrapping Vitest. Extension methods from @fncts/base and @fncts/io are loaded via ambient type imports.
import type {} from "@fncts/base/global";
import type {} from "@fncts/io/global";
Vitest helpers like vitest.fn can be imported when needed:
import { vitest } from "vitest";
suite.suite.concurrent("Vector", () => {
suite.concurrent("empty", () => {
test("empty", Vector.empty<number>().assert(strictEqualTo(Vector.empty())));
});
suite.concurrent("append", () => {
test(
"append to empty",
Vector.empty<number>()
.append(1)
.assert(strictEqualTo(Vector(1))),
);
});
});
Use the pipeable .assert() method on values. Do not use Vitest's expect().
value.assert(assertion)
Common assertion helpers:
| Assertion | Meaning |
|---|---|
strictEqualTo(expected) | Referential / Equatable equality |
deepEqualTo(expected) | Deep structural equality |
isTrue | Boolean is true |
isFalse | Boolean is false |
isJust(inner) | Maybe is Just matching inner |
isNothing | Maybe is Nothing |
calledTimes(n) | Vitest mock called exactly n times |
every(assertion) | Every element in a collection matches |
Combine assertions in a single test with &&:
test("both conditions", condition1.assert(isTrue) && condition2.assert(isFalse));
Negate an assertion with .invert:
Vector(1, 2, 3).assert(strictEqualTo(Vector(1, 2, 3, 4)).invert);
Use Gen generators inside a test.io block with .check().
suite("property-based", () => {
test.io(
"reverse is involution",
Gen.int.array.check((as) => {
const list = List.from(as);
return list.reverse.reverse.assert(strictEqualTo(list));
}),
);
});
Common Gen patterns:
Gen.int.array – arrays of intsGen.int.array.check(fn) – check a property over arraysGen.int.conc – generated Conc valuesGen.intWith({ min, max }) – bounded intsGen.int.array.zip(Gen.int.array) – two related inputsWhen testing IO values or effects, use test.io and .assertIO:
import type {} from "@fncts/io/global";
test.io(
"buffer used",
Gen.int.conc.zip(Gen.int.conc).check(([as, bs]) => {
const effect = IO.succeed(bs.foldLeft(as, (acc, a) => acc.append(a)));
const actual = IO.allConcurrent(Iterable.replicate(100, effect));
const expected = as.concat(bs);
return actual.assertIO(every(strictEqualTo(expected)));
}),
{ timeout: 20_000 },
);
Define local helpers at the top of a test file when they reduce boilerplate:
function Q<A>(...as: A[]): ImmutableQueue<A> {
let q = ImmutableQueue.empty<A>();
for (const a of as) {
q = q.enqueue(a);
}
return q;
}
When testing mutable variants vs immutable results, assert that the original is unchanged:
test("append preserves original", () => {
const original = Vector(1, 2);
const appended = original.append(3);
return original.assert(strictEqualTo(Vector(1, 2)));
});
When a function returns a tuple or pair, use deepEqualTo with an explicit as const:
test(
"splitAt middle",
Vector(1, 2, 3, 4, 5)
.splitAt(2)
.assert(deepEqualTo([Vector(1, 2), Vector(3, 4, 5)] as const)),
);
suite, not describe..assert() with strictEqualTo, deepEqualTo, isTrue, isFalse, etc. Never use expect().&& when multiple conditions are checked in one test.test.io + Gen for property-based tests.@fncts/base/global, @fncts/io/global) so extension methods are available.deepEqualTo for arrays and tuples, strictEqualTo for values with custom equality.