It Should Help

Best Practices

Habits that keep should() chains readable and their failures informative.

Pick the most specific verifier

The more specific the verifier, the more specific the failure. should().true(x !== null) fails with a generic message; should().string(x).defined() and every later check in that chain fails with context. Use true()/false() only for genuine boolean-context checks (see General Assertions).

One chain, one behavior

Chain checks that describe the same outcome, not a whole test in one line:

// good: the chain reads as one claim about the response should().array(users).ordered({ by: (u) => u?.age }); // good: several claims, each visible should().array(page).length(20); should().array(page).containOnly((u) => u!.active); // avoid: a wall of checks whose failure could mean anything should().array(page).length(20).containOnly(...).uniq(...).ordered(...);

Assert positively rather than double-negated

not.contain(5) is fine; not.empty() usually isn't the point — length(n) or contain(expected) says what you actually mean. Reserve not for genuine absence assertions (Concepts explains the mechanics).

Give object collections an identifier

Every array check on objects compares by reference unless you pass the identifier function. Make it a reflex: objects in, (e) => e?.id in (see Arrays). Without it the failure says "doesn't contain the expected element" for data that looks identical — the least debuggable failure in the library.

Prefer compareOnly over ignoring for strict contracts

ignoring('updatedAt') passes no matter what other fields drift in. When the test owns the full expectation, compareOnly(...) enumerates exactly what matters — new unexpected fields then fail loudly instead of silently passing (see Objects).

Nullables: assert definedness explicitly

When absence is meaningful, say so — defined() or not.defined() as its own check. The implicit guard throws for every check anyway; an explicit assertion documents intent and fails at the right line (see Concepts).

Use date accuracy instead of arithmetic

equals(expected, 'day') replaces hand-computed day boundaries, and it documents the test's real tolerance (see Dates).

Assert behavior, not messages

Failure messages are readable by design, but they are a contract of the library, not of your code — don't build tests around matching their exact text.

02 сентября 2026