From 77760e215f5da249c702976efaaabcfa6ba5b614 Mon Sep 17 00:00:00 2001 From: Chris Nelson Date: Wed, 15 Mar 2023 14:11:10 -0400 Subject: [PATCH 01/10] WIP --- .../cases/browser/shadow_dom_test.exs | 22 +++++++++++++++++++ .../support/pages/shadow_dom.html | 17 ++++++++++++++ lib/wallaby/browser.ex | 20 +++++++++++++++++ lib/wallaby/chrome.ex | 3 +++ lib/wallaby/driver.ex | 6 +++++ lib/wallaby/webdriver_client.ex | 12 ++++++++++ 6 files changed, 80 insertions(+) create mode 100644 integration_test/cases/browser/shadow_dom_test.exs create mode 100644 integration_test/support/pages/shadow_dom.html diff --git a/integration_test/cases/browser/shadow_dom_test.exs b/integration_test/cases/browser/shadow_dom_test.exs new file mode 100644 index 00000000..0e1defc6 --- /dev/null +++ b/integration_test/cases/browser/shadow_dom_test.exs @@ -0,0 +1,22 @@ +defmodule Wallaby.Integration.Browser.ShadowDomTest do + + use Wallaby.Integration.SessionCase, async: true + + import Wallaby.Query, only: [css: 1] + + setup %{session: session} do + page = + session + |> visit("shadow_dom.html") + + {:ok, page: page} + end + + test "can find a shadow root", %{session: session} do + element = + session + |> find_shadow(Query.css("shadow-test")) + + assert element + end +end diff --git a/integration_test/support/pages/shadow_dom.html b/integration_test/support/pages/shadow_dom.html new file mode 100644 index 00000000..773ffe90 --- /dev/null +++ b/integration_test/support/pages/shadow_dom.html @@ -0,0 +1,17 @@ + + + + + + +
I am out of shadow
+ + + \ No newline at end of file diff --git a/lib/wallaby/browser.ex b/lib/wallaby/browser.ex index c2327a18..2e93e092 100644 --- a/lib/wallaby/browser.ex +++ b/lib/wallaby/browser.ex @@ -999,6 +999,26 @@ defmodule Wallaby.Browser do parent end + def find_shadow(%{driver: driver}, query) do + retry(fn -> + try do + with {:ok, query} <- Query.validate(query), + compiled_query <- Query.compile(query), + {:ok, elements} <- driver.find_shadow(parent, compiled_query), + {:ok, elements} <- validate_visibility(query, elements), + {:ok, elements} <- validate_text(query, elements), + {:ok, elements} <- validate_selected(query, elements), + {:ok, elements} <- validate_count(query, elements), + {:ok, elements} <- do_at(query, elements) do + elements + end + rescue + StaleReferenceError -> + {:error, :stale_reference} + end + end) + end + @doc """ Finds all of the DOM elements that match the CSS selector. If no elements are found then an empty list is immediately returned. This is equivalent to calling diff --git a/lib/wallaby/chrome.ex b/lib/wallaby/chrome.ex index 82049d7b..f8b93648 100644 --- a/lib/wallaby/chrome.ex +++ b/lib/wallaby/chrome.ex @@ -531,6 +531,9 @@ defmodule Wallaby.Chrome do def find_elements(session_or_element, compiled_query), do: delegate(:find_elements, session_or_element, [compiled_query]) + def find_shadow(session_or_element, compiled_query), + do: delegate(:find_shadow, session_or_element, [compiled_query]) + @doc false def send_keys(session_or_element, keys), do: delegate(:send_keys, session_or_element, [keys]) @doc false diff --git a/lib/wallaby/driver.ex b/lib/wallaby/driver.ex index 79630fc3..009f8226 100644 --- a/lib/wallaby/driver.ex +++ b/lib/wallaby/driver.ex @@ -180,6 +180,12 @@ defmodule Wallaby.Driver do @callback find_elements(Session.t() | Element.t(), Query.compiled()) :: {:ok, [Element.t()]} | {:error, reason} + @doc """ + Invoked to find child elements of the given session/element. + """ + @callback find_shadow(Session.t() | Element.t(), Query.compiled()) :: + {:ok, Element.t()} | {:error, reason} + @doc """ Invoked to execute JavaScript in the browser. """ diff --git a/lib/wallaby/webdriver_client.ex b/lib/wallaby/webdriver_client.ex index 92adf7d6..492afb4d 100644 --- a/lib/wallaby/webdriver_client.ex +++ b/lib/wallaby/webdriver_client.ex @@ -48,6 +48,18 @@ defmodule Wallaby.WebdriverClient do do: {:ok, elements} end + @doc """ + Finds an element on the page for a session. If an element is provided then + the query will be scoped to within that element. + """ + @spec find_elements(Session.t() | Element.t(), Query.compiled()) :: {:ok, [Element.t()]} + def find_elements(parent, locator) do + with {:ok, resp} <- request(:post, parent.url <> "/elements", to_params(locator)), + {:ok, elements} <- Map.fetch(resp, "value"), + elements <- Enum.map(elements || [], &cast_as_element(parent, &1)), + do: {:ok, elements} + end + @doc """ Sets the value of an element. """ From 708a79f1ef4201427a51727e389b0ee2f995c686 Mon Sep 17 00:00:00 2001 From: Chris Nelson Date: Wed, 15 Mar 2023 16:18:26 -0400 Subject: [PATCH 02/10] passing test --- .../cases/browser/shadow_dom_test.exs | 7 +++--- .../support/pages/shadow_dom.html | 7 +++--- lib/wallaby/browser.ex | 25 ++++--------------- lib/wallaby/chrome.ex | 6 ++--- lib/wallaby/driver.ex | 4 +-- lib/wallaby/webdriver_client.ex | 18 +++++++++++++ 6 files changed, 36 insertions(+), 31 deletions(-) diff --git a/integration_test/cases/browser/shadow_dom_test.exs b/integration_test/cases/browser/shadow_dom_test.exs index 0e1defc6..7ee211b6 100644 --- a/integration_test/cases/browser/shadow_dom_test.exs +++ b/integration_test/cases/browser/shadow_dom_test.exs @@ -13,10 +13,11 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do end test "can find a shadow root", %{session: session} do - element = + shadow_root = session - |> find_shadow(Query.css("shadow-test")) + |> find(Query.css("shadow-test")) + |> shadow_root() - assert element + assert shadow_root end end diff --git a/integration_test/support/pages/shadow_dom.html b/integration_test/support/pages/shadow_dom.html index 773ffe90..7aa965b7 100644 --- a/integration_test/support/pages/shadow_dom.html +++ b/integration_test/support/pages/shadow_dom.html @@ -1,12 +1,13 @@ diff --git a/lib/wallaby/browser.ex b/lib/wallaby/browser.ex index 2e93e092..17417a90 100644 --- a/lib/wallaby/browser.ex +++ b/lib/wallaby/browser.ex @@ -999,26 +999,6 @@ defmodule Wallaby.Browser do parent end - def find_shadow(%{driver: driver}, query) do - retry(fn -> - try do - with {:ok, query} <- Query.validate(query), - compiled_query <- Query.compile(query), - {:ok, elements} <- driver.find_shadow(parent, compiled_query), - {:ok, elements} <- validate_visibility(query, elements), - {:ok, elements} <- validate_text(query, elements), - {:ok, elements} <- validate_selected(query, elements), - {:ok, elements} <- validate_count(query, elements), - {:ok, elements} <- do_at(query, elements) do - elements - end - rescue - StaleReferenceError -> - {:error, :stale_reference} - end - end) - end - @doc """ Finds all of the DOM elements that match the CSS selector. If no elements are found then an empty list is immediately returned. This is equivalent to calling @@ -1032,6 +1012,11 @@ defmodule Wallaby.Browser do ) end + def shadow_root(%{driver: driver} = element) do + IO.inspect(driver) + driver.shadow_root(element) + end + @doc """ Validates that the query returns a result. This can be used to define other types of matchers. diff --git a/lib/wallaby/chrome.ex b/lib/wallaby/chrome.ex index f8b93648..306fa1a0 100644 --- a/lib/wallaby/chrome.ex +++ b/lib/wallaby/chrome.ex @@ -410,6 +410,9 @@ defmodule Wallaby.Chrome do defdelegate accept_prompt(session, input, fun), to: WebdriverClient @doc false defdelegate dismiss_prompt(session, fun), to: WebdriverClient + + defdelegate shadow_root(element), to: WebdriverClient + @doc false defdelegate parse_log(log), to: Wallaby.Chrome.Logger @@ -531,9 +534,6 @@ defmodule Wallaby.Chrome do def find_elements(session_or_element, compiled_query), do: delegate(:find_elements, session_or_element, [compiled_query]) - def find_shadow(session_or_element, compiled_query), - do: delegate(:find_shadow, session_or_element, [compiled_query]) - @doc false def send_keys(session_or_element, keys), do: delegate(:send_keys, session_or_element, [keys]) @doc false diff --git a/lib/wallaby/driver.ex b/lib/wallaby/driver.ex index 009f8226..2e50e1f9 100644 --- a/lib/wallaby/driver.ex +++ b/lib/wallaby/driver.ex @@ -181,9 +181,9 @@ defmodule Wallaby.Driver do {:ok, [Element.t()]} | {:error, reason} @doc """ - Invoked to find child elements of the given session/element. + Invoked to find shadow root of given element """ - @callback find_shadow(Session.t() | Element.t(), Query.compiled()) :: + @callback shadow_root(Element.t()) :: {:ok, Element.t()} | {:error, reason} @doc """ diff --git a/lib/wallaby/webdriver_client.ex b/lib/wallaby/webdriver_client.ex index 492afb4d..3bddc883 100644 --- a/lib/wallaby/webdriver_client.ex +++ b/lib/wallaby/webdriver_client.ex @@ -13,6 +13,7 @@ defmodule Wallaby.WebdriverClient do | Session.t() @web_element_identifier "element-6066-11e4-a52e-4f735466cecf" + @shadow_root_identifier "shadow-6066-11e4-a52e-4f735466cecf" @button_mapping %{left: 0, middle: 1, right: 2} @@ -60,6 +61,13 @@ defmodule Wallaby.WebdriverClient do do: {:ok, elements} end + def shadow_root(element) do + with {:ok, resp} <- request(:get, element.url <> "/shadow"), + {:ok, shadow_root} <- Map.fetch(resp, "value") do + cast_as_element(element, shadow_root) + end + end + @doc """ Sets the value of an element. """ @@ -711,6 +719,16 @@ defmodule Wallaby.WebdriverClient do } end + defp cast_as_element(parent, %{@shadow_root_identifier => id}) do + %Wallaby.Element{ + id: id, + session_url: parent.session_url, + url: parent.session_url <> "/shadow/#{id}", + parent: parent, + driver: parent.driver + } + end + # Retrieves the text from an alert, prompt or confirm. @spec alert_text(Session.t()) :: {:ok, String.t()} defp alert_text(session) do From bb932b4490191760c2ddcd66a0cd2b0446f562be Mon Sep 17 00:00:00 2001 From: Chris Nelson Date: Wed, 15 Mar 2023 16:28:53 -0400 Subject: [PATCH 03/10] shadow_root works --- .../cases/browser/shadow_dom_test.exs | 17 +++++++++++++++++ integration_test/support/pages/shadow_dom.html | 5 ++++- lib/wallaby/browser.ex | 1 - 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/integration_test/cases/browser/shadow_dom_test.exs b/integration_test/cases/browser/shadow_dom_test.exs index 7ee211b6..74b26c3d 100644 --- a/integration_test/cases/browser/shadow_dom_test.exs +++ b/integration_test/cases/browser/shadow_dom_test.exs @@ -20,4 +20,21 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do assert shadow_root end + + test "can find stuff within da shadow dom", %{session: session} do + element = + session + |> find(Query.css("shadow-test")) + |> shadow_root() + |> find(Query.css("#in-shadow")) + end + + test "can click stuff within da shadow dom", %{session: session} do + element = + session + |> find(Query.css("shadow-test")) + |> shadow_root() + |> click(Query.css("button")) + end + end diff --git a/integration_test/support/pages/shadow_dom.html b/integration_test/support/pages/shadow_dom.html index 7aa965b7..f01fae0b 100644 --- a/integration_test/support/pages/shadow_dom.html +++ b/integration_test/support/pages/shadow_dom.html @@ -4,7 +4,10 @@ class ShadowTestElement extends HTMLElement { connectedCallback() { this.attachShadow({mode: 'open'}); - this.shadowRoot.innerHTML = '
I am in shadow
'; + this.shadowRoot.innerHTML = ` +
I am in shadow
+ + `; } } window.customElements.define('shadow-test', ShadowTestElement); diff --git a/lib/wallaby/browser.ex b/lib/wallaby/browser.ex index 17417a90..341a052a 100644 --- a/lib/wallaby/browser.ex +++ b/lib/wallaby/browser.ex @@ -1013,7 +1013,6 @@ defmodule Wallaby.Browser do end def shadow_root(%{driver: driver} = element) do - IO.inspect(driver) driver.shadow_root(element) end From ca0d43102954cf3b4660efceef94ea4689908659 Mon Sep 17 00:00:00 2001 From: Chris Nelson Date: Wed, 15 Mar 2023 16:41:15 -0400 Subject: [PATCH 04/10] add docs fix oops --- lib/wallaby/webdriver_client.ex | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/wallaby/webdriver_client.ex b/lib/wallaby/webdriver_client.ex index 3bddc883..6365c5b1 100644 --- a/lib/wallaby/webdriver_client.ex +++ b/lib/wallaby/webdriver_client.ex @@ -50,17 +50,9 @@ defmodule Wallaby.WebdriverClient do end @doc """ - Finds an element on the page for a session. If an element is provided then - the query will be scoped to within that element. + Finds the shadow root for a given element. """ - @spec find_elements(Session.t() | Element.t(), Query.compiled()) :: {:ok, [Element.t()]} - def find_elements(parent, locator) do - with {:ok, resp} <- request(:post, parent.url <> "/elements", to_params(locator)), - {:ok, elements} <- Map.fetch(resp, "value"), - elements <- Enum.map(elements || [], &cast_as_element(parent, &1)), - do: {:ok, elements} - end - + @spec shadow_root(Element.t()) :: Element.t() def shadow_root(element) do with {:ok, resp} <- request(:get, element.url <> "/shadow"), {:ok, shadow_root} <- Map.fetch(resp, "value") do From 80f5959080b7dfd0f248124c7af9a2ed02402cb5 Mon Sep 17 00:00:00 2001 From: Chris Nelson Date: Wed, 15 Mar 2023 17:32:58 -0400 Subject: [PATCH 05/10] handle non-existant shadow dom --- integration_test/cases/browser/shadow_dom_test.exs | 8 ++++++++ integration_test/support/pages/shadow_dom.html | 2 +- lib/wallaby/browser.ex | 5 ++++- lib/wallaby/driver.ex | 3 +-- lib/wallaby/httpclient.ex | 3 +++ lib/wallaby/webdriver_client.ex | 7 ++++--- test/wallaby/http_client_test.exs | 14 ++++++++++++++ 7 files changed, 35 insertions(+), 7 deletions(-) diff --git a/integration_test/cases/browser/shadow_dom_test.exs b/integration_test/cases/browser/shadow_dom_test.exs index 74b26c3d..c1676b6c 100644 --- a/integration_test/cases/browser/shadow_dom_test.exs +++ b/integration_test/cases/browser/shadow_dom_test.exs @@ -37,4 +37,12 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do |> click(Query.css("button")) end + test "attempting to access a shadow root where there aint one", %{session: session} do + shadow_root = + session + |> find(Query.css("#outside-shadow")) + |> shadow_root() + refute shadow_root + end + end diff --git a/integration_test/support/pages/shadow_dom.html b/integration_test/support/pages/shadow_dom.html index f01fae0b..e505fc24 100644 --- a/integration_test/support/pages/shadow_dom.html +++ b/integration_test/support/pages/shadow_dom.html @@ -15,7 +15,7 @@ -
I am out of shadow
+
I am out of shadow
\ No newline at end of file diff --git a/lib/wallaby/browser.ex b/lib/wallaby/browser.ex index 341a052a..385fc923 100644 --- a/lib/wallaby/browser.ex +++ b/lib/wallaby/browser.ex @@ -1013,7 +1013,10 @@ defmodule Wallaby.Browser do end def shadow_root(%{driver: driver} = element) do - driver.shadow_root(element) + case driver.shadow_root(element) do + {:ok, element} -> element + {:error, _error} -> nil + end end @doc """ diff --git a/lib/wallaby/driver.ex b/lib/wallaby/driver.ex index 2e50e1f9..24271eb4 100644 --- a/lib/wallaby/driver.ex +++ b/lib/wallaby/driver.ex @@ -183,8 +183,7 @@ defmodule Wallaby.Driver do @doc """ Invoked to find shadow root of given element """ - @callback shadow_root(Element.t()) :: - {:ok, Element.t()} | {:error, reason} + @callback shadow_root(Element.t()) :: {:ok, Element.t()} | {:error, reason} @doc """ Invoked to execute JavaScript in the browser. diff --git a/lib/wallaby/httpclient.ex b/lib/wallaby/httpclient.ex index 64c8597a..e5947715 100644 --- a/lib/wallaby/httpclient.ex +++ b/lib/wallaby/httpclient.ex @@ -114,6 +114,9 @@ defmodule Wallaby.HTTPClient do %{"message" => "stale element reference" <> _} -> {:error, :stale_reference} + %{"message" => "no such shadow root" <> _} -> + {:error, :shadow_root_not_found} + %{ "message" => "An element command failed because the referenced element is no longer available" <> _ diff --git a/lib/wallaby/webdriver_client.ex b/lib/wallaby/webdriver_client.ex index 6365c5b1..9be035ba 100644 --- a/lib/wallaby/webdriver_client.ex +++ b/lib/wallaby/webdriver_client.ex @@ -52,11 +52,12 @@ defmodule Wallaby.WebdriverClient do @doc """ Finds the shadow root for a given element. """ - @spec shadow_root(Element.t()) :: Element.t() + @spec shadow_root(Element.t()) :: {:ok, Element.t()} def shadow_root(element) do with {:ok, resp} <- request(:get, element.url <> "/shadow"), - {:ok, shadow_root} <- Map.fetch(resp, "value") do - cast_as_element(element, shadow_root) + {:ok, shadow_root} <- Map.fetch(resp, "value"), + element <- cast_as_element(element, shadow_root) do + {:ok, element} end end diff --git a/test/wallaby/http_client_test.exs b/test/wallaby/http_client_test.exs index eb267a13..f28ae65e 100644 --- a/test/wallaby/http_client_test.exs +++ b/test/wallaby/http_client_test.exs @@ -55,6 +55,20 @@ defmodule Wallaby.HTTPClientTest do assert {:error, :stale_reference} = Client.request(:post, bypass_url(bypass, "/my_url")) end + test "with a non-existant shadow root response", %{bypass: bypass} do + Bypass.expect(bypass, fn conn -> + send_json_resp(conn, 404, %{ + "sessionId" => "abc123", + "status" => 10, + "value" => %{ + "message" => "no such shadow root\n (Session info: headless chrome=111.0.5563.64)\n (Driver info: chromedriver=110.0.5481.77 (65ed616c6e8ee3fe0ad64fe83796c020644d42af-refs/branch-heads/5481@{#839}),platform=Mac OS X 12.0.1 arm64)" + } + }) + end) + + assert {:error, :shadow_root_not_found} = Client.request(:post, bypass_url(bypass, "/my_url")) + end + test "with an obscure status code", %{bypass: bypass} do expected_message = "message from an obscure error" From d356e2f1f827a2b206b71961ad0cd1989440c0d8 Mon Sep 17 00:00:00 2001 From: Chris Nelson Date: Thu, 16 Mar 2023 10:43:34 -0400 Subject: [PATCH 06/10] add integration test so it gets run --- integration_test/tests.exs | 1 + lib/wallaby/chrome.ex | 2 +- lib/wallaby/selenium.ex | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/integration_test/tests.exs b/integration_test/tests.exs index fab6c6dc..df2eca96 100644 --- a/integration_test/tests.exs +++ b/integration_test/tests.exs @@ -31,5 +31,6 @@ Code.require_file("cases/browser/title_test.exs", __DIR__) Code.require_file("cases/browser/visible_test.exs", __DIR__) Code.require_file("cases/browser/window_size_test.exs", __DIR__) Code.require_file("cases/element/send_keys_test.exs", __DIR__) +Code.require_file("cases/element/shadow_dom_test.exs", __DIR__) Code.require_file("cases/query_test.exs", __DIR__) Code.require_file("cases/wallaby_test.exs", __DIR__) diff --git a/lib/wallaby/chrome.ex b/lib/wallaby/chrome.ex index 306fa1a0..54a9fc5d 100644 --- a/lib/wallaby/chrome.ex +++ b/lib/wallaby/chrome.ex @@ -410,7 +410,7 @@ defmodule Wallaby.Chrome do defdelegate accept_prompt(session, input, fun), to: WebdriverClient @doc false defdelegate dismiss_prompt(session, fun), to: WebdriverClient - + @doc false defdelegate shadow_root(element), to: WebdriverClient @doc false diff --git a/lib/wallaby/selenium.ex b/lib/wallaby/selenium.ex index 2469c880..e2a984ef 100644 --- a/lib/wallaby/selenium.ex +++ b/lib/wallaby/selenium.ex @@ -190,6 +190,9 @@ defmodule Wallaby.Selenium do @doc false defdelegate dismiss_prompt(session, fun), to: WebdriverClient + @doc false + defdelegate shadow_root(element), to: WebdriverClient + @doc false defdelegate take_screenshot(session_or_element), to: WebdriverClient From f749e16176a874c4de8073c075de660680611fba Mon Sep 17 00:00:00 2001 From: Chris Nelson Date: Thu, 16 Mar 2023 10:58:58 -0400 Subject: [PATCH 07/10] oops --- integration_test/cases/browser/shadow_dom_test.exs | 5 +++-- integration_test/tests.exs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/integration_test/cases/browser/shadow_dom_test.exs b/integration_test/cases/browser/shadow_dom_test.exs index c1676b6c..4c54aed0 100644 --- a/integration_test/cases/browser/shadow_dom_test.exs +++ b/integration_test/cases/browser/shadow_dom_test.exs @@ -2,8 +2,6 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do use Wallaby.Integration.SessionCase, async: true - import Wallaby.Query, only: [css: 1] - setup %{session: session} do page = session @@ -27,6 +25,8 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do |> find(Query.css("shadow-test")) |> shadow_root() |> find(Query.css("#in-shadow")) + + assert element end test "can click stuff within da shadow dom", %{session: session} do @@ -35,6 +35,7 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do |> find(Query.css("shadow-test")) |> shadow_root() |> click(Query.css("button")) + assert element end test "attempting to access a shadow root where there aint one", %{session: session} do diff --git a/integration_test/tests.exs b/integration_test/tests.exs index df2eca96..0883a7e1 100644 --- a/integration_test/tests.exs +++ b/integration_test/tests.exs @@ -25,12 +25,12 @@ Code.require_file("cases/browser/screenshot_test.exs", __DIR__) Code.require_file("cases/browser/select_test.exs", __DIR__) Code.require_file("cases/browser/set_value_test.exs", __DIR__) Code.require_file("cases/browser/send_keys_test.exs", __DIR__) +Code.require_file("cases/browser/shadow_dom_test.exs", __DIR__) Code.require_file("cases/browser/stale_nodes_test.exs", __DIR__) Code.require_file("cases/browser/text_test.exs", __DIR__) Code.require_file("cases/browser/title_test.exs", __DIR__) Code.require_file("cases/browser/visible_test.exs", __DIR__) Code.require_file("cases/browser/window_size_test.exs", __DIR__) Code.require_file("cases/element/send_keys_test.exs", __DIR__) -Code.require_file("cases/element/shadow_dom_test.exs", __DIR__) Code.require_file("cases/query_test.exs", __DIR__) Code.require_file("cases/wallaby_test.exs", __DIR__) From 2bbd851646715320b7ffe4dfad865b3cd2935dc2 Mon Sep 17 00:00:00 2001 From: Chris Nelson Date: Thu, 16 Mar 2023 11:10:17 -0400 Subject: [PATCH 08/10] format --- integration_test/cases/browser/shadow_dom_test.exs | 4 ++-- test/wallaby/http_client_test.exs | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/integration_test/cases/browser/shadow_dom_test.exs b/integration_test/cases/browser/shadow_dom_test.exs index 4c54aed0..ea716333 100644 --- a/integration_test/cases/browser/shadow_dom_test.exs +++ b/integration_test/cases/browser/shadow_dom_test.exs @@ -1,5 +1,4 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do - use Wallaby.Integration.SessionCase, async: true setup %{session: session} do @@ -35,6 +34,7 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do |> find(Query.css("shadow-test")) |> shadow_root() |> click(Query.css("button")) + assert element end @@ -43,7 +43,7 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do session |> find(Query.css("#outside-shadow")) |> shadow_root() + refute shadow_root end - end diff --git a/test/wallaby/http_client_test.exs b/test/wallaby/http_client_test.exs index f28ae65e..b201a97f 100644 --- a/test/wallaby/http_client_test.exs +++ b/test/wallaby/http_client_test.exs @@ -61,12 +61,14 @@ defmodule Wallaby.HTTPClientTest do "sessionId" => "abc123", "status" => 10, "value" => %{ - "message" => "no such shadow root\n (Session info: headless chrome=111.0.5563.64)\n (Driver info: chromedriver=110.0.5481.77 (65ed616c6e8ee3fe0ad64fe83796c020644d42af-refs/branch-heads/5481@{#839}),platform=Mac OS X 12.0.1 arm64)" + "message" => + "no such shadow root\n (Session info: headless chrome=111.0.5563.64)\n (Driver info: chromedriver=110.0.5481.77 (65ed616c6e8ee3fe0ad64fe83796c020644d42af-refs/branch-heads/5481@{#839}),platform=Mac OS X 12.0.1 arm64)" } }) end) - assert {:error, :shadow_root_not_found} = Client.request(:post, bypass_url(bypass, "/my_url")) + assert {:error, :shadow_root_not_found} = + Client.request(:post, bypass_url(bypass, "/my_url")) end test "with an obscure status code", %{bypass: bypass} do From 2804fe9440e174f06eb7ceb60eb573d081f490b2 Mon Sep 17 00:00:00 2001 From: Chris Nelson Date: Thu, 16 Mar 2023 11:47:06 -0400 Subject: [PATCH 09/10] how bout some documentation --- lib/wallaby/browser.ex | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/wallaby/browser.ex b/lib/wallaby/browser.ex index 385fc923..4866286f 100644 --- a/lib/wallaby/browser.ex +++ b/lib/wallaby/browser.ex @@ -1012,6 +1012,19 @@ defmodule Wallaby.Browser do ) end + @doc """ + Finds the shadow DOM for the specified element and returns an element corresponding + to this shadow DOM. Subsequent queries made within element retured by calling `shadow_root` + will return elements within the shadow DOM, e. g. + + ``` + element = + session + |> find(Query.css("shadow-test")) + |> shadow_root() + |> find(Query.css("#in-shadow")) + ``` + """ def shadow_root(%{driver: driver} = element) do case driver.shadow_root(element) do {:ok, element} -> element From 158f6aa8c98b16c286a909bf86ab7def3f9ff880 Mon Sep 17 00:00:00 2001 From: Andrew Moore Date: Wed, 16 Aug 2023 03:19:47 -0600 Subject: [PATCH 10/10] address review comments --- .../cases/browser/shadow_dom_test.exs | 17 +++++++++------- .../support/pages/shadow_dom.html | 7 +++++-- lib/wallaby/browser.ex | 15 +++++++------- lib/wallaby/webdriver_client.ex | 7 +++---- test/wallaby/http_client_test.exs | 20 ++++++++++++++++++- 5 files changed, 44 insertions(+), 22 deletions(-) diff --git a/integration_test/cases/browser/shadow_dom_test.exs b/integration_test/cases/browser/shadow_dom_test.exs index ea716333..f8faecd0 100644 --- a/integration_test/cases/browser/shadow_dom_test.exs +++ b/integration_test/cases/browser/shadow_dom_test.exs @@ -1,6 +1,8 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do use Wallaby.Integration.SessionCase, async: true + alias Wallaby.Element + setup %{session: session} do page = session @@ -15,30 +17,31 @@ defmodule Wallaby.Integration.Browser.ShadowDomTest do |> find(Query.css("shadow-test")) |> shadow_root() - assert shadow_root + assert %Element{} = shadow_root end - test "can find stuff within da shadow dom", %{session: session} do + test "can find elements within a shadow dom", %{session: session} do element = session |> find(Query.css("shadow-test")) |> shadow_root() |> find(Query.css("#in-shadow")) - assert element + assert Element.text(%Element{} = element) == "I am in shadow" end - test "can click stuff within da shadow dom", %{session: session} do + test "can click elements within a shadow dom", %{session: session} do element = session |> find(Query.css("shadow-test")) |> shadow_root() - |> click(Query.css("button")) + |> click(Query.css("#option1")) + |> click(Query.css("#option2")) - assert element + assert selected?(element, Query.css("#option2")) end - test "attempting to access a shadow root where there aint one", %{session: session} do + test "does not return a shadow root when one does not exist", %{session: session} do shadow_root = session |> find(Query.css("#outside-shadow")) diff --git a/integration_test/support/pages/shadow_dom.html b/integration_test/support/pages/shadow_dom.html index e505fc24..b310062b 100644 --- a/integration_test/support/pages/shadow_dom.html +++ b/integration_test/support/pages/shadow_dom.html @@ -6,7 +6,10 @@ this.attachShadow({mode: 'open'}); this.shadowRoot.innerHTML = `
I am in shadow
- +
+ + +
`; } } @@ -18,4 +21,4 @@
I am out of shadow
- \ No newline at end of file + diff --git a/lib/wallaby/browser.ex b/lib/wallaby/browser.ex index 4866286f..8f3bdb2e 100644 --- a/lib/wallaby/browser.ex +++ b/lib/wallaby/browser.ex @@ -1013,16 +1013,15 @@ defmodule Wallaby.Browser do end @doc """ - Finds the shadow DOM for the specified element and returns an element corresponding - to this shadow DOM. Subsequent queries made within element retured by calling `shadow_root` - will return elements within the shadow DOM, e. g. + Finds and returns the shadow root for the given element. + + Queries executed on the returned shadow root will be scoped to the root's shadow DOM. ``` - element = - session - |> find(Query.css("shadow-test")) - |> shadow_root() - |> find(Query.css("#in-shadow")) + session + |> find(Query.css("shadow-test")) + |> shadow_root() + |> find(Query.css("#in-shadow")) ``` """ def shadow_root(%{driver: driver} = element) do diff --git a/lib/wallaby/webdriver_client.ex b/lib/wallaby/webdriver_client.ex index 9be035ba..b101edf4 100644 --- a/lib/wallaby/webdriver_client.ex +++ b/lib/wallaby/webdriver_client.ex @@ -50,14 +50,13 @@ defmodule Wallaby.WebdriverClient do end @doc """ - Finds the shadow root for a given element. + Finds the shadow root for the given element. """ @spec shadow_root(Element.t()) :: {:ok, Element.t()} def shadow_root(element) do with {:ok, resp} <- request(:get, element.url <> "/shadow"), - {:ok, shadow_root} <- Map.fetch(resp, "value"), - element <- cast_as_element(element, shadow_root) do - {:ok, element} + {:ok, shadow_root} <- Map.fetch(resp, "value") do + {:ok, cast_as_element(element, shadow_root)} end end diff --git a/test/wallaby/http_client_test.exs b/test/wallaby/http_client_test.exs index b201a97f..2015e26b 100644 --- a/test/wallaby/http_client_test.exs +++ b/test/wallaby/http_client_test.exs @@ -55,7 +55,7 @@ defmodule Wallaby.HTTPClientTest do assert {:error, :stale_reference} = Client.request(:post, bypass_url(bypass, "/my_url")) end - test "with a non-existant shadow root response", %{bypass: bypass} do + test "with a non-existent shadow root", %{bypass: bypass} do Bypass.expect(bypass, fn conn -> send_json_resp(conn, 404, %{ "sessionId" => "abc123", @@ -71,6 +71,24 @@ defmodule Wallaby.HTTPClientTest do Client.request(:post, bypass_url(bypass, "/my_url")) end + test "with an existing shadow root", %{bypass: bypass} do + Bypass.expect(bypass, fn conn -> + send_json_resp(conn, 200, %{ + "sessionId" => "abc123", + "status" => 0, + "value" => nil + }) + end) + + {:ok, response} = Client.request(:post, bypass_url(bypass, "/my_url")) + + assert response == %{ + "sessionId" => "abc123", + "status" => 0, + "value" => nil + } + end + test "with an obscure status code", %{bypass: bypass} do expected_message = "message from an obscure error"