require('@jess/test'): { new, expect }A built-in module, typed as Module__jess_test. A test module builds a suite, registers cases on it, and returns it; jess test runs the suite and prints the report, and a script can call suite.run() itself. Every case runs inside a log.capture, so what it logged ends up in its result instead of on stderr.
--!strict
local test = require '@jess/test'
local expect = test.expect
local suite = test.new()
local greeter = require '@greeter'
suite.describe('greet', function()
local names: { string }
suite.beforeEach(function()
names = { 'ada', 'grace' }
end)
suite.it('greets by name', function()
expect(greeter.greet(names[1])).toBe 'Hello, ada.'
end)
suite.it('greets everyone in order', function()
expect(greeter.greetAll(names)).toEqual { 'Hello, ada.', 'Hello, grace.' }
end)
suite.it('refuses an empty name', function()
expect(function() greeter.greet '' end).toThrow 'empty'
end)
end)
return suite
test.new§
test.new() -> JessTestSuiteAn empty suite. Its functions are plain functions, not methods: suite.it(...), not suite:it(...).
JessTestSuite.describe§
suite.describe(name: string, body: () -> ()) -> ()A group. body runs at once and registers cases and hooks; a case's full name is its groups' names and its own, joined with / . Groups nest.
JessTestSuite.it§
suite.it(name: string, body: () -> ()) -> ()One case. It passes when its beforeEach hooks, its body, and its afterEach hooks all return without an error.
JessTestSuite.beforeEach, afterEach§
suite.beforeEach(body: () -> ()) -> ()Hooks for every case in the current group and the groups inside it. beforeEach hooks run outermost first; afterEach hooks run innermost first, and they run even when setup or the body failed. Every failure is in the case's error, one traceback each.
JessTestSuite.run§
suite.run() -> JessTestReportRuns every case in registration order and returns { passed, failed, tests }, each test a { name, passed, error, logs }. Nothing is printed; that's the host's job. Cases can't be added while the suite runs.
test.expect§
test.expect(actual: unknown) -> JessTestExpectationAn assertion on actual. Each check raises with what it saw and what it wanted, tables rendered sorted and shortened: expected { 1, name = "a" } to equal { name = "b" }.
| Check | Passes when |
|---|---|
toBe(expected) | rawequal(actual, expected). |
toEqual(expected) | Deep equality: same keys, values compared the same way, cycles handled. Tables only compare with tables; anything else is rawequal. |
toBeTruthy(), toBeFalsy(), toBeNil() | What they say. |
toContain(item) | actual is a string containing item, or a list with an element that toEquals it. |
toBeCloseTo(expected, tolerance?) | actual is a number within tolerance (default 1e-9) of expected, for floating-point results that needn't be exact. |
toThrow(contains?) | actual is a function that raises, and its message contains contains when given. The one place a test catches an error on purpose. |
Running§
jess test a.jsl b.jsl loads each module, runs the suite it returns, and prints one report; it exits non-zero when anything failed. From Rust, jess::lua::testing::run does the same and hands back the report.
Types§
type JessTestSuite = {
describe: (name: string, body: () -> ()) -> (),
it: (name: string, body: () -> ()) -> (),
beforeEach: (body: () -> ()) -> (),
afterEach: (body: () -> ()) -> (),
run: () -> JessTestReport,
}
type JessTestResult = { name: string, passed: boolean, error: string?, logs: { JessLogRecord } }
type JessTestReport = { passed: number, failed: number, tests: { JessTestResult } }