@@ -236,15 +236,14 @@ defmodule PhoenixTest.Playwright do
236
236
conn
237
237
end
238
238
239
+ # In your test, first call `|> tap(&Connection.subscribe(&1.page_id))`
239
240
def assert_download(conn, name, contains: content) do
240
241
assert_receive({:playwright, %{method: :download} = download_msg}, 2000)
241
- artifact_guid = download_msg.params.artifact.guid
242
- assert_receive({:playwright, %{method: :__create__, params: %{guid: ^artifact_guid}} = artifact_msg}, 2000)
243
- download_path = artifact_msg.params.initializer.absolute_path
244
- wait_for_file(download_path)
242
+ path = Connection.initializer(download_msg.params.artifact.guid).absolute_path
243
+ wait_for_file(path)
245
244
246
245
assert download_msg.params.suggested_filename =~ name
247
- assert File.read!(download_path ) =~ content
246
+ assert File.read!(path ) =~ content
248
247
249
248
conn
250
249
end
@@ -334,15 +333,25 @@ defmodule PhoenixTest.Playwright do
334
333
alias PhoenixTest.OpenBrowser
335
334
alias PhoenixTest.Playwright.BrowserContext
336
335
alias PhoenixTest.Playwright.Config
337
- alias PhoenixTest.Playwright.Connection
338
336
alias PhoenixTest.Playwright.CookieArgs
337
+ alias PhoenixTest.Playwright.Dialog
338
+ alias PhoenixTest.Playwright.EventListener
339
+ alias PhoenixTest.Playwright.EventRecorder
339
340
alias PhoenixTest.Playwright.Frame
340
341
alias PhoenixTest.Playwright.Page
341
342
alias PhoenixTest.Playwright.Selector
342
343
343
344
require Logger
344
345
345
- defstruct [ :context_id , :page_id , :frame_id , :last_input_selector , within: :none ]
346
+ defstruct [
347
+ :context_id ,
348
+ :page_id ,
349
+ :frame_id ,
350
+ :navigate_recorder_pid ,
351
+ :dialog_listener_pid ,
352
+ :last_input_selector ,
353
+ within: :none
354
+ ]
346
355
347
356
@ opaque t :: % __MODULE__ { }
348
357
@ type css_selector :: String . t ( )
@@ -355,8 +364,26 @@ defmodule PhoenixTest.Playwright do
355
364
@ endpoint Application . compile_env ( :phoenix_test , :endpoint )
356
365
357
366
@ doc false
358
- def build ( context_id , page_id , frame_id ) do
359
- % __MODULE__ { context_id: context_id , page_id: page_id , frame_id: frame_id }
367
+ def build ( % { context_id: context_id , page_id: page_id , frame_id: frame_id , config: config } ) do
368
+ % __MODULE__ {
369
+ context_id: context_id ,
370
+ page_id: page_id ,
371
+ frame_id: frame_id ,
372
+ navigate_recorder_pid: start_navigate_recorder ( frame_id ) ,
373
+ dialog_listener_pid: start_dialog_listener ( page_id , config [ :accept_dialogs ] )
374
+ }
375
+ end
376
+
377
+ defp start_navigate_recorder ( frame_id ) do
378
+ args = % { guid: frame_id , filter: & match? ( % { method: :navigated } , & 1 ) }
379
+ ExUnit.Callbacks . start_supervised! ( { EventRecorder , args } , id: "#{ frame_id } -navigate-recorder" )
380
+ end
381
+
382
+ defp start_dialog_listener ( page_id , auto_accept? ) do
383
+ filter = & match? ( % { method: :__create__ , params: % { type: "Dialog" } } , & 1 )
384
+ callback = & if ( auto_accept? , do: { :ok , _ } = Dialog . accept ( & 1 . params . guid ) )
385
+ args = % { guid: page_id , filter: filter , callback: callback }
386
+ ExUnit.Callbacks . start_supervised! ( { EventListener , args } , id: "#{ page_id } -dialog-listener" )
360
387
end
361
388
362
389
@ doc false
@@ -624,6 +651,55 @@ defmodule PhoenixTest.Playwright do
624
651
end
625
652
end
626
653
654
+ @ doc """
655
+ Handle browser dialogs (`alert()`, `confirm()`, `prompt()`) while executing the inner function.
656
+
657
+ *Note:* Add `@tag accept_dialogs: false` before tests that call this function.
658
+ Otherwise, all dialogs are accepted by default.
659
+
660
+ ## Callback return values
661
+ The callback may return one of these values:
662
+ - `:accept` -> accepts confirmation dialog
663
+ - `{:accept, prompt_text}` -> accepts prompt dialog with text
664
+ - `:dismiss` -> dismisses dialog
665
+ - Any other value will ignore the dialog
666
+
667
+ ## Examples
668
+ @tag accept_dialogs: false
669
+ test "conditionally handle dialog", %{conn: conn} do
670
+ conn
671
+ |> visit("/")
672
+ |> with_dialog(
673
+ fn
674
+ %{message: "Are you sure?"} -> :accept
675
+ %{message: "Enter the magic number"} -> {:accept, "42"}
676
+ %{message: "Self destruct?"} -> :dismiss
677
+ end,
678
+ fn conn ->
679
+ conn
680
+ |> click_button("Delete")
681
+ |> assert_has(".flash", text: "Deleted")
682
+ end
683
+ end)
684
+ end
685
+ """
686
+ def with_dialog ( session , callback , fun ) when is_function ( callback , 1 ) and is_function ( fun , 1 ) do
687
+ event_callback = fn % { params: % { guid: guid , initializer: % { message: message } } } ->
688
+ { :ok , _ } =
689
+ case callback . ( % { guid: guid , message: message } ) do
690
+ :accept -> Dialog . accept ( guid )
691
+ { :accept , prompt_text } -> Dialog . accept ( guid , prompt_text: prompt_text )
692
+ :dismiss -> Dialog . dismiss ( guid )
693
+ _ -> { :ok , :ignore }
694
+ end
695
+ end
696
+
697
+ session
698
+ |> tap ( & EventListener . push_callback ( & 1 . dialog_listener_pid , event_callback ) )
699
+ |> fun . ( )
700
+ |> tap ( & EventListener . pop_callback ( & 1 . dialog_listener_pid ) )
701
+ end
702
+
627
703
@ doc false
628
704
def render_page_title ( conn ) do
629
705
case Frame . title ( conn . frame_id ) do
@@ -889,14 +965,8 @@ defmodule PhoenixTest.Playwright do
889
965
890
966
@ doc false
891
967
def current_path ( conn ) do
892
- resp =
893
- conn . frame_id
894
- |> Connection . received ( )
895
- |> Enum . find ( & match? ( % { method: :navigated , params: % { url: _ } } , & 1 ) )
896
-
897
- if resp == nil , do: raise ( ArgumentError , "Could not find current path." )
898
-
899
- uri = URI . parse ( resp . params . url )
968
+ [ event | _ ] = EventRecorder . events ( conn . navigate_recorder_pid )
969
+ uri = URI . parse ( event . params . url )
900
970
[ uri . path , uri . query ] |> Enum . reject ( & is_nil / 1 ) |> Enum . join ( "?" )
901
971
end
902
972
0 commit comments