One issue I have with the expect is that it requires I add a separate value to see useful output when the test fails.
expect
result = double [1, 2, 3]
result == [2, 4, 6]
I'd much rather write:
expect double [1, 2, 3] == [2, 4, 6]
However then I can't see the output of double [1, 2, 3].
Would it be possible to show what is given to == instead of requiring I assign a value? I don't know how == works under the hood, but if it compiles to a function you could have expect show any arguments passed to the top level function. This way it will work for other calls besides ==.
expect List.isEmpty (trim ['', '', ''])
That could output Expected List.isEmpty to return true given [''] or whatever the output of trim was.
Is this possible?
I've also run into this. I think it would be nice if it could show every "expression" involved in the final expression.
So for expect double [1, 2, 3] == [2, 4, 7] it would be
double [1, 2, 3] = [2,4,7]
double [1, 2, 3] == [2, 4, 7] = Bool.False
(literals can be omitted)
And for expect List.isEmpty (trim ['', '', ''])
trim ['', '', ''] = ['']
List.isEmpty (trim ['', '', '']) == Bool.False
Not sure if trim ['','',''] should be replaced with the result of evaluation
yeah I'd like to change this so that we recursively output all the intermediate expressions that go into that final expression
@LoipesMas What about placing the evaluated value in each resulting expression?
double [1, 2, 3] = [2,4,7]
[2, 4, 7] == [2, 4, 6] = Bool.False
trim ["", "", ""] = [""]
List.isEmpty [""] = Bool.False
I like this more so I don't have to hunt it down (there could be a lot listed there).
we could have some heuristics like "don't bother printing it if it's entirely literals" e.g. [1, 2, 3] because you know what that is since it's right there in the source code
Maybe a written-out step-by-step "evaluation" would be better?
List.isEmpty (trim ['', '', ''])
List.isEmpty ['']
Bool.False
(with a nice description/formatting/highlighting/syntax)
It would be nice if it could do all substitutions that can be done in a given step at once, for example, instead of
List.isEmpty [a, b, c]
List.isEmpty [1, b, c]
List.isEmpty [1, 2, c]
List.isEmpty [1,2,3]
Bool.False
it could merge some steps
List.isEmpty [a, b, c]
List.isEmpty [1,2,3]
Bool.False
I think it would be good to collect some real world examples!
like some actual expects you've written, and what it would look like if they failed in certain ways
Here are a few examples from advent of code that shows each step of evaluation (evaluating all leaves per step)
expect parseStr stepParser "ab=1" == Ok { label: ['a', 'b'], operation: AddLense 1 }
parseStr <opaque> "ab=1" == (Ok {label: [97, 98], operation: (AddLense 1)})
(Ok {label: [97, 98], operation: (AddLense 0)}) == (Ok {label: [97, 98], operation: (AddLense 1)})
Bool.false
Looks pretty useful.
expect part1 inputExample1 == 62
part1 "R 6 (#70c710)
D 5 (#0dc571)
L 2 (#5713f0)
D 2 (#d2c081)
R 2 (#59c680)
D 2 (#411b91)
L 5 (#8ceee2)
U 2 (#caa173)
L 1 (#1b58a2)
U 2 (#caa171)
R 2 (#7807d2)
U 3 (#a77fa3)
L 2 (#015232)
U 2 (#7a21e3)
" == 62
64 == 62
Bool.false
The long text is noisy but could be useful.
expect
springs = [OperationalSpring, DamagedSpring, UnknownSpring, UnknownSpring]
parseRow ".#?? 1,1" == { springs, counts: [1, 1] }
{counts: [1, 2], springs: [OperationalSpring, DamagedSpring, UnknownSpring, UnknownSpring]} == {counts: [1, 1], springs: [OperationalSpring, DamagedSpring, UnknownSpring, UnknownSpring]}
Bool.false
Longer lines can be a bit cumbersome to find the difference, but not bad. I know RSpec highlights the differences when doing equal assertions which is somewhat useful, but has its own issues.
expect
tiles = parseTiles "S-7\n|.|\nL-J\n"
expectedTiles = [
((0, 0), Start),
((1, 0), HorizontalPipe),
((2, 0), SouthWestPipe),
((0, 1), VerticalPipe),
((1, 1), Ground),
((2, 1), VerticalPipe),
((0, 2), NorthEastPipe),
((1, 2), HorizontalPipe),
((2, 2), NorthWestPipe),
]
Dict.toList tiles == expectedTiles
Dict.toList {(0, 0): Start, (1, 0): HorizontalPipe, (2, 0): SouthWestPipe, (0, 1): VerticalPipe, (1, 1): Ground, (2, 1): VerticalPipe, (0, 2): NorthEastPipe, (0, 2): HorizontalPipe, (2, 2): NorthWestPipe} == [((0, 0), Start), ((1, 0), HorizontalPipe), ((2, 0), SouthWestPipe), ((0, 1), VerticalPipe), ((1, 1), Ground), ((2, 1), VerticalPipe), ((0, 2), NorthEastPipe), ((1, 2), HorizontalPipe), ((2, 2), NorthWestPipe)]
[((0, 0), Start), ((1, 0), HorizontalPipe), ((2, 0), SouthWestPipe), ((0, 1), VerticalPipe), ((1, 1), Ground), ((2, 1), VerticalPipe), ((0, 2), NorthEastPipe), ((0, 2), HorizontalPipe), ((2, 2), NorthWestPipe)] == [((0, 0), Start), ((1, 0), HorizontalPipe), ((2, 0), SouthWestPipe), ((0, 1), VerticalPipe), ((1, 1), Ground), ((2, 1), VerticalPipe), ((0, 2), NorthEastPipe), ((1, 2), HorizontalPipe), ((2, 2), NorthWestPipe)]
Bool.false
This output is a mess because there's so much data. It would be very difficult to find the issue. I think if the formatting is improved for long lines it could be really nice.
BTW, the output of dbg formatting is different from both roc test and roc format. Perhaps I'll make an issue for this.
please do! It's also different from the repl
we upgraded dbg to use the Inspect ability but haven't upgraded those others to use it yet
Richard Feldman said:
we could have some heuristics like "don't bother printing it if it's entirely literals" e.g.
[1, 2, 3]because you know what that is since it's right there in the source code
That seems magical to me. If someone is learning about expect, they may just try expect 1 == 2 to see what happens. I believe we should have that behave the same as any other expect, rather than a "go find the source to look at the values, because they're too simple to be worth printing here" outcome.
Not everyone uses sophisticated editor integrations, and aside from that, any reasonable opportunity to avoid forcing the user to do more jumping around in the code is a win. Imagine stack traces without function names: technically the user could work it all out from the filenames and line numbers, but their work is easily a few hundred times slower and more tedious in that scenario.
Last updated: Jun 16 2026 at 16:19 UTC