-module(lightspeed@testing@liveview).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lightspeed/testing/liveview.gleam").
-export([lifecycle_label/1, mount_disconnected/5, mount_connected/5, render_assigns/2, render_event/3, html/1, lifecycle/1, patches/1, patch_operations/1, pushed_instructions/1, telemetry/1, has_patch/2, redirected_to/2, pushed_event/3, stable_signature/1, failure_signature/4, render_story_fixture/1, story_name/1, story_html/1, story_fingerprint/1, story_signature/1]).
-export_type([session/3, story_fixture/0]).
-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(" LiveView-style deterministic testing DSL and debug signatures.\n").
-opaque session(TYW, TYX, TYY) :: {session,
lightspeed@component@stateful:instance(TYW, TYX, TYY),
binary(),
binary(),
lightspeed@component@stateful:lifecycle(),
list(lightspeed@diff:patch()),
list(lightspeed@agent@isa:instruction()),
list(binary()),
integer()}.
-type story_fixture() :: {story_fixture, binary(), binary(), binary(), binary()}.
-file("src/lightspeed/testing/liveview.gleam", 399).
-spec append_ordered_to_rev(list(UEJ), list(UEJ)) -> list(UEJ).
append_ordered_to_rev(Rev, Ordered) ->
case Ordered of
[] ->
Rev;
[Value | Rest] ->
append_ordered_to_rev([Value | Rev], Rest)
end.
-file("src/lightspeed/testing/liveview.gleam", 146).
?DOC(" Stable lifecycle label for fixture signatures.\n").
-spec lifecycle_label(lightspeed@component@stateful:lifecycle()) -> binary().
lifecycle_label(Lifecycle) ->
case Lifecycle of
disconnected ->
<<"disconnected"/utf8>>;
connected ->
<<"connected"/utf8>>
end.
-file("src/lightspeed/testing/liveview.gleam", 345).
-spec instruction_labels(list(lightspeed@agent@isa:instruction())) -> list(binary()).
instruction_labels(Instructions) ->
gleam@list:map(
Instructions,
fun(Instruction) ->
<<"instruction:"/utf8,
(lightspeed@agent@isa:describe(Instruction))/binary>>
end
).
-file("src/lightspeed/testing/liveview.gleam", 406).
-spec prepend(list(UEN), list(UEN)) -> list(UEN).
prepend(Left, Right) ->
case Left of
[] ->
Right;
[Entry | Rest] ->
[Entry | prepend(Rest, Right)]
end.
-file("src/lightspeed/testing/liveview.gleam", 339).
-spec patch_labels(list(lightspeed@diff:patch())) -> list(binary()).
patch_labels(Patches) ->
gleam@list:map(
Patches,
fun(Patch) ->
<<<<<<"patch:"/utf8, (lightspeed@diff:operation(Patch))/binary>>/binary,
":"/utf8>>/binary,
(lightspeed@diff:target(Patch))/binary>>
end
).
-file("src/lightspeed/testing/liveview.gleam", 324).
-spec command_instructions_loop(
list(lightspeed@component:command(any())),
list(lightspeed@agent@isa:instruction())
) -> list(lightspeed@agent@isa:instruction()).
command_instructions_loop(Commands, Instructions_rev) ->
case Commands of
[] ->
lists:reverse(Instructions_rev);
[Command | Rest] ->
case Command of
{push, Instruction} ->
command_instructions_loop(
Rest,
[Instruction | Instructions_rev]
);
_ ->
command_instructions_loop(Rest, Instructions_rev)
end
end.
-file("src/lightspeed/testing/liveview.gleam", 318).
-spec command_instructions(list(lightspeed@component:command(any()))) -> list(lightspeed@agent@isa:instruction()).
command_instructions(Commands) ->
command_instructions_loop(Commands, []).
-file("src/lightspeed/testing/liveview.gleam", 279).
-spec mount_with_lifecycle(
lightspeed@component@stateful:lifecycle_component(UDH, UDI, UDJ),
binary(),
binary(),
lightspeed@component@stateful:lifecycle(),
UDI,
binary()
) -> session(UDH, UDI, UDJ).
mount_with_lifecycle(Definition, Id, Route, Lifecycle, Assigns, Target) ->
Context = lightspeed@component@stateful:mount_context(Id, Route, Lifecycle),
{Instance, Commands, Patches} = lightspeed@component@stateful:start(
Definition,
Context,
Assigns,
Target
),
Instructions = command_instructions(Commands),
Telemetry_step = prepend(
patch_labels(Patches),
prepend(
instruction_labels(Instructions),
[<<<<<<"mount:"/utf8, (lifecycle_label(Lifecycle))/binary>>/binary,
":"/utf8>>/binary,
Route/binary>>]
)
),
{session,
Instance,
Route,
Target,
Lifecycle,
append_ordered_to_rev([], Patches),
append_ordered_to_rev([], Instructions),
append_ordered_to_rev([], Telemetry_step),
1}.
-file("src/lightspeed/testing/liveview.gleam", 37).
?DOC(" Mount a stateful component in disconnected lifecycle mode.\n").
-spec mount_disconnected(
lightspeed@component@stateful:lifecycle_component(TYZ, TZA, TZB),
binary(),
binary(),
TZA,
binary()
) -> session(TYZ, TZA, TZB).
mount_disconnected(Definition, Id, Route, Assigns, Target) ->
mount_with_lifecycle(Definition, Id, Route, disconnected, Assigns, Target).
-file("src/lightspeed/testing/liveview.gleam", 55).
?DOC(" Mount a stateful component in connected lifecycle mode.\n").
-spec mount_connected(
lightspeed@component@stateful:lifecycle_component(TZI, TZJ, TZK),
binary(),
binary(),
TZJ,
binary()
) -> session(TZI, TZJ, TZK).
mount_connected(Definition, Id, Route, Assigns, Target) ->
mount_with_lifecycle(Definition, Id, Route, connected, Assigns, Target).
-file("src/lightspeed/testing/liveview.gleam", 73).
?DOC(" Apply parent assigns and capture emitted patches/commands in one test step.\n").
-spec render_assigns(session(TZR, TZS, TZT), TZS) -> session(TZR, TZS, TZT).
render_assigns(Session, Assigns) ->
{Instance, Commands, Patches} = lightspeed@component@stateful:update(
erlang:element(2, Session),
Assigns
),
Instructions = command_instructions(Commands),
Telemetry_step = prepend(
patch_labels(Patches),
prepend(instruction_labels(Instructions), [<<"assigns:update"/utf8>>])
),
{session,
Instance,
erlang:element(3, Session),
erlang:element(4, Session),
erlang:element(5, Session),
append_ordered_to_rev(erlang:element(6, Session), Patches),
append_ordered_to_rev(erlang:element(7, Session), Instructions),
append_ordered_to_rev(erlang:element(8, Session), Telemetry_step),
erlang:element(9, Session) + 1}.
-file("src/lightspeed/testing/liveview.gleam", 311).
-spec event_label(
binary(),
{ok, any()} | {error, lightspeed@event:decode_error()}
) -> binary().
event_label(Name, Routed) ->
case Routed of
{ok, _} ->
<<<<"event:"/utf8, Name/binary>>/binary, ":ok"/utf8>>;
{error, Error} ->
<<<<<<"event:"/utf8, Name/binary>>/binary, ":"/utf8>>/binary,
(lightspeed@event:error_to_string(Error))/binary>>
end.
-file("src/lightspeed/testing/liveview.gleam", 100).
?DOC(" Route and render one event against the mounted component.\n").
-spec render_event(session(UAA, UAB, UAC), binary(), binary()) -> {session(UAA, UAB, UAC),
{ok, UAC} | {error, lightspeed@event:decode_error()}}.
render_event(Session, Name, Payload) ->
Inbound = lightspeed@event:inbound(Name, Payload),
{Instance, Routed, Commands, Patches} = lightspeed@component@stateful:handle_event(
erlang:element(2, Session),
Inbound
),
Instructions = command_instructions(Commands),
Telemetry_step = prepend(
patch_labels(Patches),
prepend(instruction_labels(Instructions), [event_label(Name, Routed)])
),
{{session,
Instance,
erlang:element(3, Session),
erlang:element(4, Session),
erlang:element(5, Session),
append_ordered_to_rev(erlang:element(6, Session), Patches),
append_ordered_to_rev(erlang:element(7, Session), Instructions),
append_ordered_to_rev(erlang:element(8, Session), Telemetry_step),
erlang:element(9, Session) + 1},
Routed}.
-file("src/lightspeed/testing/liveview.gleam", 135).
?DOC(" Current rendered HTML.\n").
-spec html(session(any(), any(), any())) -> binary().
html(Session) ->
_pipe = erlang:element(2, Session),
lightspeed@component@stateful:html(_pipe).
-file("src/lightspeed/testing/liveview.gleam", 141).
?DOC(" Mount lifecycle mode.\n").
-spec lifecycle(session(any(), any(), any())) -> lightspeed@component@stateful:lifecycle().
lifecycle(Session) ->
erlang:element(5, Session).
-file("src/lightspeed/testing/liveview.gleam", 154).
?DOC(" All emitted patches in execution order.\n").
-spec patches(session(any(), any(), any())) -> list(lightspeed@diff:patch()).
patches(Session) ->
lists:reverse(erlang:element(6, Session)).
-file("src/lightspeed/testing/liveview.gleam", 159).
?DOC(" Patch operation labels in execution order.\n").
-spec patch_operations(session(any(), any(), any())) -> list(binary()).
patch_operations(Session) ->
_pipe = Session,
_pipe@1 = patches(_pipe),
gleam@list:map(_pipe@1, fun lightspeed@diff:operation/1).
-file("src/lightspeed/testing/liveview.gleam", 166).
?DOC(" All pushed ISA instructions in execution order.\n").
-spec pushed_instructions(session(any(), any(), any())) -> list(lightspeed@agent@isa:instruction()).
pushed_instructions(Session) ->
lists:reverse(erlang:element(7, Session)).
-file("src/lightspeed/testing/liveview.gleam", 173).
?DOC(" Stable telemetry/debug labels in execution order.\n").
-spec telemetry(session(any(), any(), any())) -> list(binary()).
telemetry(Session) ->
lists:reverse(erlang:element(8, Session)).
-file("src/lightspeed/testing/liveview.gleam", 351).
-spec contains_patch(list(lightspeed@diff:patch()), lightspeed@diff:patch()) -> boolean().
contains_patch(Patches, Expected) ->
case Patches of
[] ->
false;
[Patch | Rest] ->
case Patch =:= Expected of
true ->
true;
false ->
contains_patch(Rest, Expected)
end
end.
-file("src/lightspeed/testing/liveview.gleam", 178).
?DOC(" Assertion helper for expected patch output.\n").
-spec has_patch(session(any(), any(), any()), lightspeed@diff:patch()) -> boolean().
has_patch(Session, Patch) ->
contains_patch(patches(Session), Patch).
-file("src/lightspeed/testing/liveview.gleam", 362).
-spec contains_navigation(list(lightspeed@agent@isa:instruction()), binary()) -> boolean().
contains_navigation(Instructions, To) ->
case Instructions of
[] ->
false;
[Instruction | Rest] ->
case Instruction of
{navigate, Path} ->
case Path =:= To of
true ->
true;
false ->
contains_navigation(Rest, To)
end;
_ ->
contains_navigation(Rest, To)
end
end.
-file("src/lightspeed/testing/liveview.gleam", 186).
?DOC(" Assertion helper for redirect/navigation behavior.\n").
-spec redirected_to(session(any(), any(), any()), binary()) -> boolean().
redirected_to(Session, To) ->
contains_navigation(pushed_instructions(Session), To).
-file("src/lightspeed/testing/liveview.gleam", 380).
-spec contains_push_event(
list(lightspeed@agent@isa:instruction()),
binary(),
binary()
) -> boolean().
contains_push_event(Instructions, Name, Payload) ->
case Instructions of
[] ->
false;
[Instruction | Rest] ->
case Instruction of
{push_event, Event_name, Event_payload} ->
case (Event_name =:= Name) andalso (Event_payload =:= Payload) of
true ->
true;
false ->
contains_push_event(Rest, Name, Payload)
end;
_ ->
contains_push_event(Rest, Name, Payload)
end
end.
-file("src/lightspeed/testing/liveview.gleam", 194).
?DOC(" Assertion helper for pushed server-event behavior.\n").
-spec pushed_event(session(any(), any(), any()), binary(), binary()) -> boolean().
pushed_event(Session, Name, Payload) ->
contains_push_event(pushed_instructions(Session), Name, Payload).
-file("src/lightspeed/testing/liveview.gleam", 413).
-spec join_with(binary(), list(binary())) -> binary().
join_with(Separator, Values) ->
case Values of
[] ->
<<""/utf8>>;
[Value] ->
Value;
[Value@1 | Rest] ->
<<<<Value@1/binary, Separator/binary>>/binary,
(join_with(Separator, Rest))/binary>>
end.
-file("src/lightspeed/testing/liveview.gleam", 203).
?DOC(" Stable deterministic session signature for CI fixtures and debug output.\n").
-spec stable_signature(session(any(), any(), any())) -> binary().
stable_signature(Session) ->
<<<<<<<<<<<<<<<<<<<<<<<<<<"lifecycle="/utf8,
(lifecycle_label(
erlang:element(
5,
Session
)
))/binary>>/binary,
"|route="/utf8>>/binary,
(erlang:element(3, Session))/binary>>/binary,
"|target="/utf8>>/binary,
(erlang:element(4, Session))/binary>>/binary,
"|steps="/utf8>>/binary,
(erlang:integer_to_binary(
erlang:element(9, Session)
))/binary>>/binary,
"|patch_ops="/utf8>>/binary,
(join_with(<<","/utf8>>, patch_operations(Session)))/binary>>/binary,
"|instructions="/utf8>>/binary,
(join_with(
<<","/utf8>>,
gleam@list:map(
pushed_instructions(Session),
fun lightspeed@agent@isa:describe/1
)
))/binary>>/binary,
"|telemetry="/utf8>>/binary,
(join_with(<<","/utf8>>, telemetry(Session)))/binary>>.
-file("src/lightspeed/testing/liveview.gleam", 221).
?DOC(" Stable failure signature helper for assertions and fixture diagnostics.\n").
-spec failure_signature(
session(any(), any(), any()),
binary(),
binary(),
binary()
) -> binary().
failure_signature(Session, Assertion, Expected, Actual) ->
<<<<<<<<<<<<<<"assertion="/utf8, Assertion/binary>>/binary,
"|expected="/utf8>>/binary,
Expected/binary>>/binary,
"|actual="/utf8>>/binary,
Actual/binary>>/binary,
"|"/utf8>>/binary,
(stable_signature(Session))/binary>>.
-file("src/lightspeed/testing/liveview.gleam", 238).
?DOC(" Render one template story fixture with deterministic metadata.\n").
-spec render_story_fixture(lightspeed@component@story:story(any(), any())) -> story_fixture().
render_story_fixture(Fixture_story) ->
Rendered = lightspeed@component@story:render(Fixture_story),
Html = lightspeed@component:to_html(Rendered),
Fingerprint = lightspeed@component:fingerprint(Rendered),
Name = lightspeed@component@story:name(Fixture_story),
{story_fixture,
Name,
Html,
Fingerprint,
<<<<<<<<<<"story="/utf8, Name/binary>>/binary, "|fingerprint="/utf8>>/binary,
Fingerprint/binary>>/binary,
"|html="/utf8>>/binary,
Html/binary>>}.
-file("src/lightspeed/testing/liveview.gleam", 260).
?DOC(" Fixture story name.\n").
-spec story_name(story_fixture()) -> binary().
story_name(Fixture) ->
erlang:element(2, Fixture).
-file("src/lightspeed/testing/liveview.gleam", 265).
?DOC(" Fixture story HTML.\n").
-spec story_html(story_fixture()) -> binary().
story_html(Fixture) ->
erlang:element(3, Fixture).
-file("src/lightspeed/testing/liveview.gleam", 270).
?DOC(" Fixture story fingerprint.\n").
-spec story_fingerprint(story_fixture()) -> binary().
story_fingerprint(Fixture) ->
erlang:element(4, Fixture).
-file("src/lightspeed/testing/liveview.gleam", 275).
?DOC(" Fixture story stable signature.\n").
-spec story_signature(story_fixture()) -> binary().
story_signature(Fixture) ->
erlang:element(5, Fixture).