test.expect
import test.expect
testlifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelledtest.expect.*needsimport 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
| Field | Type | Description |
|---|---|---|
not | The 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 pointnotat. 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,2by 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; useto_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 thannil.
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 sentenceExpected <value> .... Without one the message says only that a predicate was not satisfied, which is rarely enough.
Returns Expect