diff --git a/lib/microwaveprop_web/live/submit_live.ex b/lib/microwaveprop_web/live/submit_live.ex index 66dfa1c1..367cc7d8 100644 --- a/lib/microwaveprop_web/live/submit_live.ex +++ b/lib/microwaveprop_web/live/submit_live.ex @@ -54,10 +54,20 @@ defmodule MicrowavepropWeb.SubmitLive do end end + @valid_tabs ~w(single csv adif)a + @impl true def handle_event("switch_tab", %{"tab" => tab}, socket) do - socket = assign(socket, active_tab: String.to_existing_atom(tab)) - {:noreply, MicrowavepropWeb.LiveStashGuard.stash(socket)} + case Enum.find(@valid_tabs, &(Atom.to_string(&1) == tab)) do + nil -> + # Stale or forged client event — ignore instead of crashing the + # LiveView via String.to_existing_atom/1. + {:noreply, socket} + + atom -> + socket = assign(socket, active_tab: atom) + {:noreply, MicrowavepropWeb.LiveStashGuard.stash(socket)} + end end def handle_event("validate", %{"contact" => contact_params}, socket) do diff --git a/test/microwaveprop_web/live/submit_live_test.exs b/test/microwaveprop_web/live/submit_live_test.exs index 1f524bf7..1aada6f4 100644 --- a/test/microwaveprop_web/live/submit_live_test.exs +++ b/test/microwaveprop_web/live/submit_live_test.exs @@ -43,6 +43,28 @@ defmodule MicrowavepropWeb.SubmitLiveTest do end end + describe "switch_tab" do + test "ignores an unknown tab string instead of crashing the LiveView", %{conn: conn} do + {:ok, lv, _html} = live(conn, ~p"/submit") + + # An unknown tab name used to flow into String.to_existing_atom/1 + # and bring the LiveView down. We expect the event to be a no-op + # and the process to stay alive. + render_hook(lv, "switch_tab", %{"tab" => "definitely-not-a-tab-#{System.unique_integer()}"}) + + assert Process.alive?(lv.pid) + end + + test "honors a known tab name", %{conn: conn} do + {:ok, lv, _html} = live(conn, ~p"/submit") + + html = render_hook(lv, "switch_tab", %{"tab" => "csv"}) + + # Active tab moved to CSV — the CSV section's heading is now visible. + assert html =~ "CSV" + end + end + describe "validate" do test "shows validation errors on change", %{conn: conn} do {:ok, lv, _html} = live(conn, ~p"/submit")