Home Testing Matchers Reference

On this page 52

Complete reference for all available matchers in Home's modern testing framework.

Table of Contents

  1. Equality Matchers
  2. Truthiness Matchers
  3. Numeric Comparison Matchers
  4. Numeric Property Matchers
  5. String Matchers
  6. Special Matchers
  7. Negation

Equality Matchers

toBe(expected)

Strict equality check (reference equality for objects).

expect.* = test.expect(allocator, 42, failures);
try expect.toBe(42); // ✓ Pass

expect.* = test.expect(allocator, "hello", failures);
try expect.toBe("hello"); // ✓ Pass

Use case: Primitive values, exact matching


toEqual(expected)

Deep equality check (compares values recursively).

expect.* = test.expect(allocator, 100, failures);
try expect.toEqual(100); // ✓ Pass

Use case: Objects, arrays, nested structures


Truthiness Matchers

toBeTruthy()

Checks if value is truthy (non-zero, non-empty, non-null).

expect.* = test.expect(allocator, true, failures);
try expect.toBeTruthy(); // ✓ Pass

expect.* = test.expect(allocator, 42, failures);
try expect.toBeTruthy(); // ✓ Pass

expect.* = test.expect(allocator, "text", failures);
try expect.toBeTruthy(); // ✓ Pass

expect.* = test.expect(allocator, false, failures);
try expect.toBeTruthy(); // ✗ Fail

Truthy values: true, non-zero numbers, non-empty strings


toBeFalsy()

Checks if value is falsy (zero, empty, null, false).

expect.* = test.expect(allocator, false, failures);
try expect.toBeFalsy(); // ✓ Pass

expect.* = test.expect(allocator, 0, failures);
try expect.toBeFalsy(); // ✓ Pass

expect.* = test.expect(allocator, "", failures);
try expect.toBeFalsy(); // ✓ Pass

Falsy values: false, 0, "", null


toBeNull()

Checks if value is null.

expect.* = test.expect(allocator, null, failures);
try expect.toBeNull(); // ✓ Pass

toBeDefined()

Checks if value is defined (not null/undefined).

expect.* = test.expect(allocator, 42, failures);
try expect.toBeDefined(); // ✓ Pass

expect.* = test.expect(allocator, null, failures);
try expect.toBeDefined(); // ✗ Fail

toBeUndefined()

Checks if value is undefined/null.

expect.* = test.expect(allocator, null, failures);
try expect.toBeUndefined(); // ✓ Pass

Numeric Comparison Matchers

toBeGreaterThan(threshold)

Value must be strictly greater than threshold.

expect.* = test.expect(allocator, 10, failures);
try expect.toBeGreaterThan(5); // ✓ Pass (10 > 5)

expect.* = test.expect(allocator, 5, failures);
try expect.toBeGreaterThan(5); // ✗ Fail (5 is not > 5)

toBeLessThan(threshold)

Value must be strictly less than threshold.

expect.* = test.expect(allocator, 3, failures);
try expect.toBeLessThan(10); // ✓ Pass (3 < 10)

toBeGreaterThanOrEqual(threshold)

Value must be greater than or equal to threshold.

expect.* = test.expect(allocator, 10, failures);
try expect.toBeGreaterThanOrEqual(10); // ✓ Pass (10 >= 10)

expect.* = test.expect(allocator, 15, failures);
try expect.toBeGreaterThanOrEqual(10); // ✓ Pass (15 >= 10)

toBeLessThanOrEqual(threshold)

Value must be less than or equal to threshold.

expect.* = test.expect(allocator, 10, failures);
try expect.toBeLessThanOrEqual(10); // ✓ Pass (10 <= 10)

expect.* = test.expect(allocator, 5, failures);
try expect.toBeLessThanOrEqual(10); // ✓ Pass (5 <= 10)

toBeCloseTo(expected, precision)

Floating-point comparison with specified precision.

const pi: f64 = 3.14159;
expect.* = test.expect(allocator, pi, failures);
try expect.toBeCloseTo(3.14, 2); // ✓ Pass (matches to 2 decimals)

// Handles floating point precision issues
const value: f64 = 0.1 + 0.2; // = 0.30000000000000004
expect.* = test.expect(allocator, value, failures);
try expect.toBeCloseTo(0.3, 1); // ✓ Pass (matches to 1 decimal)

Parameters:

  • expected: Expected floating-point value
  • precision: Number of decimal places (default: 2)

toBeBetween(min, max)

Value must be within range [min, max] (inclusive).

expect.* = test.expect(allocator, 5, failures);
try expect.toBeBetween(1, 10); // ✓ Pass (1 <= 5 <= 10)

expect.* = test.expect(allocator, 10, failures);
try expect.toBeBetween(10, 20); // ✓ Pass (inclusive bounds)

expect.* = test.expect(allocator, 0, failures);
try expect.toBeBetween(1, 10); // ✗ Fail (0 < 1)

Numeric Property Matchers

toBePositive()

Value must be greater than zero.

expect.* = test.expect(allocator, 42, failures);
try expect.toBePositive(); // ✓ Pass

expect.* = test.expect(allocator, -5, failures);
try expect.toBePositive(); // ✗ Fail

toBeNegative()

Value must be less than zero.

expect.* = test.expect(allocator, -5, failures);
try expect.toBeNegative(); // ✓ Pass

expect.* = test.expect(allocator, 0, failures);
try expect.toBeNegative(); // ✗ Fail

toBeZero()

Value must equal zero.

expect.* = test.expect(allocator, 0, failures);
try expect.toBeZero(); // ✓ Pass

expect.* = test.expect(allocator, 0.0, failures);
try expect.toBeZero(); // ✓ Pass

toBeEven()

Integer value must be even.

expect.* = test.expect(allocator, 4, failures);
try expect.toBeEven(); // ✓ Pass

expect.* = test.expect(allocator, 100, failures);
try expect.toBeEven(); // ✓ Pass

expect.* = test.expect(allocator, 3, failures);
try expect.toBeEven(); // ✗ Fail

Note: Only works with integer types


toBeOdd()

Integer value must be odd.

expect.* = test.expect(allocator, 3, failures);
try expect.toBeOdd(); // ✓ Pass

expect.* = test.expect(allocator, 99, failures);
try expect.toBeOdd(); // ✓ Pass

expect.* = test.expect(allocator, 4, failures);
try expect.toBeOdd(); // ✗ Fail

toBeNaN()

Value must be NaN (Not a Number).

const nan*value = std.math.nan(f64);
expect.* = test.expect(allocator, nan*value, failures);
try expect.toBeNaN(); // ✓ Pass

expect.* = test.expect(allocator, 42.0, failures);
try expect.toBeNaN(); // ✗ Fail

Use case: Testing invalid mathematical operations


toBeInfinite()

Value must be positive or negative infinity.

const inf*value = std.math.inf(f64);
expect.* = test.expect(allocator, inf*value, failures);
try expect.toBeInfinite(); // ✓ Pass

const neg*inf = -std.math.inf(f64);
expect.* = test.expect(allocator, neg*inf, failures);
try expect.toBeInfinite(); // ✓ Pass

String Matchers

toContain(substring)

String must contain the given substring.

expect.* = test.expect(allocator, "hello world", failures);
try expect.toContain("world"); // ✓ Pass

expect.* = test.expect(allocator, "The quick brown fox", failures);
try expect.toContain("quick"); // ✓ Pass

expect.* = test.expect(allocator, "hello", failures);
try expect.toContain("xyz"); // ✗ Fail

toStartWith(prefix)

String must start with the given prefix.

expect.* = test.expect(allocator, "hello world", failures);
try expect.toStartWith("hello"); // ✓ Pass

expect.* = test.expect(allocator, "hello world", failures);
try expect.toStartWith("world"); // ✗ Fail

toEndWith(suffix)

String must end with the given suffix.

expect.* = test.expect(allocator, "hello world", failures);
try expect.toEndWith("world"); // ✓ Pass

expect.* = test.expect(allocator, "test.txt", failures);
try expect.toEndWith(".txt"); // ✓ Pass

toHaveLength(length)

String/array must have the specified length.

expect.* = test.expect(allocator, "hello", failures);
try expect.toHaveLength(5); // ✓ Pass

expect.* = test.expect(allocator, "", failures);
try expect.toHaveLength(0); // ✓ Pass

toBeEmpty()

String/array must be empty.

expect.* = test.expect(allocator, "", failures);
try expect.toBeEmpty(); // ✓ Pass

expect.* = test.expect(allocator, "text", failures);
try expect.toBeEmpty(); // ✗ Fail

toMatch(pattern)

String must match glob pattern (* for wildcards).

expect.* = test.expect(allocator, "hello world", failures);
try expect.toMatch("hello*"); // ✓ Pass

expect.* = test.expect(allocator, "test123", failures);
try expect.toMatch("test*"); // ✓ Pass

expect.* = test.expect(allocator, "file.txt", failures);
try expect.toMatch("*.txt"); // ✓ Pass

Pattern syntax:

  • * matches any sequence of characters
  • Literal characters must match exactly

Special Matchers

toMatchSnapshot(name, snapshots)

Compare value against saved snapshot.

expect.* = test.expect(allocator, output, failures);
try expect.toMatchSnapshot("component*render", &framework.snapshots);

First run: Creates snapshot Subsequent runs: Compares against saved snapshot


toHaveBeenCalled() (Mock)

Mock/spy must have been called at least once.

var mock = testing.ModernTest.Mock.init(allocator);
defer mock.deinit();

// ... call mock ...

if (mock.toHaveBeenCalled()) {
    // Mock was called
}

toHaveBeenCalledTimes(count) (Mock)

Mock/spy must have been called exactly N times.

if (mock.toHaveBeenCalledTimes(3)) {
    // Mock was called exactly 3 times
}

toHaveBeenCalledWith(args) (Mock)

Mock/spy must have been called with specific arguments.

if (mock.toHaveBeenCalledWith(&.{arg1, arg2})) {
    // Mock was called with these arguments
}

Negation

All matchers support negation via the .not modifier.

Basic Negation

expect.* = test.expect(allocator, 42, failures);
expect.not = true;
try expect.toBe(99); // ✓ Pass (42 != 99)

Negation Examples

Not equal:

expect.not = true;
try expect.toBe(value); // Fails if equal

Not contain:

expect.* = test.expect(allocator, "hello world", failures);
expect.not = true;
try expect.toContain("xyz"); // ✓ Pass (doesn't contain "xyz")

Not positive:

expect.* = test.expect(allocator, -5, failures);
expect.not = true;
try expect.toBePositive(); // ✓ Pass (-5 is not positive)

Not in range:

expect.* = test.expect(allocator, 50, failures);
expect.not = true;
try expect.toBeBetween(1, 10); // ✓ Pass (50 not in [1,10])

Pattern: Reset Negation

Always reset .not after use if reusing expect:

expect.not = true;
try expect.toBe(99);
expect.not = false; // Reset for next assertion

Matcher Categories Summary

CategoryCountExamples
Equality2toBe, toEqual
Truthiness5toBeTruthy, toBeFalsy, toBeNull, toBeDefined, toBeUndefined
Numeric Comparison6toBeGreaterThan, toBeLessThan, toBeCloseTo, toBeBetween
Numeric Properties7toBePositive, toBeNegative, toBeZero, toBeEven, toBeOdd, toBeNaN, toBeInfinite
String6toContain, toStartWith, toEndWith, toHaveLength, toBeEmpty, toMatch
Special4toMatchSnapshot, toHaveBeenCalled, toHaveBeenCalledTimes, toHaveBeenCalledWith

Total: 30+ matchers


Quick Reference Chart

When to Use Which Matcher

ScenarioMatcherExample
Exact equalitytoBetry expect.toBe(42)
Deep equalitytoEqualtry expect.toEqual(obj)
Check if true/non-zerotoBeTruthytry expect.toBeTruthy()
Check if false/zerotoBeFalsytry expect.toBeFalsy()
Check nulltoBeNulltry expect.toBeNull()
Number > thresholdtoBeGreaterThantry expect.toBeGreaterThan(10)
Number < thresholdtoBeLessThantry expect.toBeLessThan(100)
Float comparisontoBeCloseTotry expect.toBeCloseTo(3.14, 2)
Range checktoBeBetweentry expect.toBeBetween(1, 10)
Positive numbertoBePositivetry expect.toBePositive()
Negative numbertoBeNegativetry expect.toBeNegative()
Even numbertoBeEventry expect.toBeEven()
Odd numbertoBeOddtry expect.toBeOdd()
Contains substringtoContaintry expect.toContain("hello")
Starts with prefixtoStartWithtry expect.toStartWith("Mr.")
Ends with suffixtoEndWithtry expect.toEndWith(".txt")
String lengthtoHaveLengthtry expect.toHaveLength(5)
Empty string/arraytoBeEmptytry expect.toBeEmpty()
Pattern matchtoMatchtry expect.toMatch("*.json")

Best Practices

1. Choose the Right Matcher

Good:

expect.toBePositive(); // Clear intent

Bad:

expect.toBeGreaterThan(0); // Less clear

2. Use Specific Matchers

Good:

expect.toStartWith("Error:");

Bad:

expect.toMatch("Error:*"); // More complex

3. Handle Floating Point Correctly

Good:

expect.toBeCloseTo(0.3, 1); // Handles 0.1 + 0.2

Bad:

expect.toBe(0.3); // May fail due to precision

4. Use Negation Sparingly

Good:

expect.not = true;
try expect.toContain("error");

Also Good (when available):

// Use opposite matcher if available
try expect.toBePositive(); // Instead of not.toBeNegative()

Error Messages

All matchers provide clear error messages:

✗ validates email format
  Expected value to contain substring
  Expected: "@example.com"
  Actual:   "invalidemail"
✗ checks range
  Expected value to be between range
  Expected: { 1, 10 }
  Actual:   15

See Also

Released under the MIT License.