Test DSL
The test DSL lives on the Test static class. Bring it into scope with open type:
open type Scriptorium.Quill.TestTest groups
Section titled “Test groups”testList
Section titled “testList”Groups tests under a named list. Lists can be nested to any depth. The list name becomes part of the path for all contained tests.
testList ("User service", [ testList ("create", [ test ("creates with valid data", fun _ -> ...) test ("rejects empty name", fun _ -> ...) ]) testList ("delete", [ test ("removes the record", fun _ -> ...) ])])A configurer on a list propagates to all children (see Configuration):
testList ("integration tests", skipIfJavaScript, [ test ("uses .NET filesystem", fun _ -> ...) test ("reads environment", fun _ -> ...)])xtestList — pending list
Section titled “xtestList — pending list”All children are marked as pending, regardless of their individual marks. Their bodies never execute.
xtestList ("WIP features", [ test ("feature A", fun _ -> ...) // pending, body never runs test ("feature B", fun _ -> ...) // pending, body never runs])ftestList — focused list
Section titled “ftestList — focused list”All children run as focused tests. Sibling tests and lists outside this list are skipped.
ftestList ("focused group", [ test ("a", fun _ -> ...) // runs test ("b", fun _ -> ...) // runs])// other tests in the suite are skippedSequential tests
Section titled “Sequential tests”testSequenced
Section titled “testSequenced”By default, testList runs all children in parallel. testSequenced runs them one after another, in source order. Use this when tests have shared mutable state or must execute in a specific sequence.
testSequenced ("database lifecycle", [ test ("create table", fun _ -> createTable ()) test ("insert rows", fun _ -> insertRows ()) test ("verify count", fun _ -> assertThat (rowCount ()) (isEqualTo 3)) test ("drop table", fun _ -> dropTable ())])Sync tests
Section titled “Sync tests”A normal synchronous test. The body receives a TestContext but can ignore it with _:
test ("basic equality", fun _ -> assertThat 42 (isEqualTo 42))
// With a configurertest ("platform only", skipIfJavaScript, fun _ -> assertThat System.Environment.MachineName isNotNull)xtest — pending
Section titled “xtest — pending”A pending test. The body is never executed. The test appears in output as * (yellow).
xtest ("not implemented yet", fun _ -> assertThat 1 (isEqualTo 99) // never runs)ftest — focused
Section titled “ftest — focused”A focused test. When any focused test is present, all non-focused tests produce Skipped results.
ftest ("I'm debugging this", fun _ -> assertThat result (isEqualTo expected))Async tests
Section titled “Async tests”testAsync
Section titled “testAsync”An async test. The default timeout is 5 000 ms. A test that exceeds its timeout fails with "Test timed out after Nms".
testAsync ("fetches data", fun content -> async { let! data = fetchDataAsync () assertThat data.Length (isGreaterThan 0)})
// Without TestContext (simple form)testAsync ("simple async", async { do! Async.Sleep 10 assertThat true isTrue})xtestAsync — pending async
Section titled “xtestAsync — pending async”Marks an async test as pending. The body never executes.
xtestAsync ("pending feature", async { // never runs})ftestAsync — focused async
Section titled “ftestAsync — focused async”Focuses an async test.
ftestAsync ("I'm debugging this async path", fun _ -> async { let! result = someAsyncComputation () assertThat result isExpected})Placeholder tests
Section titled “Placeholder tests”A named placeholder with no body. Appears as * (yellow/pending) in output. Use it to describe tests you plan to write later.
testList ("payment processor", [ test ("charges the card", fun _ -> ...) todo "handles declined cards" todo "handles network timeout" todo "retries on transient error"])