This commit is contained in:
2026-07-04 19:27:17 +09:00
parent 34cd5ad2e7
commit ba6a0b2c17
30 changed files with 2935 additions and 247 deletions
@@ -1,8 +1,14 @@
defmodule Rsh26poolWeb.PageControllerTest do
use Rsh26poolWeb.ConnCase
test "GET /", %{conn: conn} do
test "GET / renders the Japanese home with create and enter entry points", %{conn: conn} do
conn = get(conn, ~p"/")
assert html_response(conn, 200) =~ "Peace of mind from prototype to production"
response = html_response(conn, 200)
assert response =~ "みんなで"
assert response =~ "ルームを作成"
assert response =~ "ルームに参加"
assert response =~ ~p"/create"
assert response =~ ~p"/enter"
end
end
@@ -0,0 +1,92 @@
defmodule Rsh26poolWeb.RoomControllerTest do
use Rsh26poolWeb.ConnCase, async: true
alias Rsh26pool.Voting
defp valid_room_params(overrides \\ %{}) do
Map.merge(
%{
"name" => "テストルーム",
"votes_per_user" => "3",
"grouping_mode" => "false",
"leader_threshold" => "2",
"closes_at_local" => ""
},
overrides
)
end
describe "POST /create" do
test "valid params redirect to the manage page and log in the owner", %{conn: conn} do
conn = post(conn, ~p"/create", room: valid_room_params(%{"name" => "作成テスト"}))
path = redirected_to(conn)
assert "/manage/" <> number = path
assert number =~ ~r/^\d{6}$/
token = get_session(conn, "participant_token")
assert token
owner = Voting.get_participant_by_token(token)
assert owner.role == "owner"
assert owner.room.room_number == number
assert owner.room.name == "作成テスト"
end
test "invalid params re-render the form with a Japanese error and no login", %{conn: conn} do
conn = post(conn, ~p"/create", room: valid_room_params(%{"name" => ""}))
assert html_response(conn, 200)
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "ルームを作成できませんでした"
assert get_session(conn, "participant_token") == nil
end
end
describe "POST /enter" do
test "a valid room number and name redirect to the vote page and log in", %{conn: conn} do
{:ok, %{room: room}} = Voting.create_room(valid_room_params(%{"name" => "参加先"}))
conn = post(conn, ~p"/enter", enter: %{"room_number" => room.room_number, "name" => "花子"})
assert redirected_to(conn) == ~p"/vote/#{room.room_number}"
token = get_session(conn, "participant_token")
assert token
participant = Voting.get_participant_by_token(token)
assert participant.name == "花子"
assert participant.role == "member"
assert participant.room.id == room.id
end
test "an unknown room number stays on the page with a not-found flash", %{conn: conn} do
conn = post(conn, ~p"/enter", enter: %{"room_number" => "000000", "name" => "花子"})
assert html_response(conn, 200)
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "見つかりません"
assert get_session(conn, "participant_token") == nil
end
test "blank fields stay on the page with a validation flash", %{conn: conn} do
conn = post(conn, ~p"/enter", enter: %{"room_number" => "", "name" => ""})
assert html_response(conn, 200)
assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "ルーム番号と名前を入力してください"
assert get_session(conn, "participant_token") == nil
end
end
describe "DELETE /logout" do
test "clears the session token and redirects home", %{conn: conn} do
{:ok, %{owner: owner}} = Voting.create_room(valid_room_params())
conn =
conn
|> Plug.Test.init_test_session(%{"participant_token" => owner.token})
|> delete(~p"/logout")
assert redirected_to(conn) == ~p"/"
assert get_session(conn, "participant_token") == nil
end
end
end
@@ -0,0 +1,94 @@
defmodule Rsh26poolWeb.ManageLiveTest do
use Rsh26poolWeb.ConnCase
import Phoenix.LiveViewTest
alias Rsh26pool.Voting
defp new_room(overrides \\ %{}) do
{:ok, result} =
Voting.create_room(
Map.merge(
%{
"name" => "管理ルーム",
"votes_per_user" => "2",
"grouping_mode" => "false",
"leader_threshold" => "2",
"closes_at_local" => ""
},
overrides
)
)
result
end
defp authed(conn, participant) do
Plug.Test.init_test_session(conn, %{"participant_token" => participant.token})
end
test "a non-owner member is redirected to the home page", %{conn: conn} do
%{room: room} = new_room()
{:ok, member} = Voting.join_room(room, %{"name" => "一般参加者"})
assert {:error, {:redirect, %{to: "/"}}} =
conn |> authed(member) |> live(~p"/manage/#{room.room_number}")
end
test "the owner can view vote counts, rename the room, and close voting", %{conn: conn} do
%{room: room, owner: owner} = new_room(%{"votes_per_user" => "2"})
{:ok, poster} = Voting.join_room(room, %{"name" => "投稿者"})
{:ok, idea} = Voting.create_idea(room, poster, %{"text" => "人気の案"})
{:ok, voter1} = Voting.join_room(room, %{"name" => "投票者1"})
{:ok, voter2} = Voting.join_room(room, %{"name" => "投票者2"})
{:ok, _} = Voting.vote(voter1, idea.id)
{:ok, _} = Voting.vote(voter2, idea.id)
{:ok, lv, html} = conn |> authed(owner) |> live(~p"/manage/#{room.room_number}")
assert html =~ "管理ページ"
# The result row shows the idea and its vote count of 2 (rank is 1).
result_row = lv |> element("ol li", "人気の案") |> render()
assert result_row =~ "人気の案"
assert result_row =~ "2"
# Rename via the form.
lv |> form("#rename-form", room: %{name: "新しいルーム名"}) |> render_submit()
assert render(lv) =~ "新しいルーム名"
assert Voting.reload_room(room).name == "新しいルーム名"
# Close via the close button.
refute render(lv) =~ "この投票は終了しています"
lv |> element("button[phx-click='close']") |> render_click()
assert Voting.reload_room(room).status == "closed"
assert render(lv) =~ "この投票は終了しています"
end
test "in grouping mode the group cards appear after closing", %{conn: conn} do
%{room: room, owner: owner} =
new_room(%{"grouping_mode" => "true", "leader_threshold" => "2", "votes_per_user" => "3"})
{:ok, leader} = Voting.join_room(room, %{"name" => "リーダーA"})
{:ok, m1} = Voting.join_room(room, %{"name" => "メンバー1"})
{:ok, m2} = Voting.join_room(room, %{"name" => "メンバー2"})
{:ok, opinion} = Voting.create_idea(room, leader, %{"text" => "公園で花見をする"})
{:ok, _} = Voting.create_idea(room, m1, %{"text" => "案1"})
{:ok, _} = Voting.create_idea(room, m2, %{"text" => "案2"})
{:ok, _} = Voting.vote(m1, opinion.id)
{:ok, _} = Voting.vote(m2, opinion.id)
{:ok, lv, _} = conn |> authed(owner) |> live(~p"/manage/#{room.room_number}")
# No grouping section while the room is still open.
refute render(lv) =~ "グループ分けの結果"
lv |> element("button[phx-click='close']") |> render_click()
closed_html = render(lv)
assert closed_html =~ "グループ分けの結果"
assert closed_html =~ "リーダーA グループ"
end
end
+124
View File
@@ -0,0 +1,124 @@
defmodule Rsh26poolWeb.VoteLiveTest do
use Rsh26poolWeb.ConnCase
import Phoenix.LiveViewTest
alias Rsh26pool.Voting
defp new_room(overrides \\ %{}) do
{:ok, result} =
Voting.create_room(
Map.merge(
%{
"name" => "投票ルーム",
"votes_per_user" => "2",
"grouping_mode" => "false",
"leader_threshold" => "2",
"closes_at_local" => ""
},
overrides
)
)
result
end
defp authed(conn, participant) do
Plug.Test.init_test_session(conn, %{"participant_token" => participant.token})
end
describe "access control" do
test "an unauthenticated visitor is redirected to the enter page", %{conn: conn} do
%{room: room} = new_room()
assert {:error, {:redirect, %{to: to}}} = live(conn, ~p"/vote/#{room.room_number}")
assert to =~ "/enter"
end
test "a participant of a different room is redirected", %{conn: conn} do
%{room: room} = new_room()
%{room: other} = new_room()
{:ok, outsider} = Voting.join_room(other, %{"name" => "部外者"})
assert {:error, {:redirect, %{to: to}}} =
conn |> authed(outsider) |> live(~p"/vote/#{room.room_number}")
assert to =~ "/enter"
end
end
describe "authenticated member" do
test "can render the room, post an idea, and see it appear", %{conn: conn} do
%{room: room} = new_room()
{:ok, member} = Voting.join_room(room, %{"name" => "参加者"})
{:ok, lv, html} = conn |> authed(member) |> live(~p"/vote/#{room.room_number}")
assert html =~ room.name
assert html =~ "残りの投票数"
lv |> form("#idea-form", idea: %{text: "カラオケに行こう"}) |> render_submit()
assert render(lv) =~ "カラオケに行こう"
assert [%{text: "カラオケに行こう"}] = Voting.list_ideas(room)
end
test "voting marks the idea 投票済み and records the vote", %{conn: conn} do
%{room: room} = new_room(%{"votes_per_user" => "2"})
{:ok, poster} = Voting.join_room(room, %{"name" => "投稿者"})
{:ok, idea} = Voting.create_idea(room, poster, %{"text" => "案1"})
{:ok, member} = Voting.join_room(room, %{"name" => "参加者"})
{:ok, lv, _} = conn |> authed(member) |> live(~p"/vote/#{room.room_number}")
html = lv |> element("#idea-#{idea.id} button[phx-click='vote']") |> render_click()
assert html =~ "投票済み"
assert Voting.voted?(member, idea.id)
assert Voting.votes_remaining(room, member) == 1
end
test "spending all votes disables remaining buttons and the limit is enforced", %{conn: conn} do
%{room: room} = new_room(%{"votes_per_user" => "1"})
{:ok, poster} = Voting.join_room(room, %{"name" => "投稿者"})
{:ok, i1} = Voting.create_idea(room, poster, %{"text" => "案1"})
{:ok, i2} = Voting.create_idea(room, poster, %{"text" => "案2"})
{:ok, member} = Voting.join_room(room, %{"name" => "参加者"})
{:ok, lv, _} = conn |> authed(member) |> live(~p"/vote/#{room.room_number}")
# Spend the single vote on i1.
lv |> element("#idea-#{i1.id} button[phx-click='vote']") |> render_click()
# The other idea's vote button is now disabled in the UI.
assert has_element?(lv, "#idea-#{i2.id} button[disabled]")
# And the server-side guard surfaces the limit message if a vote is forced.
html = render_click(lv, "vote", %{"id" => "#{i2.id}"})
assert html =~ "投票できる数の上限に達しました"
refute Voting.voted?(member, i2.id)
end
test "results are hidden while open and shown once the room closes", %{conn: conn} do
%{room: room} = new_room()
{:ok, poster} = Voting.join_room(room, %{"name" => "投稿者"})
{:ok, _idea} = Voting.create_idea(room, poster, %{"text" => "唯一の案"})
{:ok, member} = Voting.join_room(room, %{"name" => "参加者"})
{:ok, lv, html} = conn |> authed(member) |> live(~p"/vote/#{room.room_number}")
# While open: idea form is present, and no results ranking (<ol>) leaks.
assert has_element?(lv, "#idea-form")
refute html =~ "結果"
refute has_element?(lv, "ol")
# Closing broadcasts to the live view, which reloads and shows results.
{:ok, _} = Voting.close_room(room)
closed_html = render(lv)
assert closed_html =~ "この投票は終了しました"
assert has_element?(lv, "ol")
assert closed_html =~ "唯一の案"
refute has_element?(lv, "#idea-form")
end
end
end