diff --git a/lib/playwright_ex/channels/frame.ex b/lib/playwright_ex/channels/frame.ex index 2a13400..11cc7d9 100644 --- a/lib/playwright_ex/channels/frame.ex +++ b/lib/playwright_ex/channels/frame.ex @@ -277,9 +277,14 @@ defmodule PlaywrightEx.Frame do connection |> Connection.send(%{guid: frame_id, method: :expect, params: Map.new(opts)}, timeout) - |> ChannelResponse.unwrap_expect(is_not) + |> ChannelResponse.unwrap(& &1) + |> matches?(is_not) end + defp matches?({:error, {%{error: %{name: "ExpectError"}}, %{timed_out: true}}}, is_not), do: {:ok, is_not} + defp matches?({:error, error}, _is_not), do: {:error, error} + defp matches?({:ok, _}, is_not), do: {:ok, not is_not} + schema = NimbleOptions.new!( connection: PlaywrightEx.Channel.connection_opt(), diff --git a/lib/playwright_ex/channels/page.ex b/lib/playwright_ex/channels/page.ex index d9ffdcf..cd8e6dd 100644 --- a/lib/playwright_ex/channels/page.ex +++ b/lib/playwright_ex/channels/page.ex @@ -448,24 +448,20 @@ defmodule PlaywrightEx.Page do @schema schema @type expect_screenshot_opt :: unquote(NimbleOptions.option_typespec(schema)) @spec expect_screenshot(PlaywrightEx.guid(), [expect_screenshot_opt() | PlaywrightEx.unknown_opt()]) :: - {:ok, binary() | nil} | {:error, any()} + {:ok, binary() | nil} | {:error, {map(), map()}} | {:error, any()} def expect_screenshot(page_id, opts \\ []) do {connection, opts} = opts |> PlaywrightEx.Channel.validate_known!(@schema) |> Keyword.pop!(:connection) {timeout, opts} = Keyword.pop!(opts, :timeout) connection |> Connection.send(%{guid: page_id, method: :expectScreenshot, params: Map.new(opts)}, timeout) - |> unwrap_expect() + |> ChannelResponse.unwrap(& &1[:actual]) + |> case do + {:ok, result} -> {:ok, result} + {:error, error} -> {:error, error} + end end - # Playwright >= 1.61.0 - defp unwrap_expect(%{error_details: details}), do: {:error, details} - # Playwright < 1.61.0 - defp unwrap_expect(%{result: %{error_message: msg} = result}), do: {:error, Map.put(result, :custom_error_message, msg)} - - defp unwrap_expect(%{result: result}), do: {:ok, result[:actual]} - defp unwrap_expect(result), do: {:ok, result} - defp main_frame_id!(connection, page_id) do page_initializer = Connection.initializer!(connection, page_id) page_initializer.main_frame.guid diff --git a/lib/playwright_ex/periphery/channel_response.ex b/lib/playwright_ex/periphery/channel_response.ex index f516ab9..fade494 100644 --- a/lib/playwright_ex/periphery/channel_response.ex +++ b/lib/playwright_ex/periphery/channel_response.ex @@ -4,25 +4,11 @@ defmodule PlaywrightEx.ChannelResponse do alias PlaywrightEx.Connection @spec unwrap(any(), (any() -> result)) :: {:ok, result} | {:error, any()} when result: any() + def unwrap(%{error: %{} = error, error_details: details}, _), do: {:error, {error, details}} def unwrap(%{error: error}, _), do: {:error, error} def unwrap(%{result: result}, fun) when is_function(fun, 1), do: {:ok, fun.(result)} def unwrap(other, fun) when is_function(fun, 1), do: {:ok, other} - @doc """ - Unwraps a `Frame.expect` reply into `{:ok, matches?}`, applying `is_not`. - - Playwright 1.60 replied `%{result: %{matches: boolean}}`. 1.61 dropped that - field and signals the outcome by success-vs-error: a non-match returns an - error carrying `error_details`. Mirrors playwright-core's `Frame._expect`, so - `matches?` (raw positive-condition result, `is_not` applied) stays identical - across drivers; a genuine 1.60 error still propagates as `{:error, _}`. - """ - @spec unwrap_expect(map(), boolean()) :: {:ok, boolean()} | {:error, any()} - def unwrap_expect(%{result: %{matches: matches}}, _is_not) when is_boolean(matches), do: {:ok, matches} - def unwrap_expect(%{error_details: _details}, is_not) when is_boolean(is_not), do: {:ok, is_not} - def unwrap_expect(%{error: error}, _is_not), do: {:error, error} - def unwrap_expect(reply, is_not) when is_map(reply) and is_boolean(is_not), do: {:ok, not is_not} - @spec unwrap_create(any(), atom(), GenServer.name()) :: {:ok, any()} | {:error, any()} def unwrap_create(value, resource_name, connection) when is_atom(resource_name) do unwrap(value, fn result -> diff --git a/test/playwright_ex/page_test.exs b/test/playwright_ex/page_test.exs index b8f46a8..50a50b9 100644 --- a/test/playwright_ex/page_test.exs +++ b/test/playwright_ex/page_test.exs @@ -61,14 +61,15 @@ defmodule PlaywrightEx.PageTest do {:ok, _} = Frame.goto(frame.guid, url: "about:blank", timeout: @timeout) assert {:error, - %{ - timed_out: false, - custom_error_message: - "Expected an image 1px by 1px, received 1280px by 720px. 1 pixels (ratio 0.01 of all image pixels) are different.", - log: _, - diff: _, - actual: _ - }} = + {_, + %{ + timed_out: false, + custom_error_message: + "Expected an image 1px by 1px, received 1280px by 720px. 1 pixels (ratio 0.01 of all image pixels) are different.", + log: _, + diff: _, + actual: _ + }}} = Page.expect_screenshot(page.guid, expected: @red_px_png, timeout: @timeout) end diff --git a/test/playwright_ex/periphery/channel_response_test.exs b/test/playwright_ex/periphery/channel_response_test.exs deleted file mode 100644 index 10ddf8d..0000000 --- a/test/playwright_ex/periphery/channel_response_test.exs +++ /dev/null @@ -1,40 +0,0 @@ -defmodule PlaywrightEx.ChannelResponseTest do - use ExUnit.Case, async: true - - alias PlaywrightEx.ChannelResponse - - describe "unwrap_expect/2" do - test "1.60 reply: trusts result.matches regardless of is_not" do - assert {:ok, true} = ChannelResponse.unwrap_expect(%{id: 1, result: %{matches: true}}, false) - assert {:ok, false} = ChannelResponse.unwrap_expect(%{id: 1, result: %{matches: false}}, false) - assert {:ok, true} = ChannelResponse.unwrap_expect(%{id: 1, result: %{matches: true}}, true) - end - - test "1.61 satisfied reply (no result/error): matches == not is_not" do - assert {:ok, true} = ChannelResponse.unwrap_expect(%{id: 6, method: nil}, false) - assert {:ok, false} = ChannelResponse.unwrap_expect(%{id: 6, method: nil}, true) - end - - test "1.61 unsatisfied reply (error + error_details): matches == is_not" do - reply = %{ - id: 27, - method: nil, - error: %{error: %{message: "Expect failed", name: "ExpectError", stack: "..."}}, - log: [" - Expect \"to.be.visible\" with timeout 2000ms"], - error_details: %{ - timed_out: true, - received: %{value: %{v: "undefined"}, aria_snapshot: "- text: hello"}, - custom_error_message: "element(s) not found" - } - } - - assert {:ok, false} = ChannelResponse.unwrap_expect(reply, false) - assert {:ok, true} = ChannelResponse.unwrap_expect(reply, true) - end - - test "genuine protocol error without error_details still propagates" do - reply = %{id: 9, error: %{error: %{message: "boom", name: "Error", stack: "..."}}} - assert {:error, %{error: %{name: "Error"}}} = ChannelResponse.unwrap_expect(reply, false) - end - end -end