- add_station no longer seeds `"input" => ""` in params, so used_input?/1 treats the new row as untouched and hides the validate_required error until the user types. - Show page's format_distance/format_db/format_meters helpers coerce with `* 1.0` because JSONB returns bare zeros as integers, which crashed Float.round/2 (FunctionClauseError on /rover-planning/:id render). - Lat/lon row uses items-start + mt-6 trash so the inputs stay aligned even when the callsign cell grows from validation feedback.
185 lines
5.9 KiB
Elixir
185 lines
5.9 KiB
Elixir
defmodule MicrowavepropWeb.RoverPlanningLiveTest do
|
|
use MicrowavepropWeb.ConnCase, async: true
|
|
|
|
import Phoenix.LiveViewTest
|
|
|
|
alias Microwaveprop.AccountsFixtures
|
|
alias Microwaveprop.Repo
|
|
alias Microwaveprop.Rover
|
|
alias Microwaveprop.RoverPlanning
|
|
alias Microwaveprop.RoverPlanning.Path
|
|
alias Microwaveprop.Terrain.ElevationClient
|
|
|
|
setup do
|
|
Req.Test.stub(ElevationClient, fn conn ->
|
|
params = Plug.Conn.fetch_query_params(conn).query_params
|
|
lat_count = params["latitude"] |> String.split(",") |> length()
|
|
Req.Test.json(conn, %{"elevation" => List.duplicate(200.0, lat_count)})
|
|
end)
|
|
|
|
:ok
|
|
end
|
|
|
|
defp create_mission(user, name) do
|
|
{:ok, _} = Rover.create_location(user, %{lat: 32.0, lon: -97.0, status: :good})
|
|
|
|
{:ok, mission} =
|
|
RoverPlanning.create_mission(user, %{
|
|
"name" => name,
|
|
"band_mhz" => 10_000,
|
|
"only_known_good" => true,
|
|
"rover_height_ft" => 8.0,
|
|
"station_height_ft" => 30.0,
|
|
"stations" => %{"0" => %{"input" => "EM12kp", "position" => 0}}
|
|
})
|
|
|
|
mission
|
|
end
|
|
|
|
describe "index" do
|
|
test "anonymous visitor sees the table and a sign-in prompt", %{conn: conn} do
|
|
{:ok, _lv, html} = live(conn, ~p"/rover-planning")
|
|
assert html =~ "Rover Planning"
|
|
assert html =~ "Sign in"
|
|
end
|
|
|
|
test "logged-in user sees the New mission button", %{conn: conn} do
|
|
user = AccountsFixtures.user_fixture()
|
|
conn = log_in_user(conn, user)
|
|
{:ok, _lv, html} = live(conn, ~p"/rover-planning")
|
|
assert html =~ "New mission"
|
|
end
|
|
|
|
test "table shows existing missions and links to the show page", %{conn: conn} do
|
|
user = AccountsFixtures.user_fixture()
|
|
mission = create_mission(user, "Visible mission")
|
|
|
|
{:ok, _lv, html} = live(conn, ~p"/rover-planning")
|
|
assert html =~ "Visible mission"
|
|
assert html =~ ~s(href="/rover-planning/#{mission.id}")
|
|
end
|
|
end
|
|
|
|
describe "show" do
|
|
test "renders mission details + path table", %{conn: conn} do
|
|
user = AccountsFixtures.user_fixture()
|
|
mission = create_mission(user, "Detail mission")
|
|
|
|
{:ok, _lv, html} = live(conn, ~p"/rover-planning/#{mission.id}")
|
|
assert html =~ "Detail mission"
|
|
assert html =~ "Stationary stations"
|
|
assert html =~ "Path profiles"
|
|
end
|
|
|
|
test "renders integer path-result values without crashing", %{conn: conn} do
|
|
# JSONB round-trips bare zeros as integers (e.g. `0` not `0.0`), so the
|
|
# show page MUST tolerate non-float numerics in `result`. Previously
|
|
# `Float.round(value, n)` crashed with FunctionClauseError when value
|
|
# came back as integer 0.
|
|
user = AccountsFixtures.user_fixture()
|
|
mission = create_mission(user, "Integer result mission")
|
|
|
|
[path | _] = Repo.all(Path)
|
|
|
|
{:ok, _} =
|
|
path
|
|
|> Ecto.Changeset.change(%{
|
|
status: :complete,
|
|
result: %{
|
|
"distance_km" => 0,
|
|
"min_clearance_m" => 0,
|
|
"diffraction_db" => 0,
|
|
"verdict" => "clear"
|
|
}
|
|
})
|
|
|> Repo.update()
|
|
|
|
{:ok, _lv, html} = live(conn, ~p"/rover-planning/#{mission.id}")
|
|
assert html =~ "Integer result mission"
|
|
assert html =~ "Clear"
|
|
end
|
|
|
|
test "redirects when mission missing", %{conn: conn} do
|
|
missing = Ecto.UUID.generate()
|
|
|
|
assert {:error, {:live_redirect, %{to: "/rover-planning"}}} =
|
|
live(conn, ~p"/rover-planning/#{missing}")
|
|
end
|
|
end
|
|
|
|
describe "form" do
|
|
test "anonymous user gets redirected to /rover-planning", %{conn: conn} do
|
|
assert {:error, {:live_redirect, %{to: "/rover-planning"}}} =
|
|
live(conn, ~p"/rover-planning/new")
|
|
end
|
|
|
|
test "clicking 'Add station' does not show 'can't be blank' on the new row", %{conn: conn} do
|
|
user = AccountsFixtures.user_fixture()
|
|
conn = log_in_user(conn, user)
|
|
{:ok, lv, _html} = live(conn, ~p"/rover-planning/new")
|
|
|
|
html =
|
|
lv
|
|
|> element("button[phx-click='add_station']")
|
|
|> render_click()
|
|
|
|
# The new (untouched) station must not render a validation error until
|
|
# the user actually interacts with its input.
|
|
refute html =~ "can't be blank"
|
|
end
|
|
|
|
test "typing into the form does not flip the only_known_good checkbox", %{conn: conn} do
|
|
user = AccountsFixtures.user_fixture()
|
|
conn = log_in_user(conn, user)
|
|
{:ok, lv, _html} = live(conn, ~p"/rover-planning/new")
|
|
|
|
html =
|
|
lv
|
|
|> form("#mission-form",
|
|
mission: %{
|
|
name: "Some name",
|
|
band_mhz: "10000",
|
|
rover_height_ft: "8.0",
|
|
station_height_ft: "30.0",
|
|
only_known_good: "true",
|
|
stations: %{"0" => %{input: ""}}
|
|
}
|
|
)
|
|
|> render_change()
|
|
|
|
# The default-checked box must STILL be checked after a phx-change.
|
|
# Hidden "false" + checkbox "true" with hidden first = checkbox wins.
|
|
assert html =~
|
|
~s(name="mission[only_known_good]" value="true" checked)
|
|
end
|
|
|
|
test "logged-in user can create a mission with a callsign-input station",
|
|
%{conn: conn} do
|
|
user = AccountsFixtures.user_fixture()
|
|
{:ok, _} = Rover.create_location(user, %{lat: 32.0, lon: -97.0, status: :good})
|
|
conn = log_in_user(conn, user)
|
|
|
|
{:ok, lv, html} = live(conn, ~p"/rover-planning/new")
|
|
assert html =~ "Only check against known good locations"
|
|
assert html =~ ~s(checked)
|
|
|
|
{:error, {:live_redirect, %{to: redirect_to}}} =
|
|
lv
|
|
|> form("#mission-form",
|
|
mission: %{
|
|
name: "From form",
|
|
band_mhz: "10000",
|
|
only_known_good: "true",
|
|
rover_height_ft: "8.0",
|
|
station_height_ft: "30.0",
|
|
stations: %{
|
|
"0" => %{input: "EM12kp"}
|
|
}
|
|
}
|
|
)
|
|
|> render_submit()
|
|
|
|
assert redirect_to =~ ~r{^/rover-planning/[0-9a-f-]+$}
|
|
end
|
|
end
|
|
end
|