Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
e39c782
Function for calculating hashes
lydell Jul 12, 2026
ab3e620
Handle recursion correctly
lydell Jul 13, 2026
97ca1a9
Explode into several functions
lydell Jul 13, 2026
d8853c4
Clean up
lydell Jul 13, 2026
b55c2cf
Helpful type alias
lydell Jul 13, 2026
ddc6515
Avoid spread
lydell Jul 13, 2026
9aa8630
Simplify API
lydell Jul 14, 2026
8dbc8fc
Use good old loops
lydell Jul 14, 2026
f15bd11
Comment
lydell Jul 14, 2026
8247f8f
Optimize regex
lydell Jul 14, 2026
e237e77
Make it all fit together but with TODOs
lydell Jul 15, 2026
00a2c96
WIP try to save outcomes of each test
lydell Jul 15, 2026
b8d667d
Store outcomes instead
lydell Jul 15, 2026
83b5411
Write down some plans
lydell Jul 15, 2026
a84beec
Fix outcomes key
lydell Jul 16, 2026
91f3653
Prepare for saving outcomes
lydell Jul 16, 2026
9712020
Pass along the metadata
lydell Jul 16, 2026
f11452d
Send new stuff back to the supervisor
lydell Jul 16, 2026
6b291a1
Require a single expectation
lydell Jul 16, 2026
be84039
Move previous run stuff to model
lydell Jul 16, 2026
c1e2a85
Start collecting newStuff
lydell Jul 16, 2026
72a015b
Write PreviousRun module
lydell Jul 16, 2026
5f13552
Detect fuzz test
lydell Jul 16, 2026
7fa5f5a
Add missing imports
lydell Jul 16, 2026
b402578
Filter out non-tests
lydell Jul 16, 2026
6bbf583
Fix issue where the same function is present in two different recursi…
lydell Jul 16, 2026
5ffe841
Temp time measurements
lydell Jul 16, 2026
073ede9
TODOs
lydell Jul 16, 2026
68e3dbc
Handle error when no fuzz tests
lydell Jul 16, 2026
374ff90
Fix isFuzzTest never being True
lydell Jul 16, 2026
9e6adca
Fix recursion with Tarjan
lydell Jul 17, 2026
f0edf35
Revert "Temp time measurements"
lydell Jul 17, 2026
2762336
Detect Debug.log
lydell Jul 17, 2026
9be3d54
Support Test.concat
lydell Jul 17, 2026
e4b118f
Support bare Test.todo
lydell Jul 17, 2026
759fbd7
Merge branch 'master' into hash
lydell Jul 21, 2026
2f20031
Merge branch 'master' into hash
lydell Jul 29, 2026
ffa8275
WIP use new API
lydell Aug 1, 2026
ec93f41
Merge branch 'master' into hash
lydell Aug 1, 2026
be3ba7c
Implement Debug.log and getHashes
lydell Aug 1, 2026
e9e0e8b
Work on running unit tests
lydell Aug 1, 2026
d56480e
Running UnitTest compiles
lydell Aug 1, 2026
4e6eddf
Fuzz tests compile
lydell Aug 1, 2026
41a93cf
foo -> checkTagged
lydell Aug 1, 2026
ff00185
Supervisor compiles
lydell Aug 2, 2026
fbbd204
Print which test the debug logs are from
lydell Aug 2, 2026
6abe2b2
Typed sends as well
lydell Aug 2, 2026
0ce6e02
Fix mistakes in code generation
lydell Aug 2, 2026
e27c31a
Fix flipped hasDebugLogs
lydell Aug 2, 2026
e3c6ce5
TODO comment about Debug.todo
lydell Aug 2, 2026
7b84761
Make room after debug logs
lydell Aug 2, 2026
e7af247
Reorder since send is sync on main thread
lydell Aug 2, 2026
56355a0
Keep track of next and finished separately
lydell Aug 2, 2026
4e296b7
Explain rounding
lydell Aug 2, 2026
826855c
Comments cleanup
lydell Aug 2, 2026
eca89d8
PreviousRun fixes
lydell Aug 2, 2026
e74e8ba
Fix debug logs compile error in cache file
lydell Aug 2, 2026
746e7cb
Optimize debug logs a bit
lydell Aug 2, 2026
9db94d8
index -> shouldSendBegin
lydell Aug 2, 2026
6d32633
Trawl cached at start
lydell Aug 2, 2026
15b5664
Fix filtering of non-tests
lydell Aug 2, 2026
f0ee7c8
elm-review
lydell Aug 2, 2026
76ff7d9
Remove Debug.log
lydell Aug 2, 2026
4f9dc4a
Resolve TODO comment
lydell Aug 2, 2026
060ff97
Fix crash when fuzz tests are too fast
lydell Aug 2, 2026
00fd248
Resolve TODO
lydell Aug 2, 2026
6bae8f5
Also expose durationFloat
lydell Aug 2, 2026
476565c
Add --unbuffered-logs
lydell Aug 2, 2026
40b9fdf
Update --workers docs
lydell Aug 2, 2026
939026f
Better default random seed
lydell Aug 2, 2026
a7cdf5d
Buffer debug logs before tests start
lydell Aug 2, 2026
7d60960
Use same seed as previous time if there was a fuzz failure
lydell Aug 2, 2026
c4fd5a1
Use Array instead of Dict for tests
lydell Aug 5, 2026
46944a1
Some comments
lydell Aug 5, 2026
c0d9c68
Fix hack for rerunFailure
lydell Aug 15, 2026
398b2fa
Stop using `formatLabels` from the lib
lydell Aug 16, 2026
9aab633
Updates for RunnerV2 module
lydell Aug 16, 2026
bbff04d
Updates for opaque RunnerV2 module
lydell Aug 16, 2026
5be0b97
Merge branch 'master' into hash
lydell Aug 16, 2026
ba39d96
Fix elm-review error
lydell Aug 16, 2026
6b2e704
Fix flaky tests
lydell Aug 16, 2026
1be7e8c
Optimize formatLabels
lydell Aug 18, 2026
b212767
CachedFuzzTestPass DistributionReport without unnecessary record
lydell Aug 18, 2026
3d6a1db
Replace `if reason == TODO then` with `case reason of`
lydell Aug 18, 2026
ce7a550
Fix "your" -> "you" in README.md
lydell Aug 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,30 @@ Start the runner in watch mode. Your tests will automatically rerun whenever you

elm-test --watch

### --no-clear-console

By default, the console is cleared before each run in watch mode, so you only see the latest information. If you don’t like this, turn it off with `--no-clear-console`.

elm-test --watch --no-clear-console

### --unbuffered-logs

elm-test collects all `Debug.log` output while executing a test, and displays it all once the test in question is finished. This way elm-test can print _which_ test the logs came from.

If the function you are testing gets into an infinite loop, it means that your debug logs will never show up. Then it can be useful to have the logs print _immediately_ instead (at the loss of no longer being able to label which tests the logs came from). To avoid confusion, use [Test.only](https://package.elm-lang.org/packages/elm-explorations/test/latest/Test#only) to isolate your test, or pass `--workers 1` to run in single-threaded mode to avoid oddly mixed output:

elm-test --unbuffered-logs --workers 1

For _failing_ fuzz tests, elm-test only prints `Debug.log` output from the run of the fuzz test that produced the failure, which is usually what you want to debug. (Earlier, passing runs of the function with different input is just noise). For _passing_ fuzz tests, elm-test _ignores_ your `Debug.log` calls (and instead displays a note about this). Let’s imagine you are debugging a failing fuzz test. After a while it finally passes. There is no longer a failing run, so which one should we pick logs from? All of them? But would you really like to see the screen fill with 100+ repetitions of your logs at that point? Probably not. But if you actually _do_ want to show logs from all runs, you can use `--unbuffered-logs` for this use case, too. Also remember that you can make the test fail from anywhere using `Debug.todo` – that’s also a way to make logs appear!

### --seed

Run with a specific fuzzer seed, rather than a randomly generated seed. This allows reproducing a failing fuzz-test. The command needed to reproduce (including the `--seed` flag) is printed after each test run. Copy, paste and run it!

elm-test --seed 336948560956134

On top of that, if you run elm-test without the `--seed` flag, elm-test will automatically use the same seed as the last run if there was a fuzz test failure, letting you reproduce errors without doing anything. It even tries to fast-forward you through the fuzzing. So if it took some time for the fuzzer to find the problem the first time, the next run should be instant.

### --fuzz

Define how many times each fuzz-test should run. Defaults to `100`.
Expand All @@ -173,16 +191,18 @@ Define how many times each fuzz-test should run. Defaults to `100`.

### --workers

Choose how many workers elm-test should use to run tests in parallel. Defaults to the number of “logical CPU cores” of the machine you run the tests on.
Choose how many workers elm-test should use to run fuzz tests in parallel. Defaults to the number of “logical CPU cores” of the machine you run the tests on.

elm-test --workers 4

Your computer might say that it has 12 logical CPU cores. Then dividing up the tests between 12 parallel workers is the theoretical optimum for running the tests as quickly as possible. But in practice your tests might run faster with just 4 workers in parallel due to overhead. Play around with it and see what is the fastest for your test suite on your computer!
Your computer might say that it has 12 logical CPU cores. Then dividing up the fuzz tests between 12 parallel workers is the theoretical optimum for running the tests as quickly as possible. But in practice your tests might run faster with just 4 workers in parallel due to overhead. Play around with it and see what is the fastest for your test suite on your computer!

To see the number of logical CPU cores on your machine, run `node -p "os.cpus().length"` (it’s also shown in `elm-test --help`).

If you pass `--workers 1`, elm-test won’t even start a new thread for running the tests in – it’ll do everything in the main thread (single-threaded mode).

Currently, elm-test always executes unit tests on the main thread, and only uses separate threads for fuzz tests. Unit tests tend to execute so fast that the overhead of threads isn’t worth it. But fuzz tests often run long enough to benefit from parallelization.

### --report

Specify which format to use for reporting test results. Valid options are:
Expand Down
2 changes: 1 addition & 1 deletion elm/elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
"elm/core": "1.0.5",
"elm/json": "1.1.3",
"elm/random": "1.0.0",
"elm/time": "1.0.0",
"elm-explorations/test": "2.2.1"
},
"indirect": {
"elm/bytes": "1.0.8",
"elm/html": "1.0.0",
"elm/time": "1.0.0",
"elm/virtual-dom": "1.0.3"
}
},
Expand Down
32 changes: 28 additions & 4 deletions elm/src/Test/Reporter/Console.elm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import Test.Reporter.Console.Format exposing (format)
import Test.Reporter.Console.Format.Color as FormatColor
import Test.Reporter.Console.Format.Monochrome as FormatMonochrome
import Test.Reporter.TestResults as Results exposing (Failure, Outcome(..), SummaryInfo)
import Test.Runner exposing (formatLabels)


formatDuration : Float -> String
Expand Down Expand Up @@ -36,6 +35,23 @@ pluralize singular plural count =
String.join " " [ String.fromInt count, suffix ]


formatLabels :
(String -> Text)
-> (String -> Text)
-> List String
-> List Text
formatLabels formatDescription formatTest labels =
case labels of
[] ->
[]

test :: descriptions ->
List.foldl
(\x acc -> formatDescription x :: acc)
[ formatTest test ]
descriptions


passedToText : List String -> String -> Text
passedToText labels distributionReport =
Text.concat
Expand Down Expand Up @@ -147,7 +163,7 @@ getStatus outcome =


reportComplete : UseColor -> Results.TestResult -> Value
reportComplete useColor { labels, outcome } =
reportComplete useColor { labels, outcome, hasDebugLogs } =
Encode.object <|
( "type", Encode.string "complete" )
:: ( "status", Encode.string (getStatus outcome) )
Expand All @@ -156,10 +172,18 @@ reportComplete useColor { labels, outcome } =
-- No failures of any kind.
case distributionReportToString distributionReport of
Nothing ->
[]
if hasDebugLogs then
[ ( "message"
, passedLabelsToText labels
|> textToValue useColor
)
]

else
[]

Just report ->
[ ( "distributionReport"
[ ( "message"
, report
|> passedToText labels
|> textToValue useColor
Expand Down
5 changes: 3 additions & 2 deletions elm/src/Test/Reporter/JUnit.elm
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ formatClassAndName labels =
( "", "" )


encodeDuration : Int -> Value
encodeDuration : Float -> Value
encodeDuration time =
(toFloat time / 1000)
(time / 1000)
|> String.fromFloat
|> Encode.string

Expand Down Expand Up @@ -119,6 +119,7 @@ encodeExtraFailure _ =
}
, NoDistribution
)
, hasDebugLogs = False
}


Expand Down
6 changes: 5 additions & 1 deletion elm/src/Test/Reporter/Json.elm
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ reportComplete { duration, labels, outcome } =
, ( "labels", encodeLabels labels )
, ( "failures", Encode.list identity (encodeFailures outcome) )
, ( "distributionReports", Encode.list identity (encodeDistributionReports outcome) )
, ( "duration", Encode.string <| String.fromInt duration )

-- Keep the "duration" field Int for backwards compatibility,
-- and also expose the new Float field for more precision.
, ( "duration", Encode.string <| String.fromInt (round duration) )
, ( "durationFloat", Encode.string <| String.fromFloat duration )
]


Expand Down
42 changes: 2 additions & 40 deletions elm/src/Test/Reporter/TestResults.elm
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@ module Test.Reporter.TestResults exposing
, Outcome(..)
, SummaryInfo
, TestResult
, isFailure
, outcomeFromExpectations
)

import Expect exposing (Expectation)
import Test.Distribution exposing (DistributionReport)
import Test.Runner
import Test.Runner.Failure exposing (Reason)


Expand All @@ -22,7 +18,8 @@ type Outcome
type alias TestResult =
{ labels : List String
, outcome : Outcome
, duration : Int -- in milliseconds
, duration : Float -- in milliseconds
, hasDebugLogs : Bool
}


Expand All @@ -40,38 +37,3 @@ type alias Failure =
, description : String
, reason : Reason
}


isFailure : Outcome -> Bool
isFailure outcome =
case outcome of
Failed _ ->
True

_ ->
False


outcomeFromExpectations : List Expectation -> Outcome
outcomeFromExpectations expectations =
case expectations of
-- The type of test runner functions says that they return `List Expectation`,
-- but in practice they only ever return lists with exactly one item:
-- https://github.com/elm-explorations/test/pull/244
-- That PR was reverted because it unfortunately was a breaking change for the package:
-- https://github.com/elm-explorations/test/commit/11f70d5fc0b6fdc88d7a34ea1d10f56969890493
-- But to keep things simpler here, we only support exactly one expectation.
[ expectation ] ->
case Test.Runner.getFailureReason expectation of
Nothing ->
Passed (Test.Runner.getDistributionReport expectation)

Just failure ->
if Test.Runner.isTodo expectation then
Todo failure.description

else
Failed ( failure, Test.Runner.getDistributionReport expectation )

_ ->
Debug.todo ("A test somehow did not return exactly 1 expectation, it returned " ++ String.fromInt (List.length expectations) ++ "!")
33 changes: 0 additions & 33 deletions elm/src/Test/Runner/JsMessage.elm

This file was deleted.

Loading
Loading