Configuration
Scriptorium.Quill lets you configure every test and list with a TestConfig -> TestConfig function. Configuration is inherited from the global level down through testList to individual tests, with each level able to override its parent.
open Scriptorium.QuillTestConfig
Section titled “TestConfig”type TestConfig = { Skip: bool TimeoutMs: int option SlowThresholdMs: int }| Field | Default | Description |
|---|---|---|
Skip | false | When true, the test is skipped at runtime |
TimeoutMs | Some 5000 | Maximum allowed duration in ms. None = no timeout |
SlowThresholdMs | 300 | Tests slower than this show their time in yellow |
You never construct TestConfig directly — use the built-in configurers and compose them with >>.
Built-in configurers
Section titled “Built-in configurers”skipIf
Section titled “skipIf”skipIf (condition: bool) : TestConfig -> TestConfigSkips the test if condition is true. The test body does not execute; the result is Skipped.
test ("conditional skip", skipIf (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)), fun _ -> // Only runs on non-Windows assertThat true isTrue)skipIfJavaScript
Section titled “skipIfJavaScript”skipIfJavaScript : TestConfig -> TestConfigSkips when compiled to JavaScript (Fable).
test ("uses .NET DateTime", skipIfJavaScript, fun _ -> assertThat System.DateTime.Now.Year (isGreaterThan 2020))skipIfDotNet
Section titled “skipIfDotNet”skipIfDotNet : TestConfig -> TestConfigSkips when running on .NET (i.e. not compiled by Fable).
test ("uses browser fetch", skipIfDotNet, fun _ -> assertThat window isNotNull)timeout
Section titled “timeout”timeout (ms: int) : TestConfig -> TestConfigSets a timeout for the test. Async tests that exceed the timeout fail with "Test timed out after Nms". Synchronous tests are checked retroactively after the body returns.
testAsync ("slow network call", timeout 10_000, fun _ -> async { let! result = httpGetAsync "https://api.example.com/data" assertThat result.StatusCode (isEqualTo 200)})noTimeout
Section titled “noTimeout”noTimeout : TestConfig -> TestConfigRemoves the timeout entirely. The test can run as long as it needs.
testAsync ("very slow integration test", noTimeout, fun _ -> async { let! result = runFullPipelineAsync () assertThat result.Success isTrue})slowThreshold
Section titled “slowThreshold”slowThreshold (ms: int) : TestConfig -> TestConfigSets the threshold above which a passing test’s duration is displayed in yellow. Default is 300 ms.
testList ("integration suite", slowThreshold 1000, [ // Tests in this list are only highlighted as slow if > 1000ms test ("database roundtrip", fun _ -> ...)])Composing configurers
Section titled “Composing configurers”Configurers are plain functions; compose them with >>:
test ("platform + timeout", skipIfJavaScript >> timeout 2000, fun _ -> // Only runs on .NET, with a 2s timeout runHeavyComputation ())Configuration inheritance
Section titled “Configuration inheritance”Configuration flows from global, list, test. Each level can override its parent’s values.
Runner.runTestsWith(configurer, tests) global └── testList(name, configurer, ...) list override └── test(name, configurer, ...) test overrideWhen a child configurer is applied, it receives the configuration inherited from its parent. The final configuration for a test is:
testConfig = testConfigurer (listConfigurer (globalConfig))Example: timeout inheritance
Section titled “Example: timeout inheritance”Runner.runTestsWith(timeout 5000, [ // global: 5s testList ("group", timeout 2000, [ // list overrides: 2s testAsync ("fast", fun _ -> async { do! Async.Sleep 100 }) // inherits 2s — passes testAsync ("slow", timeout 10000, fun _ -> async { // test overrides: 10s — passes do! Async.Sleep 5000 }) testAsync ("too slow", fun _ -> async { // inherits 2s — fails after 2s do! Async.Sleep 3000 }) ])])