prop/test/microwaveprop/rover/location_test.exs
Graham McIntire 140351c0f6
feat(rover-locations): add /rover-locations page with CRUD
New globally-shared list of rover-friendly (or off-limits) parking
spots. Anyone can view; logged-in users can add new locations and
edit/delete their own. Each location stores lat/lon, free-text notes,
and a status enum (:ideal | :off_limits).

  * Microwaveprop.Rover.Location schema + migration
  * Rover.list_locations/0, create_location/2, update_location/3,
    delete_location/2 (mutations require User; ownership-scoped)
  * /rover-locations LiveView in the public live_session — Add button
    is disabled for anonymous visitors, Edit/Delete buttons render
    only on the user's own entries
  * Tests for context + LiveView covering anonymous read, owner-only
    edit/delete, and form submission
2026-04-26 13:08:27 -05:00

85 lines
2.7 KiB
Elixir

defmodule Microwaveprop.RoverLocationsTest do
use Microwaveprop.DataCase, async: true
alias Microwaveprop.Rover
alias Microwaveprop.Rover.Location
defp user_fixture do
Microwaveprop.AccountsFixtures.user_fixture()
end
describe "list_locations/0" do
test "returns all locations across all users, newest first" do
a = user_fixture()
b = user_fixture()
{:ok, _l1} = Rover.create_location(a, %{lat: 32.5, lon: -97.5, status: :ideal})
{:ok, _l2} = Rover.create_location(b, %{lat: 33.0, lon: -96.5, status: :off_limits})
result = Rover.list_locations()
assert length(result) == 2
assert Enum.all?(result, &match?(%Location{}, &1))
end
end
describe "create_location/2" do
test "stores the creator's user_id" do
user = user_fixture()
{:ok, loc} = Rover.create_location(user, %{lat: 32.5, lon: -97.5, status: :ideal})
assert loc.user_id == user.id
end
test "supports notes and the off_limits status" do
user = user_fixture()
{:ok, loc} =
Rover.create_location(user, %{
lat: 32.0,
lon: -97.0,
status: :off_limits,
notes: "private property"
})
assert loc.status == :off_limits
assert loc.notes == "private property"
end
test "rejects out-of-range coordinates" do
user = user_fixture()
assert {:error, %Ecto.Changeset{}} = Rover.create_location(user, %{lat: 100.0, lon: 0.0, status: :ideal})
end
test "requires lat and lon" do
user = user_fixture()
assert {:error, cs} = Rover.create_location(user, %{status: :ideal})
assert "can't be blank" in errors_on(cs).lat
end
end
describe "update_location/3 and delete_location/2" do
test "creator can update their location" do
user = user_fixture()
{:ok, loc} = Rover.create_location(user, %{lat: 32.0, lon: -97.0, status: :ideal})
assert {:ok, updated} = Rover.update_location(user, loc.id, %{notes: "updated"})
assert updated.notes == "updated"
end
test "non-creator cannot update or delete" do
user = user_fixture()
other = user_fixture()
{:ok, loc} = Rover.create_location(user, %{lat: 32.0, lon: -97.0, status: :ideal})
assert {:error, :not_found} = Rover.update_location(other, loc.id, %{notes: "x"})
assert {:error, :not_found} = Rover.delete_location(other, loc.id)
end
test "creator can delete their location" do
user = user_fixture()
{:ok, loc} = Rover.create_location(user, %{lat: 32.0, lon: -97.0, status: :ideal})
assert {:ok, _} = Rover.delete_location(user, loc.id)
refute Enum.any?(Rover.list_locations(), &(&1.id == loc.id))
end
end
end