Matchers
expect is a global inside the Hermes realm. Every matcher below also works negated
through .not, and asynchronously through .resolves / .rejects — see
Async tests.
Equality
Section titled “Equality”| Matcher | Passes when |
|---|---|
toBe(expected) |
Object.is-style identity (SameValueZero) |
toEqual(expected) |
Recursively equal, ignoring undefined properties |
toStrictEqual(expected) |
Recursively equal, undefined properties significant, types must match |
expect({ a: 1 }).toEqual({ a: 1 }); // pass — different objects, same shapeexpect({ a: 1 }).toBe({ a: 1 }); // fail — not the same objectexpect({ a: 1, b: undefined }).toEqual({ a: 1 }); // passexpect({ a: 1, b: undefined }).toStrictEqual({ a: 1 }); // failTruthiness and nullishness
Section titled “Truthiness and nullishness”expect(value).toBeTruthy();expect(value).toBeFalsy();expect(value).toBeNull();expect(value).toBeUndefined();expect(value).toBeDefined();expect(value).toBeNaN();Numbers
Section titled “Numbers”expect(total).toBeGreaterThan(0);expect(total).toBeGreaterThanOrEqual(100);expect(total).toBeLessThan(1000);expect(total).toBeLessThanOrEqual(999);expect(0.1 + 0.2).toBeCloseTo(0.3); // default precision: 2 digitsexpect(0.1 + 0.2).toBeCloseTo(0.3, 10);Strings
Section titled “Strings”expect(slug).toMatch('checkout'); // substringexpect(slug).toMatch(/^checkout-\d+$/); // patternCollections
Section titled “Collections”expect(items).toHaveLength(3);expect(items).toContain('A1'); // identityexpect(items).toContainEqual({ sku: 'A1' }); // deep equalitytoContain and toContainEqual work on arrays and strings.
Objects
Section titled “Objects”expect(user).toHaveProperty('address.city');expect(user).toHaveProperty('address.city', 'Madrid');expect(user).toHaveProperty(['tags', 0], 'beta');
expect(response).toMatchObject({ status: 200, body: { ok: true } });toHaveProperty takes a dotted path or an array of keys. toMatchObject checks that the
received object contains at least the given subset, recursively.
Throwing
Section titled “Throwing”expect(() => parse('')).toThrow();expect(() => parse('')).toThrow(RangeError); // constructorexpect(() => parse('')).toThrow('empty input'); // substring of the messageexpect(() => parse('')).toThrow(/empty/); // patternThe argument must be a function. Handing toThrow a value that has already thrown is a
usage error, not a silent pass.
Negation
Section titled “Negation”.not inverts any matcher, including the async forms.
expect(total).not.toBe(0);expect(items).not.toContain('A9');await expect(load()).resolves.not.toBeNull();Mock and spy matchers
Section titled “Mock and spy matchers”Available on anything created with argus.fn() or argus.spyOn() — see
Mocks & spies.
expect(fn).toHaveBeenCalled();expect(fn).toHaveBeenCalledTimes(3);expect(fn).toHaveBeenCalledWith(1, 'a');expect(fn).toHaveBeenLastCalledWith(9);expect(fn).toHaveBeenNthCalledWith(1, 'a');
expect(fn).toHaveReturned();expect(fn).toHaveReturnedTimes(3);expect(fn).toHaveReturnedWith(10);expect(fn).toHaveLastReturnedWith(10);expect(fn).toHaveNthReturnedWith(2, 2);Argument comparison is deep equality, so object arguments match by shape.
Custom matchers
Section titled “Custom matchers”expect.extend merges a table of matchers into the global set. A matcher returns
{ pass, message }; message is a function so the string is only built when it is needed.
expect.extend({ toBeWithin(actual: number, min: number, max: number) { const pass = actual >= min && actual <= max; return { pass, message: () => pass ? `expected ${actual} not to be within ${min}..${max}` : `expected ${actual} to be within ${min}..${max}`, }; },});
expect(elapsed).toBeWithin(0, 100);expect(elapsed).not.toBeWithin(500, 1000);Negation is handled for you — return pass as if the assertion were positive.
Assertion counting
Section titled “Assertion counting”Useful when a test’s assertions live in a callback that might never run.
test('calls back exactly once', () => { expect.assertions(1); withRetry(() => { expect(true).toBe(true); });});
test('asserts something', async () => { expect.hasAssertions(); await expect(load()).resolves.toBeDefined();});expect.assertions(n) requires exactly n; expect.hasAssertions() requires at least one.
Counting happens at matcher invocation, not inside the assertion. A matcher that throws
a usage error before asserting — toThrow on a non-function, toEqual on a Map — still
counts exactly once, so a guard failure cannot masquerade as “no assertions ran”.
Failure messages
Section titled “Failure messages”Values are rendered by a Hermes-safe formatter rather than JSON.stringify. A test that
has poisoned Object.prototype or replaced Array.prototype.push still produces a
readable message instead of taking the reporter down with it.