Data and fixtures
Parameterize tests
data users = load("data/users.json")
test "A named user" tags ["data"] for each user in users {
expect len(user.name) > 0
}
Each row yields a result such as A named user [1]. Fixtures and browser isolation apply per row. The dataset must be a non-empty list; empty or malformed data is an input error, not a passing test.
load() resolves relative paths from the current module, independent of the process working directory. Path() can be passed to load().
CSV values are strings. JSON/YAML preserve supported scalar types. Convert CSV explicitly with int()/float() or compare strings. YAML is loaded safely without arbitrary object construction.
Fixtures and lifecycle
fixture session {
setup {
var baseUrl: String = "http://127.0.0.1:8765"
log "Session ready"
}
teardown {
log "Session closed"
}
}
test "Session" using [session] {
expect baseUrl contains "127.0.0.1"
}
- Set up listed fixtures from left to right.
- Expose successful setup bindings to the test.
- Run the test body.
- Tear down started fixtures from right to left.
- Close the test's HTTP client and browser.
Started fixtures are cleaned up even if their setup failed. Teardown can access bindings created before that failure; cleanup must account for resources not fully initialized. A teardown failure marks the case failed and preserves earlier reported failures. Skipping a test also triggers cleanup.
Fixtures have independent module environments. They do not implicitly depend on another fixture's bindings. Duplicate exported bindings are errors. Suite/session scopes, fixture dependency injection and lazy fixture resolution are future work.
Browser creation is lazy: API-only tests never launch one. Each test or row gets a fresh browser instance. Flows receive fixture values explicitly as parameters.