dillonkearns/elm-snapshot/1.1.0

NOTE: the latest version is 1.1.1

Snapshot

Snapshot testing framework for Elm.

module Snapshots exposing (run)


import Json.Encode
import Pages.Script exposing (Script)
import Snapshot


run : Script
run =
    Snapshot.run "Snapshots"
        [ Snapshot.test "greeting" <|
            \() -> "Hello, " ++ "World" ++ "!"
        , Snapshot.json "user" <|
            \() ->
                Json.Encode.object
                    [ ( "name", Json.Encode.string "Alice" )
                    , ( "age", Json.Encode.int 30 )
                    ]
        ]

Run with elm-pages run src/Snapshots.elm --approve=prompt and press Enter to approve each snapshot. Commit the .approved files to git.

type Test

An opaque type representing a snapshot test or group of tests.

Create tests using test, json, custom, or their task* variants. Group related tests using describe.

run : String -> List Test -> Script

Run a list of snapshot tests as an elm-pages Script.

-- In your Snapshots.elm script:
run : Script
run =
    Snapshot.run "Snapshots"
        [ Snapshot.test "greeting" <| \() -> greet "World"
        , Snapshot.json "config" <| \() -> encodeConfig config
        ]

The first argument is the script name (typically matching the module name). This organizes snapshots into snapshots/<ScriptName>/ directories, allowing multiple snapshot scripts in the same project.

Supports CLI options:

  • --approve=all - Approve all new/changed snapshots
  • --approve=prompt - Interactive per-snapshot approval
  • --approve-only "test name" - Approve a specific test
  • --ci - Compact output for CI environments
  • --list - List all test names without running
  • --prune - Remove obsolete snapshot files
  • --reporter <tool> - Open diff tool for failures (code, opendiff, meld, ksdiff, kdiff3, diff, or any command)
test : String -> (() -> String) -> Test

Create a snapshot test that compares string output.

Snapshot.test "greeting" <|
    \() ->
        greet "World"

This is the most common form - use when your function already returns a String.

json : String -> (() -> Value) -> Test

Create a snapshot test for JSON values with pretty printing.

Snapshot.json "user data" <|
    \() ->
        User.encode user

Uses 2-space indentation. Keys are sorted alphabetically for deterministic output.

custom : Printer a -> String -> (() -> a) -> Test

Create a snapshot test with a custom printer.

Snapshot.custom myXmlPrinter "config file" <|
    \() ->
        buildConfig options

Use this when you need a custom a -> String conversion.

checkedTest : String -> (() -> Result String String) -> Test

Create a snapshot test that validates before snapshotting.

Snapshot.checkedTest "parsed config" <|
    \() ->
        Config.parse rawInput
            |> Result.map Config.toString

If the Result is Err, the test fails with that error message and no snapshot is written. If Ok, the value is snapshotted normally.

This is useful when test setup might fail (parsing, validation, etc.) and you want to catch those failures before snapshotting.

checkedJson : String -> (() -> Result String Value) -> Test

Create a JSON snapshot test that validates before snapshotting.

Snapshot.checkedJson "decoded user" <|
    \() ->
        Json.Decode.decodeString userDecoder jsonString
            |> Result.mapError Json.Decode.errorToString
checkedCustom : Printer a -> String -> (() -> Result String a) -> Test

Create a snapshot test with a custom printer that validates before snapshotting.

Snapshot.checkedCustom xmlPrinter "parsed xml" <|
    \() ->
        Xml.parse rawXml
            |> Result.mapError Xml.errorToString
taskTest : String -> BackendTask FatalError String -> Test

Create a BackendTask-powered snapshot test for string output.

Snapshot.taskTest "elm.json deps" <|
    File.rawFile "elm.json"
        |> BackendTask.allowFatal

Use this for tests that need IO (file reading, HTTP, etc).

taskJson : String -> BackendTask FatalError Value -> Test

Create a BackendTask-powered snapshot test for JSON values.

Snapshot.taskJson "api response" <|
    Http.get url decoder
        |> BackendTask.allowFatal

Uses 2-space indentation. Keys are sorted alphabetically for deterministic output.

taskCustom : Printer a -> String -> BackendTask FatalError a -> Test

Create a BackendTask-powered snapshot test with a custom printer.

Snapshot.taskCustom myPrinter "fetched data" <|
    fetchData
        |> BackendTask.allowFatal
withScrubbers : List Scrubber -> Test -> Test

Add scrubbers to a test with non-deterministic output.

Snapshot.test "log entry" (\() -> formatLog entry)
    |> Snapshot.withScrubbers [ Scrubber.timestamp ]


Snapshot.json "api response" (\() -> encodeResponse resp)
    |> Snapshot.withScrubbers [ Scrubber.guid, Scrubber.timestamp ]

Scrubbers run after printing, replacing patterns like timestamps and GUIDs with stable placeholders.

describe : String -> List Test -> Test

Group related tests together.

Snapshot.describe "Date formatting"
    [ Snapshot.test "ISO format" <|
        \() -> Date.toIsoString date
    , Snapshot.test "human readable" <|
        \() -> Date.toHumanString date
    ]

Test names are prefixed with the group name, separated by " / ". Snapshot files are stored in subdirectories matching the group structure.

Run only this test (and any other tests marked with only).

Snapshot.only <|
    Snapshot.test "focus on this" <|
        \() -> workInProgress

When any test is marked with only, all tests without only will be skipped. Use this during development to focus on specific tests.

Important: Using only causes the test suite to fail, preventing you from accidentally committing focused tests to CI.

Note: skip takes precedence over only - a skipped test won't run even if it's inside an only block.

todo : String -> Test

A placeholder for a test you intend to write later.

Snapshot.todo "handle edge case where input is empty"

The test will be reported as a todo item. This is useful for jotting down test ideas without implementing them immediately.

Important: Using todo causes the test suite to fail, preventing you from accidentally committing incomplete tests to CI.