Expand description
Test helpers for Ocre apps, like Rails’ ActionDispatch::IntegrationTest
and ActiveSupport::Testing: a request client for the running app, the
test database, the server log, time travel and assertions.
Feature testing, native builds only: a generated app lists
ocre = { ..., features = ["testing"] } under [dev-dependencies], so the
module is in cargo test and never in the WebAssembly build.
§How request tests run
Handlers need workerd (D1, KV, Queues… exist only there), so request
tests talk HTTP to the real runtime. ocre test --e2e:
- creates a fresh local D1 database in
.wrangler/test-state(the development data in.wrangler/stateis untouched), applies the migrations and loads the fixtures oftests/fixtures/, - starts one
cf devon that state for the whole run, logging to.wrangler/test-state/dev.log, - runs
cargo test -- --ignoredwithTEST_URL,TEST_STATEandTEST_LOGset. In an Ocre app,#[ignore]marks the tests that need the runtime: plaincargo test(andocre test) skips them.
// tests/posts.rs
use ocre::testing::Client;
#[test]
#[ignore = "request test: run with `ocre test --e2e`"]
fn creates_a_post() {
let mut client = Client::new();
let created = client.post("/posts", &[("title", "Hello"), ("body", "First post")]);
created.assert_redirect_to("/posts/1");
assert_eq!(client.flash("notice").as_deref(), Some("Post was successfully created."));
client.follow_redirect(&created).assert_status(200).assert_contains("Hello");
}There are no per-test transactions (Rails’ transactional tests): the
database belongs to the cf dev process, which the test process reaches
only over HTTP or through wrangler. The database is fresh for each run;
tests running in parallel share it, so they create their own records
(factories give unique values) and assert on them rather than on global
counts, or run with -- --test-threads=1.
Structs§
- Broadcast
- A message broadcast to a realtime channel, from
Client::broadcasts. - Client
- An HTTP client for request tests, with a cookie jar, like a browser tab (Rails’ integration session).
- Enqueued
Job - A job sent to a queue, from
Client::jobs. - Jobs
- Jobs the app enqueued and ran, from
Client::jobs. - Log
- The test server’s log (
cf devoutput:console.log, job and cron lines, errors), read from the position ofLog::markon. - Performed
Job - A job run by the queue consumer, from
Client::jobs. - Response
- A response in a request test, with chainable assertions (Rails’
assert_response,assert_redirected_to,assert_match).
Constants§
- TEST_
LOG - Environment variable holding the path of the test server’s log.
- TEST_
STATE - Environment variable holding the local state directory of the test run (
.wrangler/test-state). - TEST_
URL - Environment variable holding the base URL of the server
ocre test --e2estarted.
Functions§
- assert_
changes - Asserts that
blockchanges whatexpressionreturns (Rails’assert_changes), and returns(before, after). - assert_
difference - Asserts that
blockchanges the numberexpressionreturns bydifference(Rails’assert_difference), and returns the block’s value. - assert_
no_ changes - Asserts that
blockleaves whatexpressionreturns unchanged (Rails’assert_no_changes). - assert_
no_ difference - Asserts that
blockleaves the numberexpressionreturns unchanged (Rails’assert_no_difference). - block_
on - Runs a future to completion on the test thread:
asynchandlers, helpers andocre::passwordin plain unit tests (no async runtime runs outside workerd). It ispollster::block_on. - count
- Number of rows of
tablein the test database, forassert_difference. - eventually
- Retries
checkevery 100 ms for up to 30 seconds until it returnsSome, for effects that happen later: a queued job, a cron, a broadcast. - fixture
- The row of
tableloaded from the fixturelabel(Rails’posts(:first)). - fixture_
id - The
idof the fixture labelledlabel(Rails’users(:david).id): the loader oftests/fixtures/*.ymlgives a record without an explicitidthe CRC-32 of its label modulo 2^30 - 1, like Rails. - freeze_
time - Stops
crate::nowat the current second (Rails’freeze_time); returns it. - insert
- Inserts a row into
tableof the test database and returns itsid: what generated factories (tests/factories/) call. One wrangler call (about a second). - quote
valueas a SQL literal: strings quoted ('doubled), numbers as is, booleans as1/0, null asNULL, arrays and objects as JSON text.- redact
- Replaces values that change on every run by placeholders, so a snapshot
or an
assert_eq!on a whole page or JSON body is stable (Loco’scleanup_*filters): UUIDs become<UUID>, ISO 8601 dates and times (2026-01-01,2026-01-01T12:00:00Z,2026-01-01 12:00:00) become<DATE>, and runs of 32 or more hexadecimal or base64url characters (tokens, digests) become<TOKEN>. - sequence
- A unique number per call in the test process, for unique test data
(FactoryBot’s
sequence): 1, 2, 3… - sql
- Rows returned by
query, run on the test database (Rails’ActiveRecord::Base.connection.select_all). - travel
- Moves
crate::nowbysecondsfrom its current value and freezes it there (Rails’travel 1.day). - travel_
back - Returns
crate::nowto the real clock (Rails’travel_back). - travel_
to - Makes
crate::nowreturnunixon this thread untiltravel_back(Rails’travel_to, frozen). Each Rust test runs on its own thread, so other tests keep the real clock. Affects code running in the test process (models, helpers, JWT), not thecf devserver. - var
- A variable of the app under test: the environment variable
name, else its value in.dev.vars(the fileocre devloads), as the Worker sees it. Request tests use it for the secrets they sign with (a webhook’s).