Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

test.expect

import test.expect

test lifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelled test.expect.* needs import test.expect.

expect(value) and everything that can be said about a value once you have one.

expect(total).to_be(42)
expect(user).to_match_object({ name: 'Ada' })
expect(items).not.to_be_empty()
expect(@{ parse('') }).to_raise_instance_of(ValueError)

Negation

Every matcher negates through .not, and there is exactly one implementation behind both directions, so a matcher and its negation can never disagree about what they mean.

Chaining

Matchers return the Expect they were called on, so several statements about one value read as one:

expect(port).to_be_int().to_be_between(1024, 65535)

Labels

A second argument to expect() names the value, which is worth doing when the number alone would not say which number it was:

expect(response.status, 'status').to_be(200)
Expected status (404) to be 200

Choosing between to_be and to_equal

to_be is Zuri’s ==. That already compares lists, dictionaries and bytes by their contents, so it is the right matcher for most things. It compares two instances by identity, though, so two separately constructed objects are never to_be each other. to_equal is the structural one: it walks instances field by field, treats NaN as equal to itself, and survives a value that contains itself.

Functions

expect()

test.expect(value, label: ?string) -> Expect

Starts an assertion about value.

expect(total).to_be(42)
expect(total, 'order total').to_be(42)

Parameters

  • value (any)
  • label (?string) — a name for the value, shown in failure messages ahead of the value itself.

Returns Expect

fail()

test.fail(message: ?string)

Fails the current test outright.

For the branch that should never be reached:

using response.status {
  when 200 handle_ok()
  when 404 handle_missing()
  default fail('unexpected status ${response.status}')
}

Parameters

  • message (?string)

Raises AssertionError always.

assertions()

test.assertions(count: int)

Declares that this test makes exactly count assertions, and fails it if the number turns out to be different.

This is how a test proves that a branch it expected to reach was actually reached, which matters most when the assertions are inside a callback that might never run:

it('reports every error', @{
  assertions(2)

  validate(bad_input, @(error) {
    expect(error.field).to_be_string()
  })
})

Parameters

  • count (int)

Raises TestSetupError outside a test.

has_assertions()

test.has_assertions()

Declares that this test makes at least one assertion, and fails it if none did.

Raises TestSetupError outside a test.

capture_output()

test.capture_output(body: function) -> string

Runs body and returns everything it printed to standard output.

The composable half of to_print(): use this when the assertion to make about the output is not “it contains this”.

var printed = capture_output(@{ report(rows) })
expect(printed.lines()).to_have_length(4)

Parameters

  • body (function)

Returns string

Classes

Expect

class test.Expect

The subject of an assertion, and every matcher that can be applied to it.

Built by expect(); there is no reason to construct one directly.

Fields

FieldTypeDescription
notThe same subject, with every matcher asserting the opposite.

Constructor

test.Expect(value, label, negated, twin)

Parameters

  • value (any) — the value under test.
  • label (?string) — a name for it, used in failure messages.
  • negated (?bool)
  • twin (?Expect) — the opposite-polarity object to point not at. Left out, one is built; this is what stops the pair from constructing each other forever.

Expect.to_be()

test.Expect.to_be(expected) -> Expect

Asserts ==.

Numbers, strings and booleans compare by value; lists, dictionaries and bytes compare by contents; instances and functions compare by identity.

expect(2 + 2).to_be(4)
expect([1, 2]).to_be([1, 2])

Parameters

  • expected (any)

Returns Expect

Expect.to_equal()

test.Expect.to_equal(expected) -> Expect

Asserts structural equality: instances are compared field by field rather than by identity, NaN equals NaN, and a value that contains itself is handled rather than hung on.

expect(Point(1, 2)).to_equal(Point(1, 2))

Parameters

  • expected (any)

Returns Expect

Expect.to_be_same_as()

test.Expect.to_be_same_as(expected) -> Expect

Asserts that this is the very same object, not merely one that looks the same. Two lists with identical contents are to_be each other but not to_be_same_as each other.

var original = [1, 2]
expect(passed_through(original)).to_be_same_as(original)

Parameters

  • expected (any)

Returns Expect

Expect.to_be_close_to()

test.Expect.to_be_close_to(expected: number, digits: ?int) -> Expect

Asserts two numbers agree to digits decimal places, which is the only sane way to compare anything that has been through floating-point arithmetic.

expect(0.1 + 0.2).to_be_close_to(0.3)

Parameters

  • expected (number)
  • digits (?int) — decimal places, 2 by default, so the default tolerance is 0.005.

Returns Expect

Expect.to_be_within()

test.Expect.to_be_within(expected: number, delta: number) -> Expect

Asserts two numbers are no more than delta apart, when the tolerance is better stated as an absolute amount than as a number of decimal places.

expect(elapsed_ms).to_be_within(500, 50)

Parameters

  • expected (number)
  • delta (number) — inclusive.

Returns Expect

Expect.to_match_object()

test.Expect.to_match_object(expected: dict) -> Expect

Asserts that every key in expected is present with a matching value, ignoring anything else the subject carries.

Nested dictionaries recurse, and the subject may be a dictionary or an instance, so one expectation can be checked against either.

expect(create_user('Ada')).to_match_object({ name: 'Ada', active: true })

Parameters

  • expected (dict)

Returns Expect

Expect.to_be_true()

test.Expect.to_be_true()

Asserts the value is exactly true. @returns Expect

Expect.to_be_false()

test.Expect.to_be_false()

Asserts the value is exactly false. @returns Expect

Expect.to_be_truthy()

test.Expect.to_be_truthy() -> Expect

Asserts the value is truthy.

Returns Expect

Note: Zuri’s falsy values are false, nil, zero, NaN, a zero bigint, the empty string and an empty bytes buffer. Every negative number is truthy, and so is an empty list or dictionary; use to_be_empty() for those.

Expect.to_be_falsy()

test.Expect.to_be_falsy() -> Expect

Asserts the value is falsy.

Returns Expect

Note: see to_be_truthy() for the full list of falsy values.

Expect.to_be_nil()

test.Expect.to_be_nil()

Asserts the value is nil. @returns Expect

Expect.to_be_defined()

test.Expect.to_be_defined() -> Expect

Asserts the value is anything other than nil, which is the assertion to reach for after a lookup that can come back empty.

Returns Expect

Expect.to_be_a()

test.Expect.to_be_a(type) -> Expect

Asserts the value’s type.

type may be a type name as a string, one of the names format.type_name() produces, or a class, in which case this means the same as to_be_instance_of().

expect(payload).to_be_a('dict')
expect(result).to_be_a(Point)

Parameters

  • type (string|class)

Returns Expect

Expect.to_be_string()

test.Expect.to_be_string()

Asserts the value is a string. @returns Expect

Expect.to_be_number()

test.Expect.to_be_number()

Asserts the value is a number, of either kind. @returns Expect

Expect.to_be_int()

test.Expect.to_be_int()

Asserts the value is a number with no fractional part. @returns Expect

Expect.to_be_float()

test.Expect.to_be_float()

Asserts the value is a number with a fractional part. @returns Expect

Expect.to_be_bigint()

test.Expect.to_be_bigint()

Asserts the value is an arbitrary-precision integer. @returns Expect

Expect.to_be_bool()

test.Expect.to_be_bool()

Asserts the value is a boolean. @returns Expect

Expect.to_be_list()

test.Expect.to_be_list()

Asserts the value is a list. @returns Expect

Expect.to_be_dict()

test.Expect.to_be_dict()

Asserts the value is a dictionary. @returns Expect

Expect.to_be_bytes()

test.Expect.to_be_bytes()

Asserts the value is a bytes buffer. @returns Expect

Expect.to_be_function()

test.Expect.to_be_function()

Asserts the value is a function. @returns Expect

Expect.to_be_callable()

test.Expect.to_be_callable() -> Expect

Asserts the value can be called, which a class and a bound method can be as well as a function.

Returns Expect

Expect.to_be_iterable()

test.Expect.to_be_iterable() -> Expect

Asserts the value can be iterated with for, which covers lists, dictionaries, strings, ranges, bytes, and any class defining @key and @value.

Returns Expect

Expect.to_be_class()

test.Expect.to_be_class()

Asserts the value is a class, not an instance of one. @returns Expect

Expect.to_be_instance()

test.Expect.to_be_instance()

Asserts the value is an instance of some class. @returns Expect

Expect.to_be_instance_of()

test.Expect.to_be_instance_of(klass: type) -> Expect

Asserts the value is an instance of klass or of anything that inherits from it.

expect(error).to_be_instance_of(ValueError)

Parameters

  • type — klass

Returns Expect

Expect.to_be_greater_than()

test.Expect.to_be_greater_than(bound: number)

Parameters

  • bound (number) — @returns Expect

Expect.to_be_greater_than_or_equal()

test.Expect.to_be_greater_than_or_equal(bound: number)

Parameters

  • bound (number) — @returns Expect

Expect.to_be_less_than()

test.Expect.to_be_less_than(bound: number)

Parameters

  • bound (number) — @returns Expect

Expect.to_be_less_than_or_equal()

test.Expect.to_be_less_than_or_equal(bound: number)

Parameters

  • bound (number) — @returns Expect

Expect.to_be_between()

test.Expect.to_be_between(low: number, high: number) -> Expect

Asserts the value falls in [low, high], both ends included.

Parameters

  • low (number)
  • high (number)

Returns Expect

Expect.to_be_positive()

test.Expect.to_be_positive()

Asserts the value is greater than zero. @returns Expect

Expect.to_be_negative()

test.Expect.to_be_negative()

Asserts the value is less than zero. @returns Expect

Expect.to_be_zero()

test.Expect.to_be_zero()

Asserts the value is zero, of either sign. @returns Expect

Expect.to_be_divisible_by()

test.Expect.to_be_divisible_by(divisor: number) -> Expect

Asserts the value divides by divisor with nothing left over.

Parameters

  • divisor (number)

Returns Expect

Expect.to_be_even()

test.Expect.to_be_even()

Asserts the value is an even whole number. @returns Expect

Expect.to_be_odd()

test.Expect.to_be_odd()

Asserts the value is an odd whole number. @returns Expect

Expect.to_be_nan()

test.Expect.to_be_nan() -> Expect

Asserts the value is the floating-point not-a-number.

NaN is not == to itself, so this is the only way to check for it.

Returns Expect

Expect.to_be_finite()

test.Expect.to_be_finite()

Asserts the value is a number that is neither infinite nor NaN. @returns Expect

Expect.to_be_infinite()

test.Expect.to_be_infinite()

Asserts the value is positive or negative infinity. @returns Expect

Expect.to_contain()

test.Expect.to_contain(item) -> Expect

Asserts the subject contains item.

What “contains” means follows the subject: a substring of a string, an element of a list or a bytes buffer, a key of a dictionary. Comparison is ==; to_contain_equal() is the structural version.

Parameters

  • item (any)

Returns Expect

Expect.to_contain_equal()

test.Expect.to_contain_equal(item) -> Expect

Asserts the subject contains an element deeply equal to item, which is what finding an object in a list needs.

Parameters

  • item (any)

Returns Expect

Expect.to_contain_ignoring_case()

test.Expect.to_contain_ignoring_case(part: string) -> Expect

Asserts the string contains part, ignoring case.

Parameters

  • part (string)

Returns Expect

Expect.to_equal_ignoring_case()

test.Expect.to_equal_ignoring_case(expected: string) -> Expect

Asserts the string equals expected, ignoring case.

Parameters

  • expected (string)

Returns Expect

Expect.to_start_with()

test.Expect.to_start_with(prefix: string) -> Expect

Parameters

  • prefix (string)

Returns Expect

Expect.to_end_with()

test.Expect.to_end_with(suffix: string) -> Expect

Parameters

  • suffix (string)

Returns Expect

Expect.to_match()

test.Expect.to_match(pattern: string) -> Expect

Asserts the string matches a regular expression.

expect(id).to_match('/^user-[0-9]+$/')

Parameters

  • pattern (string) — a Zuri regular expression, delimiters included.

Returns Expect

Expect.to_be_blank()

test.Expect.to_be_blank() -> Expect

Asserts the string is empty or contains nothing but whitespace.

Returns Expect

Expect.to_have_length()

test.Expect.to_have_length(expected: int) -> Expect

Asserts the subject’s length.

Parameters

  • expected (int)

Returns Expect

Expect.to_be_empty()

test.Expect.to_be_empty() -> Expect

Asserts the subject has no elements, no entries, or no characters.

Returns Expect

Expect.to_contain_all()

test.Expect.to_contain_all(items: list) -> Expect

Asserts every one of items is present, in any order.

Parameters

  • items (list)

Returns Expect

Expect.to_contain_any()

test.Expect.to_contain_any(items: list) -> Expect

Asserts at least one of items is present.

Parameters

  • items (list)

Returns Expect

Expect.to_contain_none()

test.Expect.to_contain_none(items: list) -> Expect

Asserts none of items is present.

Parameters

  • items (list)

Returns Expect

Expect.to_contain_exactly()

test.Expect.to_contain_exactly(items: list) -> Expect

Asserts the list holds exactly items, in any order and with the same number of duplicates.

This is the matcher for a collection whose order is not part of the contract, such as one built from a dictionary’s keys.

Parameters

  • items (list)

Returns Expect

Expect.to_have_key()

test.Expect.to_have_key(key) -> Expect

Asserts the dictionary has key, whatever it maps to.

Parameters

  • key (any)

Returns Expect

Expect.to_have_keys()

test.Expect.to_have_keys(keys: list) -> Expect

Asserts the dictionary has every one of keys.

Parameters

  • keys (list)

Returns Expect

Expect.to_have_value()

test.Expect.to_have_value(value) -> Expect

Asserts the dictionary maps some key to value.

Parameters

  • value (any)

Returns Expect

Expect.to_have_property()

test.Expect.to_have_property(path: string, value) -> Expect

Asserts something exists at a dotted path, and optionally that it equals value.

The path walks dictionary keys, instance properties and list indices alike, so one expression reaches into a whole decoded response:

expect(payload).to_have_property('data.items.0.id', 7)

Parameters

  • path (string)
  • value (?any) — when given, what must be there. Left out, this only asserts that the path resolves to something other than nil.

Returns Expect

Expect.to_be_sorted()

test.Expect.to_be_sorted() -> Expect

Asserts the list is in ascending order.

Numbers compare numerically and strings compare by codepoint. A list mixing the two has no order to be in, and says so.

Returns Expect

Expect.to_have_unique_items()

test.Expect.to_have_unique_items() -> Expect

Asserts no two elements of the list are equal.

Returns Expect

Expect.to_raise()

test.Expect.to_raise() -> Expect

Asserts that calling the subject raises.

The subject must be a function taking no arguments; wrap the call being tested in one.

expect(@{ parse('') }).to_raise()

Returns Expect

Expect.to_raise_instance_of()

test.Expect.to_raise_instance_of(klass: type) -> Expect

Asserts that calling the subject raises an instance of klass, or of something inheriting from it.

expect(@{ parse('') }).to_raise_instance_of(ValueError)

Parameters

  • type — klass

Returns Expect

Expect.to_raise_with_message()

test.Expect.to_raise_with_message(part: string) -> Expect

Asserts that calling the subject raises something whose message contains part, or matches it when part is a regular expression.

expect(@{ withdraw(10, 5) }).to_raise_with_message('cannot withdraw')
expect(@{ withdraw(10, 5) }).to_raise_with_message('/withdraw [0-9]+/')

Parameters

  • part (string) — taken as a regular expression when it is delimited like one, and as a substring otherwise.

Returns Expect

Expect.to_not_raise()

test.Expect.to_not_raise() -> Expect

Asserts that calling the subject does not raise.

The same as .not.to_raise(), and there for the many tests that read better stating it directly.

Returns Expect

Expect.to_have_been_called()

test.Expect.to_have_been_called() -> Expect

Asserts the mock has been called at least once.

The subject may be the Mock or the function it handed out.

Returns Expect

Expect.to_have_been_called_times()

test.Expect.to_have_been_called_times(count: int) -> Expect

Asserts the mock has been called exactly count times.

Parameters

  • count (int)

Returns Expect

Expect.to_have_been_called_with()

test.Expect.to_have_been_called_with(...args: list) -> Expect

Asserts the mock was called at least once with exactly these arguments.

expect(send).to_have_been_called_with('hello', { retry: true })

Parameters

  • args (...any)

Returns Expect

Expect.to_have_been_last_called_with()

test.Expect.to_have_been_last_called_with(...args: list) -> Expect

Asserts the mock’s most recent call had exactly these arguments.

Parameters

  • args (...any)

Returns Expect

Expect.to_have_been_nth_called_with()

test.Expect.to_have_been_nth_called_with(index, ...args: list) -> Expect

Asserts the mock’s index-th call had exactly these arguments, counting from zero. A negative index counts back from the most recent.

Parameters

  • index (int)
  • args (...any)

Returns Expect

Expect.to_have_returned()

test.Expect.to_have_returned() -> Expect

Asserts at least one call returned rather than raised.

Returns Expect

Expect.to_have_returned_with()

test.Expect.to_have_returned_with(value) -> Expect

Asserts at least one call returned value.

Parameters

  • value (any)

Returns Expect

Expect.to_have_raised()

test.Expect.to_have_raised() -> Expect

Asserts at least one call raised.

Returns Expect

Expect.to_print()

test.Expect.to_print(part: string) -> Expect

Asserts that running the subject prints something containing part.

The subject must be a function taking no arguments. Everything Zuri writes to standard output while it runs is collected: echo, print() and io.stdout alike.

expect(@{ greet('Ada') }).to_print('Hello, Ada')

Parameters

  • part (string)

Returns Expect

Expect.to_print_exactly()

test.Expect.to_print_exactly(expected: string) -> Expect

Asserts that running the subject prints exactly expected, trailing newline and all.

Parameters

  • expected (string)

Returns Expect

Expect.to_print_nothing()

test.Expect.to_print_nothing() -> Expect

Asserts that running the subject prints nothing at all.

Returns Expect

Expect.to_match_snapshot()

test.Expect.to_match_snapshot(name: ?string) -> Expect

Asserts the value still looks the way it did when it was first recorded.

The first run writes the snapshot and passes. Later runs compare against it. See test.snapshot on where the files live, how to update them, and why a brand new snapshot fails on CI.

expect(render(invoice)).to_match_snapshot()
expect(headers).to_match_snapshot('response headers')

Parameters

  • name (?string) — distinguishes several snapshots in one test. Without one they are numbered in the order they are taken.

Returns Expect

Expect.to_satisfy()

test.Expect.to_satisfy(predicate: function, description: ?string) -> Expect

Asserts predicate(value) is truthy, for the assertion no built-in matcher makes.

expect(port).to_satisfy(@(n) { return n % 2 == 0 }, 'to be an even port')

Parameters

  • predicate (function)
  • description (?string) — completes the sentence Expected <value> .... Without one the message says only that a predicate was not satisfied, which is rarely enough.

Returns Expect