dream_test/matchers
Matcher API for Dream Test.
Matchers are small functions you pipe values through to produce the value a
Dream Test it(...) body returns: Result(AssertionResult, String).
You’ll typically:
- Start with
should(wrap a value for matching) - Apply one or more matchers (like
be_equal,be_some,contain_string) - Finish with
or_fail_with("...")to produce the final test result
Available Matchers
| Category | Matchers |
|---|---|
| Equality | be_equal, not_equal |
| Boolean | be_true, be_false |
| Option | be_some, be_none |
| Result | be_ok, be_error |
| Collections | contain, not_contain, have_length, be_empty |
| Comparison | be_greater_than, be_less_than, be_at_least, be_at_most, be_between, be_in_range, be_greater_than_float, be_less_than_float |
| String | start_with, end_with, contain_string, match_regex |
| Snapshot | match_snapshot, match_snapshot_inspect |
Chaining Matchers
Some matchers “unwrap” values:
be_some()turnsOption(a)intoabe_ok()turnsResult(a, e)intoa
That’s why you can chain checks after them.
Explicit failures
Sometimes you need to explicitly return “pass” or “fail” from a branch of a
case expression. Use succeed() / fail_with("...") for that.
Imports
You can import individual matchers, or import the whole module and qualify
with matchers.. The examples in these docs assume you imported the matcher
functions you’re using.
Values
pub const be_at_least: fn(types.MatchResult(Int), Int) -> types.MatchResult(
Int,
)
Assert that an integer is at least a minimum value (>=).
Example
10
|> should
|> be_at_least(10)
|> or_fail_with("expected 10 to be at least 10")
Parameters
value_or_result: theMatchResult(Int)produced byshould(or a previous matcher)minimum: the minimum allowed value (inclusive)
Returns
A MatchResult(Int) preserving the integer for further chaining.
pub const be_at_most: fn(types.MatchResult(Int), Int) -> types.MatchResult(
Int,
)
Assert that an integer is at most a maximum value (<=).
Example
10
|> should
|> be_at_most(10)
|> or_fail_with("expected 10 to be at most 10")
Parameters
value_or_result: theMatchResult(Int)produced byshould(or a previous matcher)maximum: the maximum allowed value (inclusive)
Returns
A MatchResult(Int) preserving the integer for further chaining.
pub const be_between: fn(types.MatchResult(Int), Int, Int) -> types.MatchResult(
Int,
)
Assert that an integer is between two values (exclusive).
The value must be strictly greater than min and strictly less than max.
Example
5
|> should
|> be_between(1, 10)
|> or_fail_with("expected 5 to be between 1 and 10")
Parameters
value_or_result: theMatchResult(Int)produced byshould(or a previous matcher)min: lower bound (exclusive)max: upper bound (exclusive)
Returns
A MatchResult(Int) preserving the integer for further chaining.
pub const be_empty: fn(types.MatchResult(List(a))) -> types.MatchResult(
List(a),
)
Assert that a list is empty.
Example
[]
|> should
|> be_empty()
|> or_fail_with("expected empty list")
Parameters
value_or_result: theMatchResult(List(a))produced byshould(or a previous matcher)
Returns
A MatchResult(List(a)) preserving the list for further chaining.
pub const be_equal: fn(types.MatchResult(a), a) -> types.MatchResult(
a,
)
Assert that a value equals the expected value.
Uses Gleam’s structural equality (==).
Example
2 + 3
|> should
|> be_equal(5)
|> or_fail_with("2 + 3 should equal 5")
Parameters
value_or_result: theMatchResult(a)produced byshould(or a previous matcher)expected: the value you expect the actual value to equal
Returns
A MatchResult(a):
- On success, the original value is preserved for further chaining.
- On failure, the chain becomes failed and later matchers are skipped.
pub const be_error: fn(types.MatchResult(Result(a, b))) -> types.MatchResult(
b,
)
Assert that a Result is Error and extract the error value.
If the assertion passes, the error value is passed to subsequent matchers.
Example
Error("nope")
|> should
|> be_error()
|> be_equal("nope")
|> or_fail_with("expected Error(\"nope\")")
Parameters
value_or_result: theMatchResult(Result(a, e))produced byshould(or a previous matcher)
Returns
A MatchResult(e) containing the unwrapped error value on success.
pub const be_false: fn(types.MatchResult(Bool)) -> types.MatchResult(
Bool,
)
Assert that a value is False.
Example
False
|> should
|> be_false()
|> or_fail_with("expected False")
Parameters
value_or_result: theMatchResult(Bool)produced byshould(or a previous matcher)
Returns
A MatchResult(Bool) preserving the boolean for further chaining.
pub const be_greater_than: fn(types.MatchResult(Int), Int) -> types.MatchResult(
Int,
)
Assert that an integer is greater than a threshold.
Example
10
|> should
|> be_greater_than(0)
|> or_fail_with("expected 10 to be greater than 0")
Parameters
value_or_result: theMatchResult(Int)produced byshould(or a previous matcher)threshold: the value the actual integer must be greater than
Returns
A MatchResult(Int) preserving the integer for further chaining.
pub const be_greater_than_float: fn(
types.MatchResult(Float),
Float,
) -> types.MatchResult(Float)
Assert that a float is greater than a threshold.
Example
0.5
|> should
|> be_greater_than_float(0.0)
|> or_fail_with("expected 0.5 to be greater than 0.0")
Parameters
value_or_result: theMatchResult(Float)produced byshould(or a previous matcher)threshold: the value the actual float must be greater than
Returns
A MatchResult(Float) preserving the float for further chaining.
pub const be_in_range: fn(types.MatchResult(Int), Int, Int) -> types.MatchResult(
Int,
)
Assert that an integer is within a range (inclusive).
The value must be >= min and <= max.
Example
10
|> should
|> be_in_range(0, 100)
|> or_fail_with("expected 10 to be in range 0..100")
Parameters
value_or_result: theMatchResult(Int)produced byshould(or a previous matcher)min: lower bound (inclusive)max: upper bound (inclusive)
Returns
A MatchResult(Int) preserving the integer for further chaining.
pub const be_less_than: fn(types.MatchResult(Int), Int) -> types.MatchResult(
Int,
)
Assert that an integer is less than a threshold.
Example
10
|> should
|> be_less_than(100)
|> or_fail_with("expected 10 to be less than 100")
Parameters
value_or_result: theMatchResult(Int)produced byshould(or a previous matcher)threshold: the value the actual integer must be less than
Returns
A MatchResult(Int) preserving the integer for further chaining.
pub const be_less_than_float: fn(types.MatchResult(Float), Float) -> types.MatchResult(
Float,
)
Assert that a float is less than a threshold.
Example
0.5
|> should
|> be_less_than_float(1.0)
|> or_fail_with("expected 0.5 to be less than 1.0")
Parameters
value_or_result: theMatchResult(Float)produced byshould(or a previous matcher)threshold: the value the actual float must be less than
Returns
A MatchResult(Float) preserving the float for further chaining.
pub const be_none: fn(types.MatchResult(option.Option(a))) -> types.MatchResult(
Nil,
)
Assert that an Option is None.
Example
None
|> should
|> be_none()
|> or_fail_with("expected None")
Parameters
value_or_result: theMatchResult(Option(a))produced byshould(or a previous matcher)
Returns
A MatchResult(Nil) that continues the chain with Nil on success.
pub const be_ok: fn(types.MatchResult(Result(a, b))) -> types.MatchResult(
a,
)
Assert that a Result is Ok and extract its value.
If the assertion passes, the Ok value is passed to subsequent matchers.
This enables chaining like be_ok() |> be_equal(42).
Example
Ok("hello")
|> should
|> be_ok()
|> be_equal("hello")
|> or_fail_with("expected Ok(\"hello\")")
Parameters
value_or_result: theMatchResult(Result(a, e))produced byshould(or a previous matcher)
Returns
A MatchResult(a) containing the unwrapped Ok value on success.
pub const be_some: fn(types.MatchResult(option.Option(a))) -> types.MatchResult(
a,
)
Assert that an Option is Some and extract its value.
If the assertion passes, the inner value is passed to subsequent matchers.
This enables chaining like be_some() |> be_equal(42).
Example
Some(42)
|> should
|> be_some()
|> be_equal(42)
|> or_fail_with("expected Some(42)")
Parameters
value_or_result: theMatchResult(Option(a))produced byshould(or a previous matcher)
Returns
A MatchResult(a):
- On
Some(value), the chain continues with the unwrappedvalue. - On
None, the chain becomes failed and later matchers are skipped.
pub const be_true: fn(types.MatchResult(Bool)) -> types.MatchResult(
Bool,
)
Assert that a value is True.
Example
True
|> should
|> be_true()
|> or_fail_with("expected True")
Parameters
value_or_result: theMatchResult(Bool)produced byshould(or a previous matcher)
Returns
A MatchResult(Bool) preserving the boolean for further chaining.
pub const clear_snapshot: fn(String) -> Result(Nil, String)
Delete a snapshot file.
Use this to force regeneration of a snapshot on the next test run.
Example
let path = "./test/tmp/clear_snapshot_example.snap"
// Setup: create a snapshot file (no assertions during setup)
use _ <- result.try(
file.write(path, "hello") |> result.map_error(file.error_to_string),
)
clear_snapshot(path)
|> should
|> be_equal(Ok(Nil))
|> or_fail_with("expected clear_snapshot to succeed")
Parameters
snapshot_path: the file path to delete
Returns
Result(Nil, String):
Ok(Nil)if the snapshot was deleted (or didn’t exist)Error(message)if deletion failed
pub const clear_snapshots_in_directory: fn(String) -> Result(
Int,
String,
)
Delete all snapshot files in a directory.
Deletes all files with the .snap extension in the given directory.
Example
let directory = "./test/tmp/clear_snapshots_in_directory_example"
let a = directory <> "/a.snap"
let b = directory <> "/b.snap"
// Setup: create two snapshot files (no assertions during setup)
use _ <- result.try(
file.write(a, "a") |> result.map_error(file.error_to_string),
)
use _ <- result.try(
file.write(b, "b") |> result.map_error(file.error_to_string),
)
clear_snapshots_in_directory(directory)
|> should
|> be_equal(Ok(2))
|> or_fail_with("expected two deleted snapshots")
Parameters
directory: the directory to scan (non-recursively)
Returns
Result(Int, String):
Ok(count)with the number of.snapfiles deletedError(message)if deletion failed
pub const contain: fn(types.MatchResult(List(a)), a) -> types.MatchResult(
List(a),
)
Assert that a list contains a specific item.
Example
[1, 2, 3]
|> should
|> contain(2)
|> or_fail_with("expected list to contain 2")
Parameters
value_or_result: theMatchResult(List(a))produced byshould(or a previous matcher)expected_item: the item that must be present in the list
Returns
A MatchResult(List(a)) preserving the list for further chaining.
pub const contain_string: fn(types.MatchResult(String), String) -> types.MatchResult(
String,
)
Assert that a string contains a substring.
Example
"hello world"
|> should
|> contain_string("world")
|> or_fail_with("expected substring match")
Parameters
value_or_result: theMatchResult(String)produced byshould(or a previous matcher)substring: required substring that must be present
Returns
A MatchResult(String) preserving the string for further chaining.
pub const end_with: fn(types.MatchResult(String), String) -> types.MatchResult(
String,
)
Assert that a string ends with a suffix.
Example
"hello.gleam"
|> should
|> end_with(".gleam")
|> or_fail_with("expected .gleam suffix")
Parameters
value_or_result: theMatchResult(String)produced byshould(or a previous matcher)suffix: required ending substring
Returns
A MatchResult(String) preserving the string for further chaining.
pub fn fail_with(
message message: String,
) -> types.AssertionResult
Explicitly fail a test with a message.
Use this when you need to fail a test in a conditional branch where the normal matcher chain doesn’t apply.
Example
Ok(case 1 + 1 {
2 -> succeed()
_ -> fail_with("expected 1 + 1 to be 2")
})
When to Use
- In
casebranches that represent unexpected states - When testing that something does NOT happen
- As a placeholder for unimplemented test branches
Returns
An AssertionResult you can wrap in Ok(...) from a test body.
If you want to abort a test immediately (rather than “failing a matcher”),
return Error("...") from the test body instead.
pub const have_length: fn(types.MatchResult(List(a)), Int) -> types.MatchResult(
List(a),
)
Assert that a list has a specific length.
Example
[1, 2, 3]
|> should
|> have_length(3)
|> or_fail_with("expected list length 3")
Parameters
value_or_result: theMatchResult(List(a))produced byshould(or a previous matcher)expected_length: the exact length the list must have
Returns
A MatchResult(List(a)) preserving the list for further chaining.
pub const match_regex: fn(types.MatchResult(String), String) -> types.MatchResult(
String,
)
Assert that a string matches a regular expression.
The pattern is compiled using gleam/regexp.from_string, and the assertion
passes if it matches anywhere in the string. Use ^...$ to require a
full match.
If the pattern is invalid, this matcher fails (with an error message).
Example
"user-123"
|> should
|> match_regex("^user-\\d+$")
|> or_fail_with("expected an id like user-123")
pub const match_snapshot: fn(types.MatchResult(String), String) -> types.MatchResult(
String,
)
Assert that a string matches the content of a snapshot file.
- If snapshot doesn’t exist: creates it and passes
- If snapshot exists and matches: passes
- If snapshot exists but doesn’t match: fails
To update a snapshot: delete the file and re-run the test.
Example
let path = "./test/tmp/match_snapshot_example.snap"
"hello"
|> should
|> match_snapshot(path)
|> or_fail_with("expected snapshot match")
Parameters
value_or_result: theMatchResult(String)produced byshould(or a previous matcher)snapshot_path: file path used to store/compare the snapshot
Returns
A MatchResult(String) preserving the string for further chaining.
pub const match_snapshot_inspect: fn(types.MatchResult(a), String) -> types.MatchResult(
a,
)
Assert that any value matches a snapshot (using string.inspect).
Serializes the value using string.inspect and compares against
the stored snapshot. Useful for testing complex data structures.
Example
let path = "./test/tmp/match_snapshot_inspect_example.snap"
Some(1)
|> should
|> match_snapshot_inspect(path)
|> or_fail_with("expected inspect snapshot match")
Parameters
value_or_result: theMatchResult(value)produced byshould(or a previous matcher)snapshot_path: file path used to store/compare the snapshot
Returns
A MatchResult(value) preserving the unwrapped value for further chaining.
pub const not_contain: fn(types.MatchResult(List(a)), a) -> types.MatchResult(
List(a),
)
Assert that a list does not contain a specific item.
Example
["a", "b", "c"]
|> should
|> not_contain("d")
|> or_fail_with("expected list to not contain \"d\"")
Parameters
value_or_result: theMatchResult(List(a))produced byshould(or a previous matcher)unexpected_item: the item that must not be present in the list
Returns
A MatchResult(List(a)) preserving the list for further chaining.
pub const not_equal: fn(types.MatchResult(a), a) -> types.MatchResult(
a,
)
Assert that a value does not equal the unexpected value.
Example
10 + 3
|> should
|> not_equal(3)
|> or_fail_with("10 + 3 should not equal 3")
Parameters
value_or_result: theMatchResult(a)produced byshould(or a previous matcher)unexpected: the value you expect the actual value to not equal
Returns
A MatchResult(a):
- On success, the original value is preserved for further chaining.
- On failure, the chain becomes failed and later matchers are skipped.
pub fn or_fail_with(
result result: types.MatchResult(a),
message message: String,
) -> Result(types.AssertionResult, String)
Complete a matcher chain and provide a failure message.
This is the terminal operation that ends every matcher chain. It
converts the MatchResult into an AssertionResult that the test runner
understands.
If the matcher passed, returns AssertionOk. If it failed, returns
AssertionFailed with the provided message.
Example
2 + 3
|> should
|> be_equal(5)
|> or_fail_with("2 + 3 should equal 5")
Parameters
result: theMatchResult(a)produced byshouldand matchersmessage: message to show if the chain failed
Returns
A Result(AssertionResult, String) so test bodies can return it directly:
Ok(AssertionOk)when the chain passedOk(AssertionFailed(...))when the chain failed
(This function currently never returns Error, but the Result shape keeps
test bodies uniform for dream_test/unit: fn() { ... } -> Result(AssertionResult, String).)
Writing Good Messages
Good failure messages explain what should have happened:
- ✓ “User should be authenticated after login”
- ✓ “Cart total should include tax”
- ✗ “wrong”
- ✗ “failed”
pub fn should(value value: a) -> types.MatchResult(a)
Start a matcher chain.
This wraps a value so it can be piped through matchers.
Every matcher chain starts with should.
Example
True
|> should
|> be_true()
|> or_fail_with("expected True")
Parameters
value: any value you want to make assertions about
Returns
A MatchResult(a) containing value. Subsequent matchers will either:
- preserve this value (for “checking” matchers), or
- transform it (for “unwrapping” matchers like
be_some/be_ok).
pub const start_with: fn(types.MatchResult(String), String) -> types.MatchResult(
String,
)
Assert that a string starts with a prefix.
Example
"hello world"
|> should
|> start_with("hello")
|> or_fail_with("expected string to start with \"hello\"")
Parameters
value_or_result: theMatchResult(String)produced byshould(or a previous matcher)prefix: required starting substring
Returns
A MatchResult(String) preserving the string for further chaining.
pub fn succeed() -> types.AssertionResult
Explicitly mark a matcher chain as successful.
Use this when you need to explicitly succeed in a conditional branch,
as the counterpart to fail_with.
Example
Ok(case 1 + 1 {
2 -> succeed()
_ -> fail_with("expected 1 + 1 to be 2")
})
When to Use
- In
casebranches where success is the expected outcome - When all branches of a case must return an
AssertionResult - To make intent explicit rather than relying on implicit success
Returns
AssertionOk.