-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] -> <<<>/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).