Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
6536cc6
Add Test.Runner.fromTestV2
lydell Jul 22, 2026
6aae883
Notify runners of each run of a fuzz test
lydell Jul 22, 2026
732c1a7
Make it possible to tag tests
lydell Jul 22, 2026
a87ad90
Simplify away intermediate type
lydell Jul 23, 2026
b9f1a90
Fewer impossible states
lydell Jul 26, 2026
ad13a50
Return the RandomRun and a function for rerunning the failure
lydell Jul 26, 2026
56528cf
Remove old NotifyRunStarted
lydell Jul 26, 2026
1fb8d30
Make it possible to run a fuzz test from a previous RandomRun
lydell Jul 26, 2026
4b52fa9
Fix public vs internal types
lydell Jul 26, 2026
a80567f
The old implemenation already does this, no need to worry
lydell Jul 26, 2026
a5d8226
Description
lydell Jul 26, 2026
00fd131
Call it fuzzerInts consistently
lydell Jul 26, 2026
0f93b19
Expose fuzzReproduce
lydell Jul 26, 2026
7e6d8b3
More docs
lydell Jul 26, 2026
8be1c2a
Expose tagTest
lydell Jul 26, 2026
54d75cf
Remove fuzzReproduce – let the runner automatically provide a saved r…
lydell Jul 28, 2026
50b44a3
Continue with a regular fuzz run after a saved RandomRun
lydell Jul 28, 2026
b6d30f2
Add parametrize and fuzzWithExamples
lydell Jul 28, 2026
5ece70b
Actually expose stuff
lydell Jul 29, 2026
d49d9d5
Catch exceptions earlier for fuzz tests
lydell Aug 2, 2026
0123966
Optimize away one layer of lambdas
lydell Aug 2, 2026
2129942
Docs
lydell Aug 2, 2026
2f69e71
fromTestV2Helper -> toTestsHelper
lydell Aug 5, 2026
c72d811
Use arrays instead of lists – maybe faster append, node-test-runner n…
lydell Aug 5, 2026
b28a21f
Remove parametrized and fuzzWithExamples from this branch
lydell Aug 16, 2026
6cbc795
RunnerV2 module
lydell Aug 16, 2026
ebb7451
Opaque
lydell Aug 16, 2026
b2c7f4c
RunnerTests
lydell Aug 16, 2026
ee0f805
Add missing docs
lydell Aug 16, 2026
f07729a
Improve docs
lydell Aug 16, 2026
ef858b8
Add test for tagTest
lydell Aug 16, 2026
6890f3b
Rename to fromFuzzTestExpectation
lydell Aug 17, 2026
77e33e2
Avoid creating a new record by not destructuring
lydell Aug 17, 2026
cebd96d
Flatten to `FuzzTestPass DistributionReport`
lydell Aug 17, 2026
646ba7a
Apply doc suggestions from code review
lydell Aug 17, 2026
530c4aa
Extract code block to tryReproduceFailureFromFuzzerInts function
lydell Aug 17, 2026
3d83b98
Add comment explaining reproducing fuzz test failures a bit more
lydell Aug 17, 2026
9116894
Optimize toTestsHelper
lydell Aug 17, 2026
e48084e
Add `Test.RunnerV2.identifyTest`
lydell Aug 22, 2026
e523882
Make running tests also measure how long they take
lydell Aug 22, 2026
c384b2d
Capture Debug.log
lydell Aug 22, 2026
a2e470e
Massively simplify Debug.log collection
lydell Aug 22, 2026
43f1d19
Add DebugLogs.fromString
lydell Aug 22, 2026
9bbde9a
Renames
lydell Aug 22, 2026
4577f5f
Document stderr
lydell Aug 22, 2026
6cd9456
Tweaks
lydell Aug 22, 2026
b63cc63
Simplify by storing debug logs as a string
lydell Aug 22, 2026
c049d6f
Document debug log string format
lydell Aug 22, 2026
8a19106
Remove thrown exception test for now
lydell Aug 22, 2026
ba02a3a
Update comment
lydell Aug 22, 2026
5c572dc
Rename leftover old name for param
lydell Aug 22, 2026
87336e8
Make it easier to use Debug.log to debug a runner
lydell Aug 22, 2026
c5f7f91
Simplify links
lydell Aug 22, 2026
61ce974
Count number of skipped tests
lydell Aug 22, 2026
2cde6a1
Optimize Only record update
lydell Aug 22, 2026
d9af4fd
Revert "Count number of skipped tests"
lydell Aug 22, 2026
34073a0
Fix compile error after revert
lydell Aug 22, 2026
206d315
Merge branch 'master' into fromTestV2
lydell Aug 24, 2026
b9d6196
Merge branch 'master' into fromTestV2
lydell Sep 27, 2026
0fd56c3
Fix compilation errors in tests after merge
lydell Sep 27, 2026
1d4b68b
Count tests excluded due to `skip` and `only`
lydell Sep 27, 2026
5f3c0a7
Remove comment referring to deprecated module
lydell Sep 27, 2026
2173f95
Don’t use Test.Runner.getFailureReason internally
lydell Sep 27, 2026
3add818
Merge branch 'master' into fromTestV2
lydell Sep 28, 2026
ca106cf
Remove unnecessary in-let
lydell Sep 28, 2026
77ea3e7
Suppress “unused” `Mode` (Kernel-backed)
lydell Sep 28, 2026
0e25523
Merge branch 'master' into fromTestV2
lydell Sep 29, 2026
8292c19
Fix: Use runs from `fuzzWith` if available
lydell Oct 6, 2026
f5818e2
Merge branch 'master' into fromTestV2
lydell Nov 6, 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
1 change: 1 addition & 0 deletions elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"exposed-modules": [
"Test",
"Test.Runner",
"Test.RunnerV2",
"Test.Runner.Failure",
"Test.Distribution",
"Expect",
Expand Down
8 changes: 8 additions & 0 deletions review/suppressed/NoUnused.CustomTypeConstructors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"version": 1,
"automatically created by": "elm-review suppress",
"learn more": "elm-review suppress --help",
"suppressions": [
{ "count": 1, "filePath": "src/Test/Internal/DebugLogs.elm" }
]
}
75 changes: 75 additions & 0 deletions src/Elm/Kernel/DebugLogs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*

import Elm.Kernel.Debug exposing (toString)
import Elm.Kernel.Json exposing (wrap)
import Elm.Kernel.Scheduler exposing (binding, succeed)
import Elm.Kernel.Utils exposing (Tuple0)

*/

var _DebugLogs_modeConsoleLog = __1_CONSOLE_LOG;
var _DebugLogs_modeCollect = __1_COLLECT;
var _DebugLogs_modeIgnore = __1_IGNORE;

var _DebugLogs_logs = '';
var _DebugLogs_used = false;
var _DebugLogs_mode = globalThis.elmTestPrintDebugLogsBeforeFirstTestToConsole ? __1_CONSOLE_LOG : __1_COLLECT;
// Note: Always reset the mode to __1_CONSOLE_LOG, so that `Debug.log` used to debug a test runner
// has a higher chance of showing up out of the box.

var _DebugLogs_logsBeforeFirstTestRun = undefined;

var _DebugLogs_getDebugLogsBeforeFirstTestRun = __Scheduler_binding(function(callback)
{
if (_DebugLogs_logsBeforeFirstTestRun === undefined) {
_DebugLogs_logsBeforeFirstTestRun = _DebugLogs_logs;
_DebugLogs_logs = '';
_DebugLogs_used = false;
_DebugLogs_mode = __1_CONSOLE_LOG;
}
callback(__Scheduler_succeed(_DebugLogs_logsBeforeFirstTestRun));
});

var _DebugLogs_runTestWithDurationAndCollectDebugLogs = F3(function(mode, thunk, mapper)
{
return __Scheduler_binding(function(callback)
{
if (_DebugLogs_logsBeforeFirstTestRun === undefined) {
_DebugLogs_logsBeforeFirstTestRun = _DebugLogs_logs;
}
_DebugLogs_logs = '';
_DebugLogs_used = false;
_DebugLogs_mode = mode;
var start = performance.now();
var value = thunk(__Utils_Tuple0);
var duration = performance.now() - start;
_DebugLogs_mode = __1_CONSOLE_LOG;
callback(__Scheduler_succeed(A4(mapper, value, duration, _DebugLogs_logs, _DebugLogs_used)));
});
});

function _DebugLogs_rerunFailureToCollectDebugLogs(rerunFailure)
{
_DebugLogs_logs = '';
_DebugLogs_used = false;
_DebugLogs_mode = __1_COLLECT;
rerunFailure(__Utils_Tuple0);
_DebugLogs_mode = __1_CONSOLE_LOG;
return _DebugLogs_logs;
}

var _Debug_log = F2(function(tag, value)
{
_DebugLogs_used = true;
switch (_DebugLogs_mode) {
case __1_CONSOLE_LOG:
console.error(tag + ': ' + __Debug_toString(value));
break;
case __1_COLLECT:
_DebugLogs_logs += tag + ': ' + __Debug_toString(value) + '\n';
break;
default:
// __1_IGNORE: Do nothing.
}
return value;
});
6 changes: 5 additions & 1 deletion src/Elm/Kernel/RandomRun.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import Basics exposing (EQ, LT, GT)
import Maybe exposing (Just, Nothing)
import Elm.Kernel.List exposing (Nil, Cons)
import Elm.Kernel.List exposing (Nil, Cons, toArray)

*/

Expand Down Expand Up @@ -56,6 +56,10 @@ function _RandomRun_toList(rr) {
return out;
}

function _RandomRun_fromList(list) {
return new Uint32Array(__List_toArray(list));
}

var _RandomRun_get = F2(function _RandomRun_get_(index, rr) {
var item = rr[index];
if (item === undefined) {
Expand Down
20 changes: 16 additions & 4 deletions src/Elm/Kernel/Test.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
/*

import Elm.Kernel.Utils exposing (Tuple0)
import Maybe exposing (Just, Nothing)
import Result exposing (Err, Ok)

*/


function _Test_runThunk(thunk)
var _Test_runWithTryCatch = F2(function(thunk, a)
{
try {
// Attempt to run the thunk as normal.
return __Result_Ok(thunk(__Utils_Tuple0));
return __Result_Ok(thunk(a));
} catch (err) {
// If it throws, return an error instead of crashing.
return __Result_Err(err.toString());
}
});

var _Test_symbol = Symbol("_Test_symbol");

function _Test_tagTest(test)
{
test[_Test_symbol] = true;
return test;
}

function _Test_identifyTest(value)
{
return value && value[_Test_symbol] ? __Maybe_Just(value) : __Maybe_Nothing;
}
6 changes: 6 additions & 0 deletions src/RandomRun.elm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module RandomRun exposing
, deleteChunk
, empty
, equal
, fromList
, get
, isEmpty
, length
Expand Down Expand Up @@ -121,6 +122,11 @@ toList =
Elm.Kernel.RandomRun.toList


fromList : List Int -> RandomRun
fromList =
Elm.Kernel.RandomRun.fromList


update : Int -> (Int -> Int) -> RandomRun -> RandomRun
update =
Elm.Kernel.RandomRun.update
Expand Down
61 changes: 21 additions & 40 deletions src/Test.elm
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import Test.Internal as Internal
import Test.Runner.Failure exposing (InvalidReason(..), Reason(..))


{-| A test which has yet to be evaluated. When evaluated, it produces one
or more [`Expectation`](Expect#Expectation)s.
{-| A test which has yet to be evaluated. When evaluated, it produces an
[`Expectation`](Expect#Expectation).

See [`test`](#test) and [`fuzz`](#fuzz) for some ways to create a `Test`.

Expand Down Expand Up @@ -69,6 +69,7 @@ concat tests =

Ok _ ->
Internal.ElmTestVariant__Batch tests
|> Internal.wrapTestVariant


{-| Apply a description to a list of tests.
Expand Down Expand Up @@ -114,28 +115,33 @@ describe untrimmedDesc tests =
}

else
let
labeled test_ =
Internal.ElmTestVariant__Labeled desc test_
|> Internal.wrapTestVariant
in
case Internal.duplicatedName tests of
Err dups ->
let
dupDescription duped =
"Contains multiple tests named '" ++ duped ++ "'. Let's rename them so we know which is which."
in
Internal.ElmTestVariant__Labeled desc <|
labeled <|
Internal.failNow
{ description = String.join "\n" (List.map dupDescription <| Set.toList dups)
, reason = Invalid DuplicatedName
}

Ok childrenNames ->
if Set.member desc childrenNames then
Internal.ElmTestVariant__Labeled desc <|
labeled <|
Internal.failNow
{ description = "The test '" ++ desc ++ "' contains a child test of the same name. Let's rename them so we know which is which."
, reason = Invalid DuplicatedName
}

else
Internal.ElmTestVariant__Labeled desc (Internal.ElmTestVariant__Batch tests)
labeled (Internal.wrapTestVariant (Internal.ElmTestVariant__Batch tests))


{-| Create a group of tests from a list of input-output cases (also called "parameterized tests").
Expand Down Expand Up @@ -202,7 +208,8 @@ test untrimmedDesc thunk =
Internal.blankDescriptionFailure

else
Internal.ElmTestVariant__Labeled desc (Internal.ElmTestVariant__UnitTest (\() -> thunk ()))
Internal.ElmTestVariant__Labeled desc (Internal.wrapTestVariant (Internal.ElmTestVariant__UnitTest (Internal.wrapWithTryCatch thunk)))
|> Internal.wrapTestVariant


{-| Returns a [`Test`](#Test) that is "TODO" (not yet implemented). These tests
Expand Down Expand Up @@ -270,8 +277,9 @@ an `only` inside a `skip`, it will also get skipped.

-}
only : Test -> Test
only =
Internal.ElmTestVariant__Only
only test_ =
Internal.ElmTestVariant__Only test_
|> Internal.wrapTestVariant


{-| Returns a [`Test`](#Test) that gets skipped.
Expand Down Expand Up @@ -306,8 +314,9 @@ an `only` inside a `skip`, it will also get skipped.

-}
skip : Test -> Test
skip =
Internal.ElmTestVariant__Skipped
skip test_ =
Internal.ElmTestVariant__Skipped test_
|> Internal.wrapTestVariant


{-| Options [`fuzzWith`](#fuzzWith) accepts.
Expand Down Expand Up @@ -392,35 +401,7 @@ fuzzWith desc options fuzzer getTest =
}

else
fuzzWithHelp options (Test.Fuzz.fuzzTest desc options.distribution fuzzer getTest)


fuzzWithHelp : FuzzOptions a -> Test -> Test
fuzzWithHelp options aTest =
case aTest of
Internal.ElmTestVariant__UnitTest _ ->
aTest

Internal.ElmTestVariant__FuzzTest run ->
Internal.ElmTestVariant__FuzzTest (\seed _ -> run seed options.runs)

Internal.ElmTestVariant__Labeled label subTest ->
Internal.ElmTestVariant__Labeled label (fuzzWithHelp options subTest)

Internal.ElmTestVariant__Skipped subTest ->
-- It's important to treat skipped tests exactly the same as normal,
-- until after seed distribution has completed.
fuzzWithHelp options subTest
|> Internal.ElmTestVariant__Only

Internal.ElmTestVariant__Only subTest ->
fuzzWithHelp options subTest
|> Internal.ElmTestVariant__Only

Internal.ElmTestVariant__Batch tests ->
tests
|> List.map (fuzzWithHelp options)
|> Internal.ElmTestVariant__Batch
Test.Fuzz.fuzzTest desc (Just options.runs) options.distribution fuzzer getTest


{-| Specify hardcoded example inputs for your fuzz test. They will be run
Expand Down Expand Up @@ -499,7 +480,7 @@ fuzz :
-> (a -> Expectation)
-> Test
fuzz desc fuzzer getExpectation =
Test.Fuzz.fuzzTest desc Test.Distribution.Internal.NoDistributionNeeded fuzzer getExpectation
Test.Fuzz.fuzzTest desc Nothing Test.Distribution.Internal.NoDistributionNeeded fuzzer getExpectation


{-| Run a [fuzz test](#fuzz) using two random inputs.
Expand Down
3 changes: 0 additions & 3 deletions src/Test/Distribution.elm
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ atLeast =


{-| A result of a distribution check.

Get it from your `Expectation` with `Test.Runner.getDistributionReport`.

-}
type DistributionReport
= -- Adding a () so that all variants have the same number of arguments
Expand Down
Loading
Loading