Current section

Files

Jump to
dream_test src dream_test@matchers@snapshot.erl
Raw

src/dream_test@matchers@snapshot.erl

-module(dream_test@matchers@snapshot).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/dream_test/matchers/snapshot.gleam").
-export([clear_snapshot/1, clear_snapshots_in_directory/1, match_snapshot/2, match_snapshot_inspect/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Snapshot matchers for dream_test.\n"
"\n"
" Snapshot testing compares output against a stored “golden” file.\n"
"\n"
" - On first run (missing snapshot), the snapshot is created and the test passes.\n"
" - On later runs, the output is compared against the file; differences fail.\n"
"\n"
" Snapshot tests are useful when the output is large or awkward to specify by\n"
" hand (rendered HTML, JSON, error messages, logs, etc.).\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let path = \"./test/tmp/match_snapshot_example.snap\"\n"
" \"hello\"\n"
" |> should\n"
" |> match_snapshot(path)\n"
" |> or_fail_with(\"expected snapshot match\")\n"
" ```\n"
).
-file("src/dream_test/matchers/snapshot.gleam", 152).
?DOC(
" Delete a snapshot file to force regeneration.\n"
"\n"
" Use this to programmatically clear a snapshot. The next test run will\n"
" create a fresh snapshot with the current output.\n"
"\n"
" ## Parameters\n"
"\n"
" - `snapshot_path` - Path to the snapshot file to delete\n"
"\n"
" ## Returns\n"
"\n"
" - `Ok(Nil)` - Snapshot was deleted (or didn't exist)\n"
" - `Error(String)` - Human-readable error message\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let path = \"./test/tmp/clear_snapshot_example.snap\"\n"
"\n"
" // Setup: create a snapshot file (no assertions during setup)\n"
" use _ <- result.try(\n"
" file.write(path, \"hello\") |> result.map_error(file.error_to_string),\n"
" )\n"
"\n"
" clear_snapshot(path)\n"
" |> should\n"
" |> be_equal(Ok(Nil))\n"
" |> or_fail_with(\"expected clear_snapshot to succeed\")\n"
" ```\n"
).
-spec clear_snapshot(binary()) -> {ok, nil} | {error, binary()}.
clear_snapshot(Snapshot_path) ->
case dream_test_file_ffi:delete_file(Snapshot_path) of
{ok, nil} ->
{ok, nil};
{error, Error} ->
{error, dream_test@file:error_to_string(Error)}
end.
-file("src/dream_test/matchers/snapshot.gleam", 194).
?DOC(
" Delete all `.snap` files in a directory.\n"
"\n"
" Clears all snapshot files in the given directory (non-recursively).\n"
" Useful for resetting all snapshots before a major refactor.\n"
"\n"
" ## Parameters\n"
"\n"
" - `directory` - Path to the directory containing snapshots\n"
"\n"
" ## Returns\n"
"\n"
" - `Ok(Int)` - Number of snapshot files deleted\n"
" - `Error(String)` - Human-readable error message\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let directory = \"./test/tmp/clear_snapshots_in_directory_example\"\n"
" let a = directory <> \"/a.snap\"\n"
" let b = directory <> \"/b.snap\"\n"
"\n"
" // Setup: create two snapshot files (no assertions during setup)\n"
" use _ <- result.try(\n"
" file.write(a, \"a\") |> result.map_error(file.error_to_string),\n"
" )\n"
" use _ <- result.try(\n"
" file.write(b, \"b\") |> result.map_error(file.error_to_string),\n"
" )\n"
"\n"
" clear_snapshots_in_directory(directory)\n"
" |> should\n"
" |> be_equal(Ok(2))\n"
" |> or_fail_with(\"expected two deleted snapshots\")\n"
" ```\n"
).
-spec clear_snapshots_in_directory(binary()) -> {ok, integer()} |
{error, binary()}.
clear_snapshots_in_directory(Directory) ->
case dream_test_file_ffi:delete_files_matching(Directory, <<".snap"/utf8>>) of
{ok, Count} ->
{ok, Count};
{error, Error} ->
{error, dream_test@file:error_to_string(Error)}
end.
-file("src/dream_test/matchers/snapshot.gleam", 227).
-spec drop_trailing_newlines(list(binary())) -> list(binary()).
drop_trailing_newlines(Graphemes_reversed) ->
case Graphemes_reversed of
[<<"\n"/utf8>> | Rest] ->
drop_trailing_newlines(Rest);
[<<"\r"/utf8>> | Rest@1] ->
drop_trailing_newlines(Rest@1);
Other ->
Other
end.
-file("src/dream_test/matchers/snapshot.gleam", 218).
-spec normalize_snapshot_expected(binary()) -> binary().
normalize_snapshot_expected(Expected) ->
_pipe = Expected,
_pipe@1 = gleam@string:to_graphemes(_pipe),
_pipe@2 = lists:reverse(_pipe@1),
_pipe@3 = drop_trailing_newlines(_pipe@2),
_pipe@4 = lists:reverse(_pipe@3),
gleam@string:join(_pipe@4, <<""/utf8>>).
-file("src/dream_test/matchers/snapshot.gleam", 249).
-spec make_mismatch_failure(binary(), binary(), binary()) -> dream_test@types:match_result(binary()).
make_mismatch_failure(Actual, Expected, Snapshot_path) ->
Payload = {snapshot_failure, Actual, Expected, Snapshot_path, false},
{match_failed,
{assertion_failure,
<<"match_snapshot"/utf8>>,
<<""/utf8>>,
{some, Payload}}}.
-file("src/dream_test/matchers/snapshot.gleam", 235).
-spec compare_snapshot(binary(), binary(), binary()) -> dream_test@types:match_result(binary()).
compare_snapshot(Actual, Expected, Snapshot_path) ->
Normalized_actual = normalize_snapshot_expected(Actual),
case Normalized_actual =:= Expected of
true ->
{match_ok, Actual};
false ->
make_mismatch_failure(Actual, Expected, Snapshot_path)
end.
-file("src/dream_test/matchers/snapshot.gleam", 268).
-spec make_read_error_failure(binary(), dream_test@file:file_error()) -> dream_test@types:match_result(binary()).
make_read_error_failure(Snapshot_path, Error) ->
Payload = {snapshot_failure, <<""/utf8>>, <<""/utf8>>, Snapshot_path, true},
{match_failed,
{assertion_failure,
<<"match_snapshot"/utf8>>,
<<"Failed to read snapshot: "/utf8,
(dream_test@file:error_to_string(Error))/binary>>,
{some, Payload}}}.
-file("src/dream_test/matchers/snapshot.gleam", 293).
-spec make_write_failure(binary(), dream_test@file:file_error()) -> dream_test@types:match_result(binary()).
make_write_failure(Snapshot_path, Error) ->
Payload = {snapshot_failure, <<""/utf8>>, <<""/utf8>>, Snapshot_path, true},
{match_failed,
{assertion_failure,
<<"match_snapshot"/utf8>>,
<<"Failed to write snapshot: "/utf8,
(dream_test@file:error_to_string(Error))/binary>>,
{some, Payload}}}.
-file("src/dream_test/matchers/snapshot.gleam", 286).
-spec create_snapshot(binary(), binary()) -> dream_test@types:match_result(binary()).
create_snapshot(Actual, Snapshot_path) ->
case dream_test_file_ffi:write_file(Snapshot_path, Actual) of
{ok, nil} ->
{match_ok, Actual};
{error, Error} ->
make_write_failure(Snapshot_path, Error)
end.
-file("src/dream_test/matchers/snapshot.gleam", 205).
-spec check_snapshot(binary(), binary()) -> dream_test@types:match_result(binary()).
check_snapshot(Actual, Snapshot_path) ->
case dream_test_file_ffi:read_file(Snapshot_path) of
{ok, Expected} ->
compare_snapshot(
Actual,
normalize_snapshot_expected(Expected),
Snapshot_path
);
{error, {not_found, _}} ->
create_snapshot(Actual, Snapshot_path);
{error, Error} ->
make_read_error_failure(Snapshot_path, Error)
end.
-file("src/dream_test/matchers/snapshot.gleam", 65).
?DOC(
" Assert that a string value matches the content of a snapshot file.\n"
"\n"
" This is the primary snapshot matcher. Use it when you have string output\n"
" (JSON, HTML, plain text, etc.) that you want to compare against a snapshot.\n"
"\n"
" ## Behavior\n"
"\n"
" - **Snapshot doesn't exist**: Creates it and the test **passes**\n"
" - **Snapshot exists and matches**: Test **passes**\n"
" - **Snapshot exists but differs**: Test **fails** with detailed diff\n"
"\n"
" ## Parameters\n"
"\n"
" - `value_or_result` - The `MatchResult(String)` from the assertion chain\n"
" - `snapshot_path` - Path to the snapshot file (will be created if missing)\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let path = \"./test/tmp/match_snapshot_example.snap\"\n"
" \"hello\"\n"
" |> should\n"
" |> match_snapshot(path)\n"
" |> or_fail_with(\"expected snapshot match\")\n"
" ```\n"
"\n"
" ## Returns\n"
"\n"
" A `MatchResult(String)`:\n"
" - On success, preserves the original string for further chaining.\n"
" - On failure, the chain becomes failed and later matchers are skipped.\n"
).
-spec match_snapshot(dream_test@types:match_result(binary()), binary()) -> dream_test@types:match_result(binary()).
match_snapshot(Value_or_result, Snapshot_path) ->
case Value_or_result of
{match_failed, Failure} ->
{match_failed, Failure};
{match_ok, Actual} ->
check_snapshot(Actual, Snapshot_path)
end.
-file("src/dream_test/matchers/snapshot.gleam", 342).
-spec make_mismatch_failure_inspect(binary(), binary(), binary()) -> dream_test@types:match_result(any()).
make_mismatch_failure_inspect(Actual, Expected, Snapshot_path) ->
Payload = {snapshot_failure, Actual, Expected, Snapshot_path, false},
{match_failed,
{assertion_failure,
<<"match_snapshot_inspect"/utf8>>,
<<""/utf8>>,
{some, Payload}}}.
-file("src/dream_test/matchers/snapshot.gleam", 330).
-spec compare_snapshot_inspect(HTL, binary(), binary(), binary()) -> dream_test@types:match_result(HTL).
compare_snapshot_inspect(Value, Serialized, Expected, Snapshot_path) ->
case Serialized =:= Expected of
true ->
{match_ok, Value};
false ->
make_mismatch_failure_inspect(Serialized, Expected, Snapshot_path)
end.
-file("src/dream_test/matchers/snapshot.gleam", 361).
-spec make_read_error_failure_inspect(binary(), dream_test@file:file_error()) -> dream_test@types:match_result(any()).
make_read_error_failure_inspect(Snapshot_path, Error) ->
Payload = {snapshot_failure, <<""/utf8>>, <<""/utf8>>, Snapshot_path, true},
{match_failed,
{assertion_failure,
<<"match_snapshot_inspect"/utf8>>,
<<"Failed to read snapshot: "/utf8,
(dream_test@file:error_to_string(Error))/binary>>,
{some, Payload}}}.
-file("src/dream_test/matchers/snapshot.gleam", 390).
-spec make_write_failure_inspect(binary(), dream_test@file:file_error()) -> dream_test@types:match_result(any()).
make_write_failure_inspect(Snapshot_path, Error) ->
Payload = {snapshot_failure, <<""/utf8>>, <<""/utf8>>, Snapshot_path, true},
{match_failed,
{assertion_failure,
<<"match_snapshot_inspect"/utf8>>,
<<"Failed to write snapshot: "/utf8,
(dream_test@file:error_to_string(Error))/binary>>,
{some, Payload}}}.
-file("src/dream_test/matchers/snapshot.gleam", 379).
-spec create_snapshot_inspect(HTR, binary(), binary()) -> dream_test@types:match_result(HTR).
create_snapshot_inspect(Value, Serialized, Snapshot_path) ->
case dream_test_file_ffi:write_file(Snapshot_path, Serialized) of
{ok, nil} ->
{match_ok, Value};
{error, Error} ->
make_write_failure_inspect(Snapshot_path, Error)
end.
-file("src/dream_test/matchers/snapshot.gleam", 311).
-spec check_snapshot_inspect(HTJ, binary()) -> dream_test@types:match_result(HTJ).
check_snapshot_inspect(Value, Snapshot_path) ->
Serialized = gleam@string:inspect(Value),
case dream_test_file_ffi:read_file(Snapshot_path) of
{ok, Expected} ->
compare_snapshot_inspect(
Value,
Serialized,
normalize_snapshot_expected(Expected),
Snapshot_path
);
{error, {not_found, _}} ->
create_snapshot_inspect(Value, Serialized, Snapshot_path);
{error, Error} ->
make_read_error_failure_inspect(Snapshot_path, Error)
end.
-file("src/dream_test/matchers/snapshot.gleam", 108).
?DOC(
" Assert that any value matches a snapshot when serialized.\n"
"\n"
" Use this when testing complex data structures that aren't strings.\n"
" The value is converted to a string using `string.inspect`, which\n"
" produces Gleam's debug representation.\n"
"\n"
" ## When to Use This\n"
"\n"
" - Testing return values of functions (records, tuples, lists)\n"
" - Comparing parsed AST structures\n"
" - Verifying complex state after operations\n"
"\n"
" ## Parameters\n"
"\n"
" - `value_or_result` - The `MatchResult(value)` from the assertion chain\n"
" - `snapshot_path` - Path to the snapshot file\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let path = \"./test/tmp/match_snapshot_inspect_example.snap\"\n"
" Some(1)\n"
" |> should\n"
" |> match_snapshot_inspect(path)\n"
" |> or_fail_with(\"expected inspect snapshot match\")\n"
" ```\n"
"\n"
" ## Returns\n"
"\n"
" A `MatchResult(value)`:\n"
" - On success, preserves the original value for further chaining.\n"
" - On failure, the chain becomes failed and later matchers are skipped.\n"
).
-spec match_snapshot_inspect(dream_test@types:match_result(HSU), binary()) -> dream_test@types:match_result(HSU).
match_snapshot_inspect(Value_or_result, Snapshot_path) ->
case Value_or_result of
{match_failed, Failure} ->
{match_failed, Failure};
{match_ok, Value} ->
check_snapshot_inspect(Value, Snapshot_path)
end.