Skip to content

Commit

Permalink
add test for phoenixframework#2787
Browse files Browse the repository at this point in the history
  • Loading branch information
SteffenDE committed May 3, 2024
1 parent cdd4eb1 commit ca1db79
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 1 deletion.
4 changes: 3 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ defmodule Phoenix.LiveView.MixProject do
{:makeup_diff, "~> 0.1", only: :docs},
{:html_entities, ">= 0.0.0", only: :test},
{:phoenix_live_reload, "~> 1.4.1", only: :test},
{:plug_cowboy, "~> 2.6", only: :e2e}
{:plug_cowboy, "~> 2.6", only: :e2e},
{:ecto, "~> 3.11", only: :e2e},
{:phoenix_ecto, "~> 4.5", only: :e2e}
]
end

Expand Down
3 changes: 3 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
"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.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
"ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
"esbuild": {:hex, :esbuild, "0.7.1", "fa0947e8c3c3c2f86c9bf7e791a0a385007ccd42b86885e8e893bdb6631f5169", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "66661cdf70b1378ee4dc16573fcee67750b59761b2605a0207c267ab9d19f13c"},
"ex_doc": {:hex, :ex_doc, "0.31.2", "8b06d0a5ac69e1a54df35519c951f1f44a7b7ca9a5bb7a260cd8a174d6322ece", [: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", "317346c14febaba9ca40fd97b5b5919f7751fb85d399cc8e7e8872049f37e0af"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
Expand All @@ -19,6 +21,7 @@
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"phoenix": {:hex, :phoenix, "1.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.5.1", "6fdbc334ea53620e71655664df6f33f670747b3a7a6c4041cdda3e2c32df6257", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ebe43aa580db129e54408e719fb9659b7f9e0d52b965c5be26cdca416ecead28"},
"phoenix_html": {:hex, :phoenix_html, "3.3.0", "bf451c71ebdaac8d2f40d3b703435e819ccfbb9ff243140ca3bd10c155f134cc", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "272c5c1533499f0132309936c619186480bafcc2246588f99a69ce85095556ef"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
Expand Down
1 change: 1 addition & 0 deletions test/e2e/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ defmodule Phoenix.LiveViewTest.E2E.Router do
scope "/issues", Phoenix.LiveViewTest.E2E do
pipe_through(:browser)

live "/2787", Issue2787Live
live "/3026", Issue3026Live
live "/3040", Issue3040Live
live "/3083", Issue3083Live
Expand Down
38 changes: 38 additions & 0 deletions test/e2e/tests/issues/2787.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const { test, expect } = require("../../test-fixtures");
const { syncLV } = require("../../utils");

const selectOptions = (locator) => locator.evaluateAll(list => list.map(option => option.value));

test("select is properly cleared on submit", async ({ page }) => {
await page.goto("/issues/2787");
await syncLV(page);

const select1 = page.locator("#demo_select1");
const select2 = page.locator("#demo_select2");

// at the beginning, both selects are empty
await expect(select1).toHaveValue("");
await expect(await selectOptions(select1.locator("option"))).toEqual(["", "greetings", "goodbyes"]);
await expect(select2).toHaveValue("");
await expect(await selectOptions(select2.locator("option"))).toEqual([""]);

// now we select greetings in the first select
await select1.selectOption("greetings");
await syncLV(page);
// now the second select should have some greeting options
await expect(await selectOptions(select2.locator("option"))).toEqual(["", "hello", "hallo", "hei"]);
await select2.selectOption("hei");
await syncLV(page);

// now we submit the form
await page.locator("button").click();

// now, both selects should be empty again (this was the bug in #2787)
await expect(select1).toHaveValue("");
await expect(select2).toHaveValue("");

// now we select goodbyes in the first select
await select1.selectOption("goodbyes");
await syncLV(page);
await expect(await selectOptions(select2.locator("option"))).toEqual(["", "goodbye", "auf wiedersehen", "ha det bra"]);
});
170 changes: 170 additions & 0 deletions test/support/e2e/issues/issue_2787.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
defmodule Phoenix.LiveViewTest.E2E.Issue2787Live do
use Phoenix.LiveView

# https://github.com/phoenixframework/phoenix_live_view/issues/2787

@greetings ["hello", "hallo", "hei"]
@goodbyes ["goodbye", "auf wiedersehen", "ha det bra"]

@impl Phoenix.LiveView
def mount(_params, _session, socket) do
{:ok,
assign(socket,
form: to_form(changeset(%{}), as: :demo),
select1_opts: ["greetings", "goodbyes"],
select2_opts: []
)}
end

@types %{
select1: :string,
select2: :string,
dummy: :string
}

def changeset(params) do
Ecto.Changeset.cast({%{}, @types}, params, [:select1, :select2, :dummy])

Check warning on line 26 in test/support/e2e/issues/issue_2787.ex

View workflow job for this annotation

GitHub Actions / mix test (OTP 24.3 | Elixir 1.13.4)

Ecto.Changeset.cast/3 is undefined (module Ecto.Changeset is not available or is yet to be defined)

Check warning on line 26 in test/support/e2e/issues/issue_2787.ex

View workflow job for this annotation

GitHub Actions / mix test (OTP 25.3 | Elixir 1.15.4)

Ecto.Changeset.cast/3 is undefined (module Ecto.Changeset is not available or is yet to be defined)

Check warning on line 26 in test/support/e2e/issues/issue_2787.ex

View workflow job for this annotation

GitHub Actions / mix test (OTP 26 | Elixir 1.15.5)

Ecto.Changeset.cast/3 is undefined (module Ecto.Changeset is not available or is yet to be defined)
end

@impl Phoenix.LiveView
def handle_event("updated", %{"demo" => demo_params}, socket) do
select2_opts =
case Map.get(demo_params, "select1") do
"greetings" -> @greetings
"goodbyes" -> @goodbyes
_ -> []
end

# Ideally select2 gets reset when select1 updates but we'll leave it off
# for simplicity

{:noreply,
assign(socket, form: to_form(changeset(demo_params), as: :demo), select2_opts: select2_opts)}
end

def handle_event("submitted", %{"demo" => _demo_params}, socket) do
{:noreply,
assign(socket,
form: to_form(changeset(%{}), as: :demo),
select2_opts: []
)}
end

@impl Phoenix.LiveView
def render(assigns) do
~H"""
<script src="https://cdn.tailwindcss.com/3.4.3"></script>
<div class="p-20">
<.form for={@form} phx-change="updated" phx-submit="submitted" class="space-y-4">
<.input
type="select"
field={@form[:select1]}
label="select1"
prompt="Select"
options={@select1_opts}
/>
<.input
type="select"
field={@form[:select2]}
label="select2"
prompt="Select"
options={@select2_opts}
/>
<.input type="text" field={@form[:dummy]} label="Some text" />
<button class="text-sm border bg-zinc-200" type="submit">Submit</button>
</.form>
</div>
"""
end

attr :for, :string, default: nil
slot(:inner_block, required: true)

def label(assigns) do
~H"""
<label for={@for} class="block text-sm font-semibold leading-6 text-zinc-800">
<%= render_slot(@inner_block) %>
</label>
"""
end

###
# Input components copied and adjusted from generated core_components

attr :id, :any, default: nil
attr :name, :any
attr :label, :string, default: nil
attr :value, :any

attr :type, :string,
default: "text",
values: ~w(checkbox color date datetime-local email file month number password
range search select tel text textarea time url week)

attr :field, Phoenix.HTML.FormField

attr :errors, :list, default: []
attr :checked, :boolean
attr :prompt, :string
attr :options, :list
attr :multiple, :boolean, default: false

attr :rest, :global,
include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step)

slot(:inner_block)

def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
errors = if Phoenix.Component.used_input?(field), do: field.errors, else: []

assigns
|> assign(field: nil, id: assigns.id || field.id)
|> assign(:errors, errors)
|> assign_new(:name, fn -> if assigns.multiple, do: field.name <> "[]", else: field.name end)
|> assign_new(:value, fn -> field.value end)
|> input()
end

def input(%{type: "select"} = assigns) do
~H"""
<div>
<.label for={@id}><%= @label %></.label>
<select
id={@id}
name={@name}
class="mt-2 block w-full rounded-md border border-gray-300 bg-white shadow-sm focus:border-zinc-400 focus:ring-0 sm:text-sm"
multiple={@multiple}
{@rest}
>
<option :if={@prompt} value=""><%= @prompt %></option>
<%= Phoenix.HTML.Form.options_for_select(@options, @value) %>
</select>
</div>
"""
end

# All other inputs text, datetime-local, url, password, etc. are handled here...
def input(assigns) do
~H"""
<div>
<.label for={@id}><%= @label %></.label>
<input
type={@type}
name={@name}
id={@id}
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
class={[
"mt-2 px-2 block w-full rounded-lg text-zinc-900 border focus:ring-0 sm:text-sm sm:leading-6",
@errors == [] && "border-zinc-300 focus:border-zinc-400",
@errors != [] && "border-rose-400 focus:border-rose-400"
]}
{@rest}
/>
</div>
"""
end
end

0 comments on commit ca1db79

Please sign in to comment.