Test.Runner.Effectful

A test runner that supports running Tasks.

Config

type alias Config =
{ termConfig : Maybe Configuration
, stdout : Writable Bytes
, stderr : Writable Bytes
}

Configuration for the test runner. You can get this from initialize as part of your application's init, or if you want fine-grained control over what the package has access to, you can create it yourself.

initialize : Environment -> (Config -> Task a) -> Task a

A convenience function that acquires Terminal permission and packages stdout/stderr from the environment into a Config.

Note: This gives unlimited subsystem permissions to the package. If you want more control, create your own Config record instead.

Node.defineSimpleProgram <| \env ->
    Effectful.initialize env <| \config ->
        Effectful.run config myTests
            |> Node.endSimpleProgram

Running Tests

run : Config -> Test -> Task Never {}

Run your effectful test suite.

Returns a Task that outputs test results and sets the exit code. Run it like any other task. For example, in a Node.SimpleProgram:

main =
    Node.defineSimpleProgram <| \env ->
        Effectful.initialize env <| \config ->
            Node.endSimpleProgram (Effectful.run config myTests)
runWithOptions : Config -> Options -> Test -> Task Never {}

Customize a test run with Options.

type alias Options = { runs : Int, seed : Seed }

Options to customize your test run.

  • runs: how many times a fuzz test is run with different inputs.
  • seed: used to generate random input in fuzz tests. A test suite run with the same seed will generate the same fuzz values.

Awaiting Tasks

await : String -> Task error a -> (a -> Test) -> Test

Wait for a task to resolve before running a test.

await "Current time" Time.now <| \now ->
    test "is not Jan 1, 1970" <| \_ ->
        Expect.notEqual (Time.millisToPosix 0) now

If the task fails, the inner test won't run and the test suite will fail. If you want to test the error condition of a task, use awaitError.

You can nest as many awaits as you want:

await "task a" (Task.succeed "a") <| \a ->
await "task b" (Task.succeed "b") <| \b ->
    test "are not equal" <| \_ ->
        Expect.notEqual a b
awaitError : String -> Task error a -> (error -> Test) -> Test

Test the error state of a task.

awaitError "An expected failure" (Task.fail "oopsy") <| \error ->
    test "is an oopsy" \_ ->
        Expect.equal "oopsy" error

If the task does not fail, the inner test won't run and the test suite will fail.

These can be nested just like (and alongside) await calls.

Defining Tests

type alias Test = Task Never (InternalTest {})

A test in an effectful test suite.

They can be created with test, fuzz, or several other functions in this module:

import Expect
import Test.Runner.Effectful exposing (test)

test "my test" <| \_ ->
    Expect.equal True True

The semantics are the same as a test from the core test package, except they can wrapped in one or more await or awaitError calls to verify the outcome of a Task:

import Expect
import Test.Runner.Effectful exposing (await, test)
import Time

await "The current time" Time.now <| \now ->
    test "is not Jan 1, 1970" <| \_ ->
        Expect.notEqual (Time.millisToPosix 0) now
test : String -> ({} -> Expectation) -> Test

Create a Test.

wrap : Test -> Test

Wrap a test from the core test library.

Test Organization

concat : Array Test -> Test

Group an array of Tests into one.

concat
    [ test "true is true" <| \_ ->
        Expect.equal True True
    , test "false is false" <| \_ ->
        Expect.equal False False
    ]
describe : String -> Array Test -> Test

Group an array of Tests with a description.

describe "Truisms"
    [ test "true is true" <| \_ ->
        Expect.equal True True
    , test "false is false" <| \_ ->
        Expect.equal False False
    ]
todo : String -> Test

Create a Test that is a "TODO" (not yet implemented).

The behavior and API mirrors todo from the core test package.

only : Test -> Test

Create a Test that causes other tests to be skipped, and only runs the given one.

The behavior and API mirrors only from the core test package.

Fuzz Testing

fuzz : Fuzzer a -> String -> (a -> Expectation) -> Test

Create a "fuzz test".

The behavior and API mirrors fuzz from the core test package.

fuzz2 :
Fuzzer a
-> Fuzzer b
-> String
-> (a -> b -> Expectation)
-> Test

Create a "fuzz test" using two random inputs.

The behavior and API mirrors fuzz2 from the core test package.

fuzz3 :
Fuzzer a
-> Fuzzer b
-> Fuzzer c
-> String
-> (a -> b -> c -> Expectation)
-> Test

Create a "fuzz test" using three random inputs.

The behavior and API mirrors fuzz3 from the core test package.