diff --git a/.gitignore b/.gitignore
index 6bdf718f..4dc23bab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,5 +25,9 @@ phoenix_test-*.tar
# Temporary files, for example, from tests.
/tmp/
+# Local configuration
+.envrc
+
# Ignore assets that are produced by build tools.
-/priv/static/assets/
+/priv/static/assets/*
+!/priv/static/assets/app.css
diff --git a/config/test.exs b/config/test.exs
index 68cbde9f..bcc06013 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -20,3 +20,11 @@ config :esbuild,
cd: Path.expand("../test/assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
+
+config :wallaby,
+ otp_app: :phoenix_test,
+ js_logger: nil,
+ chromedriver: [
+ headless: System.get_env("WALLABY_HEADLESS", "t") in ["t", "true"],
+ binary: System.get_env("CHROME_EXECUTABLE", "")
+ ]
diff --git a/lib/phoenix_test.ex b/lib/phoenix_test.ex
index 518d38ec..68ee0bcb 100644
--- a/lib/phoenix_test.ex
+++ b/lib/phoenix_test.ex
@@ -213,6 +213,12 @@ defmodule PhoenixTest do
LiveView or a static view. You don't need to worry about which type of page
you're visiting.
"""
+ if Code.ensure_loaded?(Wallaby) do
+ def visit(%Plug.Conn{assigns: %{phoenix_test_js: true}} = conn, path) do
+ PhoenixTest.Wallaby.build(conn, path)
+ end
+ end
+
def visit(conn, path) do
conn
|> recycle(all_headers(conn))
@@ -237,6 +243,32 @@ defmodule PhoenixTest do
Enum.map(conn.req_headers, &elem(&1, 0))
end
+ @doc """
+ Helper to run tests with the Javascript (Wallaby) driver via `@tag :js`.
+
+ ```elixir
+ setup %{conn: conn} = context do
+ conn = if context[:js], do: with_js_driver(conn), else: conn
+ %{conn: conn}
+ end
+
+ @tag :js
+ test "with wallaby", %{conn: conn} do
+ visit(conn, "/path")
+ end
+
+ test "without wallaby", %{conn: conn} do
+ visit(conn, "/path")
+ end
+ ```
+
+ You can also use `@describetag :js` and `@moduletag :js`.
+ Refer to the [ExUnit docs](https://hexdocs.pm/ex_unit/1.16.3/ExUnit.Case.html#module-tags) for more details.
+ """
+ def with_js_driver(%Plug.Conn{} = conn) do
+ Plug.Conn.assign(conn, :phoenix_test_js, true)
+ end
+
@doc """
Clicks a link with given text and performs the action.
diff --git a/lib/phoenix_test/field.ex b/lib/phoenix_test/field.ex
index 6be3ebbf..54061cf9 100644
--- a/lib/phoenix_test/field.ex
+++ b/lib/phoenix_test/field.ex
@@ -7,8 +7,8 @@ defmodule PhoenixTest.Field do
alias PhoenixTest.Query
alias PhoenixTest.Utils
- @enforce_keys ~w[source_raw parsed label id name value selector]a
- defstruct ~w[source_raw parsed label id name value selector]a
+ @enforce_keys ~w[source_raw parsed label id name value selector raw]a
+ defstruct ~w[source_raw parsed label id name value selector raw]a
def find_input!(html, input_selectors, label, opts) do
field = Query.find_by_label!(html, input_selectors, label, opts)
@@ -23,13 +23,13 @@ defmodule PhoenixTest.Field do
id: id,
name: name,
value: value,
- selector: Element.build_selector(field)
+ selector: Element.build_selector(field),
+ raw: field
}
end
def find_checkbox!(html, input_selector, label, opts) do
field = Query.find_by_label!(html, input_selector, label, opts)
-
id = Html.attribute(field, "id")
name = Html.attribute(field, "name")
value = Html.attribute(field, "value") || "on"
@@ -41,7 +41,8 @@ defmodule PhoenixTest.Field do
id: id,
name: name,
value: value,
- selector: Element.build_selector(field)
+ selector: Element.build_selector(field),
+ raw: field
}
end
@@ -60,7 +61,8 @@ defmodule PhoenixTest.Field do
id: id,
name: name,
value: value,
- selector: Element.build_selector(field)
+ selector: Element.build_selector(field),
+ raw: field
}
end
diff --git a/lib/phoenix_test/link.ex b/lib/phoenix_test/link.ex
index c26e8aef..a87f513c 100644
--- a/lib/phoenix_test/link.ex
+++ b/lib/phoenix_test/link.ex
@@ -1,6 +1,7 @@
defmodule PhoenixTest.Link do
@moduledoc false
+ alias PhoenixTest.Element
alias PhoenixTest.Html
alias PhoenixTest.Query
alias PhoenixTest.Utils
@@ -17,7 +18,7 @@ defmodule PhoenixTest.Link do
raw: link_html,
parsed: link,
id: id,
- selector: selector,
+ selector: Element.build_selector(link),
text: text,
href: href
}
diff --git a/lib/phoenix_test/wallaby.ex b/lib/phoenix_test/wallaby.ex
new file mode 100644
index 00000000..22ab5285
--- /dev/null
+++ b/lib/phoenix_test/wallaby.ex
@@ -0,0 +1,293 @@
+if Code.ensure_loaded?(Wallaby) do
+ defmodule PhoenixTest.Wallaby do
+ @moduledoc false
+
+ import Wallaby.Browser
+
+ alias ExUnit.AssertionError
+ alias PhoenixTest.Button
+ alias PhoenixTest.Field
+ alias PhoenixTest.Html
+ alias PhoenixTest.Link
+ alias PhoenixTest.OpenBrowser
+ alias PhoenixTest.Query
+ alias PhoenixTest.Select
+
+ require Wallaby.Browser
+
+ @endpoint Application.compile_env(:phoenix_test, :endpoint)
+
+ defstruct session: nil, within: :none, last_field_query: :none
+
+ def build(_conn, path) do
+ {:ok, session} = Wallaby.start_session()
+ Wallaby.Browser.visit(session, path)
+ %__MODULE__{session: session}
+ end
+
+ def current_path(%{session: session}) do
+ uri = session |> current_url() |> URI.parse()
+ append_query_string(uri.path, uri.query)
+ end
+
+ def append_query_string(path, nil), do: path
+ def append_query_string(path, query), do: path <> "?" <> query
+
+ def render_page_title(session) do
+ session
+ |> render_html()
+ |> Query.find("title")
+ |> case do
+ {:found, element} -> Html.text(element)
+ _ -> nil
+ end
+ end
+
+ def render_html(%{session: session, within: within}) do
+ html = Wallaby.Browser.page_source(session)
+
+ case within do
+ :none -> html
+ selector -> html |> Query.find!(selector) |> Html.raw()
+ end
+ end
+
+ def click_link(session, selector, text) do
+ query = query(session, &Link.find!(&1, selector, text))
+ # TODO Remove redundant text filter
+ Wallaby.Browser.click(session.session, Wallaby.Query.text(query, text))
+ session
+ end
+
+ def click_button(session, selector, text) do
+ query = query(session, &Button.find!(&1, selector, text))
+
+ belongs_to_form? =
+ session
+ |> render_html()
+ |> Button.find!(selector, text)
+ |> Button.belongs_to_form?()
+
+ # TODO Remove redundant text filter
+ Wallaby.Browser.click(session.session, Wallaby.Query.text(query, text))
+ Map.update!(session, :last_field_query, &if(belongs_to_form?, do: :none, else: &1))
+ end
+
+ def within(session, selector, fun) when is_function(fun, 1) do
+ session
+ |> Map.put(:within, selector)
+ |> fun.()
+ |> Map.put(:within, :none)
+ end
+
+ def fill_in(session, input_selector, label, opts) do
+ {value, opts} = Keyword.pop!(opts, :with)
+ field = Field.find_input!(render_html(session), input_selector, label, opts)
+ query = query(session, &Field.find_input!(&1, input_selector, label, opts))
+
+ case Html.attribute(field.raw, "type") do
+ # Set via JS to avoid locale format issues
+ type when type in ~w(date datetime-local time week) ->
+ js = """
+ el = document.querySelector('#{field.selector}');
+ el.value = '#{value}';
+ """
+
+ session.session
+ |> Wallaby.Browser.execute_script(js)
+ |> Wallaby.Browser.click(query)
+
+ _other ->
+ Wallaby.Browser.clear(session.session, query)
+ Wallaby.Browser.fill_in(session.session, query, with: value || "")
+ end
+
+ session
+ |> Map.put(:last_field_query, query)
+ |> trigger_phx_change_validations(query)
+ end
+
+ def select(session, input_selector, options, opts) do
+ {label, opts} = Keyword.pop!(opts, :from)
+ query = query(session, &Select.find_select_option!(&1, input_selector, label, options, opts))
+
+ for option <- List.wrap(options) do
+ option_query =
+ if opts[:exact_option] do
+ Wallaby.Query.option(option)
+ else
+ Wallaby.Query.css("option", text: option)
+ end
+
+ session.session
+ |> Wallaby.Browser.find(query)
+ |> Wallaby.Browser.set_value(option_query, :selected)
+ end
+
+ Map.put(session, :last_field_query, query)
+ end
+
+ def check(session, input_selector, label, opts) do
+ query = query(session, &Field.find_checkbox!(&1, input_selector, label, opts))
+ Wallaby.Browser.set_value(session.session, query, :selected)
+
+ Map.put(session, :last_field_query, query)
+ end
+
+ def uncheck(session, input_selector, label, opts) do
+ query = query(session, &Field.find_checkbox!(&1, input_selector, label, opts))
+ Wallaby.Browser.set_value(session.session, query, :unselected)
+
+ Map.put(session, :last_field_query, query)
+ end
+
+ def choose(session, input_selector, label, opts) do
+ query = query(session, &Field.find_input!(&1, input_selector, label, opts))
+ Wallaby.Browser.click(session.session, query)
+
+ Map.put(session, :last_field_query, query)
+ end
+
+ def upload(session, input_selector, label, path, opts) do
+ # TODO Improve: wait for live upload input to be ready
+ Process.sleep(1000)
+
+ query = query(session, &Field.find_input!(&1, input_selector, label, opts))
+ Wallaby.Browser.attach_file(session.session, query, [{:path, Path.expand(path)}])
+
+ Map.put(session, :last_field_query, query)
+ end
+
+ def submit(session) do
+ case session.last_field_query do
+ :none -> raise no_active_form_error()
+ # TODO Fix for file input ('enter' key doesn't trigger form submit)
+ query -> Wallaby.Browser.send_keys(session.session, query, [:enter])
+ end
+
+ Map.put(session, :last_field_query, :none)
+ end
+
+ def open_browser(session, open_fun \\ &OpenBrowser.open_with_system_cmd/1) do
+ path = Path.join([System.tmp_dir!(), "phx-test#{System.unique_integer([:monotonic])}.html"])
+
+ html =
+ session.session
+ |> Wallaby.Browser.page_source()
+ |> Floki.parse_document!()
+ |> Floki.traverse_and_update(&OpenBrowser.prefix_static_paths(&1, @endpoint))
+ |> Floki.raw_html()
+
+ File.write!(path, html)
+
+ open_fun.(path)
+
+ session
+ end
+
+ def unwrap(session, fun) when is_function(fun, 1) do
+ fun.(session.session)
+ session
+ end
+
+ defp query(session, find_fun) do
+ # Use PhoenixTest.Field queries for label exact-match semantics
+ html = render_html(session)
+ field = find_fun.(html)
+
+ within =
+ case session.within do
+ :none -> ""
+ selector -> selector
+ end
+
+ selector = "#{within} #{field.selector}"
+ Wallaby.Query.css(selector)
+ end
+
+ defp trigger_phx_change_validations(session, query) do
+ if has?(session.session, query) do
+ Wallaby.Browser.send_keys(session.session, query, [:tab])
+ end
+
+ session
+ end
+
+ defp no_active_form_error do
+ %ArgumentError{
+ message: "There's no active form. Fill in a form with `fill_in`, `select`, etc."
+ }
+ end
+ end
+
+ defimpl PhoenixTest.Driver, for: PhoenixTest.Wallaby do
+ alias ExUnit.AssertionError
+ alias PhoenixTest.Assertions
+ alias PhoenixTest.Wallaby
+
+ def render_page_title(session), do: map_errors(fn -> Wallaby.render_page_title(session) end)
+ def render_html(session), do: map_errors(fn -> Wallaby.render_html(session) end)
+ def click_link(session, selector, text), do: map_errors(fn -> Wallaby.click_link(session, selector, text) end)
+ def click_button(session, selector, text), do: map_errors(fn -> Wallaby.click_button(session, selector, text) end)
+ def within(session, selector, fun), do: map_errors(fn -> Wallaby.within(session, selector, fun) end)
+
+ def fill_in(session, input_selector, label, opts),
+ do: map_errors(fn -> Wallaby.fill_in(session, input_selector, label, opts) end)
+
+ def select(session, input_selector, option, opts),
+ do: map_errors(fn -> Wallaby.select(session, input_selector, option, opts) end)
+
+ def check(session, input_selector, label, opts),
+ do: map_errors(fn -> Wallaby.check(session, input_selector, label, opts) end)
+
+ def uncheck(session, input_selector, label, opts),
+ do: map_errors(fn -> Wallaby.uncheck(session, input_selector, label, opts) end)
+
+ def choose(session, input_selector, label, opts),
+ do: map_errors(fn -> Wallaby.choose(session, input_selector, label, opts) end)
+
+ def upload(session, input_selector, label, path, opts),
+ do: map_errors(fn -> Wallaby.upload(session, input_selector, label, path, opts) end)
+
+ def submit(session), do: map_errors(fn -> Wallaby.submit(session) end)
+ def open_browser(session), do: map_errors(fn -> Wallaby.open_browser(session) end)
+ def open_browser(session, open_fun), do: map_errors(fn -> Wallaby.open_browser(session, open_fun) end)
+ def unwrap(session, fun), do: map_errors(fn -> Wallaby.unwrap(session, fun) end)
+ def current_path(session), do: map_errors(fn -> Wallaby.current_path(session) end)
+
+ def assert_has(session, selector), do: retry(fn -> Assertions.assert_has(session, selector) end)
+ def assert_has(session, selector, opts), do: retry(fn -> Assertions.assert_has(session, selector, opts) end)
+ def refute_has(session, selector), do: retry(fn -> Assertions.refute_has(session, selector) end)
+ def refute_has(session, selector, opts), do: retry(fn -> Assertions.refute_has(session, selector, opts) end)
+ def assert_path(session, path), do: retry(fn -> Assertions.assert_path(session, path) end)
+ def assert_path(session, path, opts), do: retry(fn -> Assertions.assert_path(session, path, opts) end)
+ def refute_path(session, path), do: retry(fn -> Assertions.refute_path(session, path) end)
+ def refute_path(session, path, opts), do: retry(fn -> Assertions.refute_path(session, path, opts) end)
+
+ defp map_errors(fun) do
+ fun.()
+ rescue
+ e ->
+ raise ArgumentError, Exception.message(e)
+ end
+
+ defp retry(fun, timeout_ms \\ 300, interval_ms \\ 10) do
+ now = DateTime.to_unix(DateTime.utc_now(), :millisecond)
+ timeout_at = DateTime.utc_now() |> DateTime.add(timeout_ms, :millisecond) |> DateTime.to_unix(:millisecond)
+ retry(fun, now, timeout_at, interval_ms)
+ end
+
+ defp retry(fun, now, timeout_at, _interval_ms) when now >= timeout_at do
+ fun.()
+ end
+
+ defp retry(fun, _now, timeout_at, interval_ms) do
+ fun.()
+ rescue
+ AssertionError ->
+ Process.sleep(interval_ms)
+ now = DateTime.to_unix(DateTime.utc_now(), :millisecond)
+ retry(fun, now, timeout_at, interval_ms)
+ end
+ end
+end
diff --git a/mix.exs b/mix.exs
index 79816100..aa13d2fe 100644
--- a/mix.exs
+++ b/mix.exs
@@ -51,7 +51,8 @@ defmodule PhoenixTest.MixProject do
{:phoenix, "~> 1.7.10"},
{:phoenix_live_view, "~> 0.20.1"},
{:plug_cowboy, "~> 2.7", only: :test, runtime: false},
- {:styler, "~> 0.11", only: [:dev, :test], runtime: false}
+ {:styler, "~> 0.11", only: [:dev, :test], runtime: false},
+ {:wallaby, "~> 0.30.6", runtime: false, only: :test, optional: true}
]
end
@@ -79,7 +80,8 @@ defmodule PhoenixTest.MixProject do
[
setup: ["deps.get", "assets.setup", "assets.build"],
"assets.setup": ["esbuild.install --if-missing"],
- "assets.build": ["esbuild default"]
+ "assets.build": ["esbuild default"],
+ test: ["assets.build", "test"]
]
end
end
diff --git a/mix.lock b/mix.lock
index 0685833d..0e8a537d 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,5 +1,6 @@
%{
"castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"},
+ "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
"cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
@@ -7,6 +8,9 @@
"esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
"ex_doc": {:hex, :ex_doc, "0.32.1", "21e40f939515373bcdc9cffe65f3b3543f05015ac6c3d01d991874129d173420", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "5142c9db521f106d61ff33250f779807ed2a88620e472ac95dc7d59c380113da"},
"floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"},
+ "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
+ "httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"},
+ "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"},
"makeup_diff": {:hex, :makeup_diff, "0.1.0", "5be352b6aa6f07fa6a236e3efd7ba689a03f28fb5d35b7a0fa0a1e4a64f6d8bb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "186bad5bb433a8afeb16b01423950e440072284a4103034ca899180343b9b4ac"},
@@ -14,8 +18,11 @@
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.5", "e0ff5a7c708dda34311f7522a8758e23bfcd7d8d8068dc312b5eb41c6fd76eba", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "94d2e986428585a21516d7d7149781480013c56e30c6a233534bedf38867a59a"},
"makeup_html": {:hex, :makeup_html, "0.1.1", "c3d4abd39d5f7e925faca72ada6e9cc5c6f5fa7cd5bc0158315832656cf14d7f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "44f2a61bc5243645dd7fafeaa6cc28793cd22f3c76b861e066168f9a5b2c26a4"},
+ "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
+ "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
+ "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"phoenix": {:hex, :phoenix, "1.7.10", "02189140a61b2ce85bb633a9b6fd02dff705a5f1596869547aeb2b2b95edd729", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "cf784932e010fd736d656d7fead6a584a4498efefe5b8227e9f383bf15bb79d0"},
"phoenix_html": {:hex, :phoenix_html, "4.0.0", "4857ec2edaccd0934a923c2b0ba526c44a173c86b847e8db725172e9e51d11d6", [:mix], [], "hexpm", "cee794a052f243291d92fa3ccabcb4c29bb8d236f655fb03bcbdc3a8214b8d13"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.20.3", "8b6406bc0a451f295407d7acff7f234a6314be5bbe0b3f90ed82b07f50049878", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a8e4385e05618b424779f894ed2df97d3c7518b7285fcd11979077ae6226466b"},
@@ -25,8 +32,13 @@
"plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"},
"plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
+ "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"styler": {:hex, :styler, "0.11.9", "2595393b94e660cd6e8b582876337cc50ff047d184ccbed42fdad2bfd5d78af5", [:mix], [], "hexpm", "8b7806ba1fdc94d0a75127c56875f91db89b75117fcc67572661010c13e1f259"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
+ "tesla": {:hex, :tesla, "1.9.0", "8c22db6a826e56a087eeb8cdef56889731287f53feeb3f361dec5d4c8efb6f14", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7c240c67e855f7e63e795bf16d6b3f5115a81d1f44b7fe4eadbf656bae0fef8a"},
+ "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
+ "wallaby": {:hex, :wallaby, "0.30.6", "7dc4c1213f3b52c4152581d126632bc7e06892336d3a0f582853efeeabd45a71", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.12 or ~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]}, {:web_driver_client, "~> 0.2.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}], "hexpm", "50950c1d968549b54c20e16175c68c7fc0824138e2bb93feb11ef6add8eb23d4"},
+ "web_driver_client": {:hex, :web_driver_client, "0.2.0", "63b76cd9eb3b0716ec5467a0f8bead73d3d9612e63f7560d21357f03ad86e31a", [:mix], [{:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.3", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "83cc6092bc3e74926d1c8455f0ce927d5d1d36707b74d9a65e38c084aab0350f"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"},
}
diff --git a/priv/static/assets/app.css b/priv/static/assets/app.css
new file mode 100644
index 00000000..e69de29b
diff --git a/priv/static/favicon.ico b/priv/static/favicon.ico
new file mode 100644
index 00000000..e69de29b
diff --git a/test/phoenix_test/assertions_test.exs b/test/phoenix_test/assertions_test.exs
index c11d8025..1db57cf7 100644
--- a/test/phoenix_test/assertions_test.exs
+++ b/test/phoenix_test/assertions_test.exs
@@ -8,18 +8,22 @@ defmodule PhoenixTest.AssertionsTest do
alias ExUnit.AssertionError
alias PhoenixTest.Live
- setup do
- %{conn: Phoenix.ConnTest.build_conn()}
+ require PhoenixTest.TestHelpers
+
+ setup context do
+ conn = Phoenix.ConnTest.build_conn()
+ conn = if context[:js], do: with_js_driver(conn), else: conn
+ %{conn: conn}
end
describe "assert_has/2" do
- test "succeeds if single element is found with CSS selector", %{conn: conn} do
+ test_also_with_js "succeeds if single element is found with CSS selector", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has("[data-role='title']")
end
- test "raises an error if the element cannot be found at all", %{conn: conn} do
+ test_also_with_js "raises an error if the element cannot be found at all", %{conn: conn} do
conn = visit(conn, "/page/index")
msg = ~r/Could not find any elements with selector "#nonexistent-id"/
@@ -29,25 +33,25 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "succeeds if element searched is title (Static)", %{conn: conn} do
+ test_also_with_js "succeeds if element searched is title (Static)", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has("title")
end
- test "succeeds if element searched is title (Live)", %{conn: conn} do
+ test_also_with_js "succeeds if element searched is title (Live)", %{conn: conn} do
conn
|> visit("/live/index")
|> assert_has("title")
end
- test "succeeds if more than one element matches selector", %{conn: conn} do
+ test_also_with_js "succeeds if more than one element matches selector", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has("li")
end
- test "takes in input helper in assertion", %{conn: conn} do
+ test_also_with_js "takes in input helper in assertion", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has(input(type: "text", label: "User Name"))
@@ -55,7 +59,7 @@ defmodule PhoenixTest.AssertionsTest do
end
describe "assert_has/3" do
- test "succeeds if single element is found with CSS selector and text (Static)", %{conn: conn} do
+ test_also_with_js "succeeds if single element is found with CSS selector and text (Static)", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has("h1", text: "Main page")
@@ -64,7 +68,7 @@ defmodule PhoenixTest.AssertionsTest do
|> assert_has("[data-role='title']", text: "Main page")
end
- test "succeeds if single element is found with CSS selector and text (Live)", %{conn: conn} do
+ test_also_with_js "succeeds if single element is found with CSS selector and text (Live)", %{conn: conn} do
conn
|> visit("/live/index")
|> assert_has("h1", text: "LiveView main page")
@@ -73,7 +77,7 @@ defmodule PhoenixTest.AssertionsTest do
|> assert_has("[data-role='title']", text: "LiveView main page")
end
- test "succeeds if more than one element matches selector but text narrows it down", %{
+ test_also_with_js "succeeds if more than one element matches selector but text narrows it down", %{
conn: conn
} do
conn
@@ -81,25 +85,25 @@ defmodule PhoenixTest.AssertionsTest do
|> assert_has("li", text: "Aragorn")
end
- test "succeeds if more than one element matches selector and text", %{conn: conn} do
+ test_also_with_js "succeeds if more than one element matches selector and text", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has(".multiple_links", text: "Multiple links")
end
- test "succeeds if text difference is only a matter of truncation", %{conn: conn} do
+ test_also_with_js "succeeds if text difference is only a matter of truncation", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has(".has_extra_space", text: "Has extra space")
end
- test "succeeds when a non-200 status code is returned", %{conn: conn} do
+ test_also_with_js "succeeds when a non-200 status code is returned", %{conn: conn} do
conn
|> visit("/page/unauthorized")
|> assert_has("h1", text: "Unauthorized")
end
- test "raises an error if the element cannot be found at all", %{conn: conn} do
+ test_also_with_js "raises an error if the element cannot be found at all", %{conn: conn} do
conn = visit(conn, "/page/index")
msg = ~r/Could not find any elements with selector "#nonexistent-id"/
@@ -109,7 +113,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises error if element cannot be found but selector matches other elements", %{
+ test_also_with_js "raises error if element cannot be found but selector matches other elements", %{
conn: conn
} do
conn = visit(conn, "/page/index")
@@ -130,25 +134,25 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "can be used to assert on page title (Static)", %{conn: conn} do
+ test_also_with_js "can be used to assert on page title (Static)", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has("title", text: "PhoenixTest is the best!")
end
- test "can be used to assert on page title (Live)", %{conn: conn} do
+ test_also_with_js "can be used to assert on page title (Live)", %{conn: conn} do
conn
|> visit("/live/index")
|> assert_has("title", text: "PhoenixTest is the best!")
end
- test "can assert title's exactness", %{conn: conn} do
+ test_also_with_js "can assert title's exactness", %{conn: conn} do
conn
|> visit("/live/index")
|> assert_has("title", text: "PhoenixTest is the best!", exact: true)
end
- test "raises if title does not match expected value (Static)", %{conn: conn} do
+ test_also_with_js "raises if title does not match expected value (Static)", %{conn: conn} do
msg =
ignore_whitespace("""
Expected title to be "Not the title" but got "PhoenixTest is the best!"
@@ -161,7 +165,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises if title does not match expected value (Live)", %{conn: conn} do
+ test_also_with_js "raises if title does not match expected value (Live)", %{conn: conn} do
msg =
ignore_whitespace("""
Expected title to be "Not the title" but got "PhoenixTest is the best!"
@@ -174,8 +178,8 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises if title is contained but is not exactly the same as expected (with exact=true)",
- %{conn: conn} do
+ test_also_with_js "raises if title is contained but is not exactly the same as expected (with exact=true)",
+ %{conn: conn} do
msg =
ignore_whitespace("""
Expected title to be "PhoenixTest" but got "PhoenixTest is the best!"
@@ -188,7 +192,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises error if element cannot be found and selector matches a nested structure", %{
+ test_also_with_js "raises error if element cannot be found and selector matches a nested structure", %{
conn: conn
} do
conn = visit(conn, "/page/index")
@@ -217,7 +221,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "accepts a `count` option", %{conn: conn} do
+ test_also_with_js "accepts a `count` option", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has(".multiple_links", count: 2)
@@ -226,7 +230,7 @@ defmodule PhoenixTest.AssertionsTest do
|> assert_has("h1", text: "Main page", count: 1)
end
- test "raises an error if count is more than expected count", %{conn: conn} do
+ test_also_with_js "raises an error if count is more than expected count", %{conn: conn} do
session = visit(conn, "/page/index")
msg =
@@ -241,7 +245,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises an error if count is less than expected count", %{conn: conn} do
+ test_also_with_js "raises an error if count is less than expected count", %{conn: conn} do
session = visit(conn, "/page/index")
msg =
@@ -256,14 +260,14 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "accepts an `exact` option to match text exactly", %{conn: conn} do
+ test_also_with_js "accepts an `exact` option to match text exactly", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has("h1", text: "Main", exact: false)
|> assert_has("h1", text: "Main page", exact: true)
end
- test "raises if `exact` text doesn't match", %{conn: conn} do
+ test_also_with_js "raises if `exact` text doesn't match", %{conn: conn} do
msg =
ignore_whitespace("""
Could not find any elements with selector "h1" and text "Main".
@@ -282,13 +286,13 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "accepts an `at` option to assert on a specific element", %{conn: conn} do
+ test_also_with_js "accepts an `at` option to assert on a specific element", %{conn: conn} do
conn
|> visit("/page/index")
|> assert_has("#multiple-items li", at: 2, text: "Legolas")
end
- test "raises if it cannot find element at `at` position", %{conn: conn} do
+ test_also_with_js "raises if it cannot find element at `at` position", %{conn: conn} do
msg =
ignore_whitespace("""
Could not find any elements with selector "#multiple-items li" and text "Aragorn" at position 2
@@ -303,28 +307,28 @@ defmodule PhoenixTest.AssertionsTest do
end
describe "refute_has/2" do
- test "succeeds if no element is found with CSS selector (Static)", %{conn: conn} do
+ test_also_with_js "succeeds if no element is found with CSS selector (Static)", %{conn: conn} do
conn
|> visit("/page/index")
|> refute_has("#some-invalid-id")
|> refute_has("[data-role='invalid-role']")
end
- test "succeeds if no element is found with CSS selector (Live)", %{conn: conn} do
+ test_also_with_js "succeeds if no element is found with CSS selector (Live)", %{conn: conn} do
conn
|> visit("/live/index")
|> refute_has("#some-invalid-id")
|> refute_has("[data-role='invalid-role']")
end
- test "can refute presence of title (Static)", %{conn: conn} do
+ test_also_with_js "can refute presence of title (Static)", %{conn: conn} do
conn
|> visit("/page/index_no_layout")
|> refute_has("title")
|> refute_has("#something-else-to-test-pipe")
end
- test "accepts a `count` option", %{conn: conn} do
+ test_also_with_js "accepts a `count` option", %{conn: conn} do
conn
|> visit("/page/index")
|> refute_has("h1", count: 2)
@@ -333,7 +337,7 @@ defmodule PhoenixTest.AssertionsTest do
|> refute_has(".multiple_links", text: "Multiple links", count: 1)
end
- test "raises if element is found", %{conn: conn} do
+ test_also_with_js "raises if element is found", %{conn: conn} do
msg =
ignore_whitespace("""
Expected not to find any elements with selector "h1".
@@ -352,7 +356,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises if title is found", %{conn: conn} do
+ test_also_with_js "raises if title is found", %{conn: conn} do
msg =
ignore_whitespace("""
Expected title not to be present but found: "PhoenixTest is the best!"
@@ -365,7 +369,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises an error if multiple elements are found", %{conn: conn} do
+ test_also_with_js "raises an error if multiple elements are found", %{conn: conn} do
conn = visit(conn, "/page/index")
msg =
@@ -380,7 +384,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises if there is one element and count is 1", %{conn: conn} do
+ test_also_with_js "raises if there is one element and count is 1", %{conn: conn} do
conn = visit(conn, "/page/index")
msg =
@@ -393,7 +397,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises if there are the same number of elements as refuted", %{conn: conn} do
+ test_also_with_js "raises if there are the same number of elements as refuted", %{conn: conn} do
conn = visit(conn, "/page/index")
msg =
@@ -410,27 +414,27 @@ defmodule PhoenixTest.AssertionsTest do
end
describe "refute_has/3" do
- test "can be used to refute on page title (Static)", %{conn: conn} do
+ test_also_with_js "can be used to refute on page title (Static)", %{conn: conn} do
conn
|> visit("/page/index")
|> refute_has("title", text: "Not the title")
|> refute_has("title", text: "Not this title either")
end
- test "can be used to refute on page title (Live)", %{conn: conn} do
+ test_also_with_js "can be used to refute on page title (Live)", %{conn: conn} do
conn
|> visit("/live/index")
|> refute_has("title", text: "Not the title")
|> refute_has("title", text: "Not this title either")
end
- test "can be used to refute page title's exactness", %{conn: conn} do
+ test_also_with_js "can be used to refute page title's exactness", %{conn: conn} do
conn
|> visit("/live/index")
|> refute_has("title", text: "PhoenixTest is the", exact: true)
end
- test "raises if title matches value (Static)", %{conn: conn} do
+ test_also_with_js "raises if title matches value (Static)", %{conn: conn} do
msg =
ignore_whitespace("""
Expected title not to be "PhoenixTest is the best!"
@@ -443,7 +447,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises if title matches value (Live)", %{conn: conn} do
+ test_also_with_js "raises if title matches value (Live)", %{conn: conn} do
msg =
ignore_whitespace("""
Expected title not to be "PhoenixTest is the best!"
@@ -456,7 +460,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "succeeds if no element is found with CSS selector and text (Static)", %{conn: conn} do
+ test_also_with_js "succeeds if no element is found with CSS selector and text (Static)", %{conn: conn} do
conn
|> visit("/page/index")
|> refute_has("h1", text: "Not main page")
@@ -465,7 +469,7 @@ defmodule PhoenixTest.AssertionsTest do
|> refute_has("#title", text: "Not main page")
end
- test "succeeds if no element is found with CSS selector and text (Live)", %{conn: conn} do
+ test_also_with_js "succeeds if no element is found with CSS selector and text (Live)", %{conn: conn} do
conn
|> visit("/live/index")
|> refute_has("h1", text: "Not main page")
@@ -474,7 +478,7 @@ defmodule PhoenixTest.AssertionsTest do
|> refute_has("#title", text: "Not main page")
end
- test "raises an error if one element is found", %{conn: conn} do
+ test_also_with_js "raises an error if one element is found", %{conn: conn} do
conn = visit(conn, "/page/index")
msg =
@@ -493,7 +497,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises an error if multiple elements are found", %{conn: conn} do
+ test_also_with_js "raises an error if multiple elements are found", %{conn: conn} do
conn = visit(conn, "/page/index")
msg =
@@ -516,13 +520,13 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "accepts an `exact` option to match text exactly", %{conn: conn} do
+ test_also_with_js "accepts an `exact` option to match text exactly", %{conn: conn} do
conn
|> visit("/page/index")
|> refute_has("h1", text: "Main", exact: true)
end
- test "raises if `exact` text makes refutation false", %{conn: conn} do
+ test_also_with_js "raises if `exact` text makes refutation false", %{conn: conn} do
msg =
ignore_whitespace("""
Expected not to find any elements with selector "h1" and text "Main".
@@ -541,19 +545,19 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "accepts an `at` option (without text) to refute on a specific element", %{conn: conn} do
+ test_also_with_js "accepts an `at` option (without text) to refute on a specific element", %{conn: conn} do
conn
|> visit("/page/index")
|> refute_has("#single-list-item li", at: 2)
end
- test "accepts an `at` option with text to refute on a specific element", %{conn: conn} do
+ test_also_with_js "accepts an `at` option with text to refute on a specific element", %{conn: conn} do
conn
|> visit("/page/index")
|> refute_has("#multiple-items li", at: 2, text: "Aragorn")
end
- test "raises if it finds element at `at` position", %{conn: conn} do
+ test_also_with_js "raises if it finds element at `at` position", %{conn: conn} do
msg =
ignore_whitespace("""
Expected not to find any elements with selector "#multiple-items li" and text "Legolas" at position 2
@@ -574,25 +578,25 @@ defmodule PhoenixTest.AssertionsTest do
end
describe "assert_path" do
- test "asserts the session's current path" do
+ test_also_with_js "asserts the session's current path" do
session = %Live{current_path: "/page/index"}
assert_path(session, "/page/index")
end
- test "asserts query params are the same" do
+ test_also_with_js "asserts query params are the same" do
session = %Live{current_path: "/page/index?hello=world"}
assert_path(session, "/page/index", query_params: %{"hello" => "world"})
end
- test "order of query params does not matter" do
+ test_also_with_js "order of query params does not matter" do
session = %Live{current_path: "/page/index?hello=world&foo=bar"}
assert_path(session, "/page/index", query_params: %{"foo" => "bar", "hello" => "world"})
end
- test "raises helpful error if path doesn't match" do
+ test_also_with_js "raises helpful error if path doesn't match" do
msg =
ignore_whitespace("""
Expected path to be "/page/not-index" but got "/page/index"
@@ -605,7 +609,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises helpful error if path doesn't have query params" do
+ test_also_with_js "raises helpful error if path doesn't have query params" do
msg =
ignore_whitespace("""
Expected query params to be "details=true&foo=bar" but got nil
@@ -618,7 +622,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises helpful error if query params don't match" do
+ test_also_with_js "raises helpful error if query params don't match" do
msg =
ignore_whitespace("""
Expected query params to be "goodbye=world&hi=bye" but got "hello=world&hi=bye"
@@ -633,19 +637,19 @@ defmodule PhoenixTest.AssertionsTest do
end
describe "refute_path" do
- test "refute the given path is the current path" do
+ test_also_with_js "refute the given path is the current path" do
session = %Live{current_path: "/page/index"}
refute_path(session, "/page/page_2")
end
- test "refutes query params are the same" do
+ test_also_with_js "refutes query params are the same" do
session = %Live{current_path: "/page/index?hello=world"}
refute_path(session, "/page/index", query_params: %{"hello" => "not-world"})
end
- test "raises helpful error if path matches" do
+ test_also_with_js "raises helpful error if path matches" do
msg =
ignore_whitespace("""
Expected path not to be "/page/index"
@@ -658,7 +662,7 @@ defmodule PhoenixTest.AssertionsTest do
end
end
- test "raises helpful error if query params MATCH" do
+ test_also_with_js "raises helpful error if query params MATCH" do
msg =
ignore_whitespace("""
Expected query params not to be "hello=world&hi=bye"
diff --git a/test/phoenix_test/form_test.exs b/test/phoenix_test/form_test.exs
index d1a47e29..e763d0f0 100644
--- a/test/phoenix_test/form_test.exs
+++ b/test/phoenix_test/form_test.exs
@@ -111,7 +111,7 @@ defmodule PhoenixTest.FormTest do
-