sendou.ink/e2e/tournament-bracket.spec.ts
Kalle f599c408fb
Some checks are pending
E2E Tests / e2e (push) Waiting to run
Tests and checks on push / run-checks-and-tests (push) Waiting to run
Updates translation progress / update-translation-progress-issue (push) Waiting to run
Mark one more test as slow
2026-03-21 15:46:15 +02:00

1313 lines
36 KiB
TypeScript

import type { Page } from "@playwright/test";
import { NZAP_TEST_ID } from "~/db/seed/constants";
import { ADMIN_DISCORD_ID } from "~/features/admin/admin-constants";
import { updateNoScreenSchema } from "~/features/settings/settings-schemas";
import {
expect,
impersonate,
isNotVisible,
navigate,
seed,
selectUser,
startBracket,
submit,
test,
} from "~/utils/playwright";
import { createFormHelpers } from "~/utils/playwright-form";
import {
NOTIFICATIONS_URL,
SETTINGS_PAGE,
tournamentAdminPage,
tournamentBracketsPage,
tournamentMatchPage,
tournamentPage,
tournamentTeamsPage,
userResultsPage,
} from "~/utils/urls";
const navigateToMatch = async (page: Page, matchId: number) => {
await expect(async () => {
await page.locator(`[data-match-id="${matchId}"]`).click();
await expect(page.getByTestId("match-header")).toBeVisible();
}).toPass();
};
const reportResult = async ({
page,
amountOfMapsToReport,
winner = 1,
points,
}: {
page: Page;
amountOfMapsToReport: 1 | 2 | 3 | 4;
winner?: 1 | 2;
points?: [number, number];
}) => {
const confirmCheckbox = page.getByTestId("end-confirmation");
const fillPointsInput = async () => {
if (!points) return;
await page.getByTestId("points-input-1").fill(String(points[0]));
await page.getByTestId("points-input-2").fill(String(points[1]));
};
await page.getByTestId("actions-tab").click();
// Auto-detect and set rosters for teams with 5+ players
// Check if first team needs roster selection (checkbox exists and is not disabled)
const firstTeamCheckbox = page.getByTestId("player-checkbox-0").first();
if (
(await firstTeamCheckbox.count()) > 0 &&
!(await firstTeamCheckbox.isDisabled())
) {
await page.getByTestId("player-checkbox-0").first().click();
await page.getByTestId("player-checkbox-1").first().click();
await page.getByTestId("player-checkbox-2").first().click();
await page.getByTestId("player-checkbox-3").first().click();
await submit(page, "save-active-roster-button-0");
// update went through
await expect(page.getByTestId("player-checkbox-0").first()).toBeDisabled();
}
// Check if second team needs roster selection
const lastTeamCheckbox = page.getByTestId("player-checkbox-0").last();
if (
(await lastTeamCheckbox.count()) > 0 &&
!(await lastTeamCheckbox.isDisabled())
) {
await page.getByTestId("player-checkbox-0").last().click();
await page.getByTestId("player-checkbox-1").last().click();
await page.getByTestId("player-checkbox-2").last().click();
await page.getByTestId("player-checkbox-3").last().click();
await submit(page, "save-active-roster-button-1");
}
await fillPointsInput();
await page.getByTestId(`winner-radio-${winner}`).click();
await submit(page, "report-score-button");
await expect(page.getByText(winner === 1 ? "1-0" : "0-1")).toBeVisible();
if (amountOfMapsToReport >= 2) {
await page.getByTestId(`winner-radio-${winner}`).click();
await fillPointsInput();
if (amountOfMapsToReport === 2) {
await confirmCheckbox.click();
await submit(page, "report-score-button");
await expect(page.getByTestId("report-timestamp")).toBeVisible();
} else {
await submit(page, "report-score-button");
}
}
if (amountOfMapsToReport === 3) {
await expect(page.getByText("2-0")).toBeVisible();
await page.getByTestId(`winner-radio-${winner}`).click();
await fillPointsInput();
await confirmCheckbox.click();
await submit(page, "report-score-button");
await expect(page.getByTestId("report-timestamp")).toBeVisible();
}
if (amountOfMapsToReport === 4) {
await expect(page.getByText("2-0")).toBeVisible();
await page.getByTestId(`winner-radio-${winner}`).click();
await fillPointsInput();
await submit(page, "report-score-button");
await expect(page.getByText("3-0")).toBeVisible();
await page.getByTestId(`winner-radio-${winner}`).click();
await confirmCheckbox.click();
await submit(page, "report-score-button");
await expect(page.getByTestId("report-timestamp")).toBeVisible();
}
};
const backToBracket = async (page: Page) => {
await expect(async () => {
await page.getByTestId("back-to-bracket-button").click();
await expect(page.getByTestId("brackets-viewer")).toBeVisible();
}).toPass();
};
const expectScore = (page: Page, score: [number, number]) =>
expect(page.getByText(score.join("-"))).toBeVisible();
test.describe("Tournament bracket", () => {
test("sets active roster as regular member", async ({ page }) => {
const tournamentId = 1;
// User 37 is owner of team 10 (seed 10) which has 5 players
// Team 10 vs Team 9 (seed 9) is match 2 in WB Round 1
const matchId = 2;
await startBracket(page, tournamentId);
await impersonate(page, 37);
await navigate({
page,
url: tournamentMatchPage({ tournamentId, matchId }),
});
await expect(page.getByTestId("active-roster-needed-text")).toBeVisible();
await page.getByTestId("actions-tab").click();
// Team 10 has 5 players; select first 4 for active roster
// Team 10 is team 2 (second team in the match), so use last()
await page.getByTestId("player-checkbox-0").last().click();
await page.getByTestId("player-checkbox-1").last().click();
await page.getByTestId("player-checkbox-2").last().click();
await page.getByTestId("player-checkbox-3").last().click();
await submit(page, "save-active-roster-button-1");
// did it persist?
await navigate({
page,
url: tournamentMatchPage({ tournamentId, matchId }),
});
// Only team 10 needed to set roster (team 9 has 4 players)
await isNotVisible(page.getByTestId("active-roster-needed-text"));
await page.getByTestId("actions-tab").click();
await page.getByTestId("edit-active-roster-button").click();
await page.getByTestId("player-checkbox-3").last().click();
await page.getByTestId("player-checkbox-4").last().click();
await submit(page, "save-active-roster-button-1");
await expect(page.getByTestId("edit-active-roster-button")).toBeVisible();
await expect(
page.getByTestId("player-checkbox-3").last(),
).not.toBeChecked();
});
// 1) Report winner of N-ZAP's first match
// 2) Report winner of the adjacent match by using admin powers
// 3) Report one match on the only losers side match available
// 4) Try to reopen N-ZAP's first match and fail
// 5) Undo score of first losers match
// 6) Try to reopen N-ZAP's first match and succeed
// 7) As N-ZAP, undo all scores and switch to different team sweeping
test("reports score and sees bracket update", async ({ page }) => {
test.slow();
const tournamentId = 2;
await startBracket(page);
await impersonate(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
// 1)
await navigateToMatch(page, 5);
await reportResult({ page, amountOfMapsToReport: 2 });
await backToBracket(page);
// 2)
await impersonate(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await navigateToMatch(page, 6);
await reportResult({ page, amountOfMapsToReport: 2 });
await backToBracket(page);
// 3)
await navigateToMatch(page, 18);
await reportResult({
page,
amountOfMapsToReport: 1,
});
await backToBracket(page);
// 4)
await navigateToMatch(page, 5);
await isNotVisible(page.getByTestId("reopen-match-button"));
await backToBracket(page);
// 5)
await navigateToMatch(page, 18);
await submit(page, "undo-score-button");
await expectScore(page, [0, 0]);
await backToBracket(page);
// 6)
await navigateToMatch(page, 5);
await submit(page, "reopen-match-button");
await expectScore(page, [1, 0]);
// 7)
await impersonate(page, NZAP_TEST_ID);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await navigateToMatch(page, 5);
await submit(page, "undo-score-button");
await expectScore(page, [0, 0]);
await reportResult({
page,
amountOfMapsToReport: 2,
winner: 2,
});
await backToBracket(page);
await expect(
page.locator("[data-round-id='5'] [data-participant-id='102']"),
).toBeVisible();
});
test("adds a sub mid tournament (from non checked in team)", async ({
page,
}) => {
const tournamentId = 1;
await startBracket(page, tournamentId);
// captain of the first team
await impersonate(page, 5);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("add-sub-button").click();
await page.getByTestId("copy-invite-link-button").click();
const inviteLinkProd: string = await page.evaluate(
"navigator.clipboard.readText()",
);
const inviteLink = inviteLinkProd.replace(
"https://sendou.ink",
"http://localhost:6173",
);
await impersonate(page, NZAP_TEST_ID);
await navigate({
page,
url: inviteLink,
});
await submit(page);
await expect(page).toHaveURL(/brackets/);
});
test("completes and finalizes a small tournament with badge assigning", async ({
page,
}) => {
test.slow();
const tournamentId = 2;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentPage(tournamentId),
});
await page.getByTestId("admin-tab").click();
await page.getByLabel("Action").selectOption("CHECK_OUT");
for (let id = 103; id < 117; id++) {
await page.getByLabel("Team", { exact: true }).selectOption(String(id));
await submit(page);
}
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
await page.locator('[data-match-id="1"]').click();
await reportResult({
page,
amountOfMapsToReport: 2,
});
await backToBracket(page);
await page.getByTestId("finalize-tournament-button").click();
await page.getByLabel("Receiving team").first().selectOption("101");
await page.getByLabel("Receiving team").last().selectOption("102");
await submit(page, "confirm-button");
await page.getByTestId("results-tab").click();
// seed performance rating shows up after tournament is finalized
await expect(page.getByTestId("spr-header")).toBeVisible();
await navigate({
page,
url: userResultsPage({ discordId: ADMIN_DISCORD_ID }),
});
await expect(
page.getByTestId("tournament-name-cell").getByText("In The Zone 22"),
).toBeVisible();
await navigate({
page,
url: NOTIFICATIONS_URL,
});
await expect(page.getByTestId("notification-item").first()).toContainText(
"New badge",
);
});
test("completes and finalizes a small tournament (RR->SE w/ underground bracket)", async ({
page,
}) => {
test.setTimeout(150_000);
const tournamentId = 3;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentPage(tournamentId),
});
await page.getByTestId("admin-tab").click();
await page.getByLabel("Action").selectOption("CHECK_OUT");
for (let id = 202; id < 210; id++) {
await page.getByLabel("Team", { exact: true }).selectOption(String(id));
await submit(page);
}
await navigate({
page,
url: tournamentBracketsPage({
tournamentId,
}),
});
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
for (const id of [2, 4, 6, 7, 8, 9, 10, 11, 12]) {
await navigateToMatch(page, id);
await reportResult({
page,
amountOfMapsToReport: 2,
points: [100, 0],
});
await backToBracket(page);
}
// captain of one of the underground bracket teams
await impersonate(page, 57);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByRole("tab", { name: "Underground" }).click();
await submit(page, "check-in-bracket-button");
await impersonate(page);
await navigate({
page,
url: tournamentAdminPage(tournamentId),
});
await page.getByLabel("Action").selectOption("CHECK_IN");
await page.getByLabel("Team", { exact: true }).selectOption("216");
await page
.getByLabel("Bracket", { exact: true })
.selectOption("Underground bracket");
await submit(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId, bracketIdx: 2 }),
});
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
await navigateToMatch(page, 13);
await reportResult({
page,
amountOfMapsToReport: 3,
});
await navigate({
page,
url: tournamentBracketsPage({ tournamentId, bracketIdx: 1 }),
});
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
for (const matchId of [14, 15, 16, 17]) {
await navigateToMatch(page, matchId);
await reportResult({
page,
amountOfMapsToReport: 3,
});
await backToBracket(page);
}
await page.getByTestId("finalize-tournament-button").click();
await page.getByTestId("assign-badges-later-switch").click();
await submit(page, "confirm-button");
// not possible to reopen finals match anymore
await navigateToMatch(page, 14);
await isNotVisible(page.getByTestId("reopen-match-button"));
await backToBracket(page);
});
test("shows tournament results on user profile after finalized tournament", async ({
page,
}) => {
const tournamentId = 4;
await seed(page, "SMALL_SOS");
await impersonate(page);
await navigate({
page,
url: tournamentAdminPage(tournamentId),
});
await page.getByLabel("Action").selectOption("CHECK_OUT");
for (const teamId of ["303", "304"]) {
await page.getByLabel("Team", { exact: true }).selectOption(teamId);
await submit(page);
}
await page.getByTestId("edit-event-info-button").click();
for (let i = 0; i < 3; i++) {
await page.getByTestId("delete-bracket-button").last().click();
}
await page.getByTestId("placements-input").last().fill("1,2");
await submit(page);
await page.getByTestId("brackets-tab").click();
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
await page.locator('[data-match-id="1"]').click();
await reportResult({
page,
amountOfMapsToReport: 2,
points: [100, 0],
});
await backToBracket(page);
await page.getByRole("tab", { name: "Great White" }).click();
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
await page.locator('[data-match-id="2"]').click();
await reportResult({
page,
amountOfMapsToReport: 3,
});
await backToBracket(page);
await page.getByTestId("finalize-tournament-button").click();
await page.getByRole("button", { name: "Finalize" }).click();
await page.getByTestId("results-tab").click();
await page.getByTestId("result-team-name").first().click();
await page.getByTestId("team-member-name").first().click();
await page.getByTestId("user-seasons-tab").click();
await expect(page.getByTestId("seasons-tournament-result")).toBeVisible();
await page.getByTestId("user-results-tab").click();
await expect(
page.getByTestId("tournament-name-cell").first(),
).toContainText("Swim or Sink 101");
await page.getByTestId("mates-button").first().click();
await expect(
page.locator('[data-testid="mates-cell-placement-0"] li'),
).toHaveCount(3);
});
test("changes SOS format and progresses with it & adds a member to another team", async ({
page,
}) => {
test.slow();
const tournamentId = 4;
await seed(page, "SMALL_SOS");
await impersonate(page);
await navigate({
page,
url: tournamentAdminPage(tournamentId),
});
await page.getByTestId("edit-event-info-button").click();
await page.getByTestId("delete-bracket-button").last().click();
await page.getByTestId("placements-input").last().fill("3,4");
await submit(page);
await page.getByTestId("brackets-tab").click();
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
for (const matchId of [1, 2, 3, 4, 5, 6]) {
await page.locator(`[data-match-id="${matchId}"]`).click();
await reportResult({
page,
amountOfMapsToReport: 2,
points: [100, 0],
});
await backToBracket(page);
}
await page.getByRole("tab", { name: "Hammerhead" }).click();
await isNotVisible(page.getByTestId("brackets-viewer"));
await page.getByRole("tab", { name: "Mako" }).click();
await expect(page.getByTestId("brackets-viewer")).toBeVisible();
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
await page.locator('[data-match-id="7"]').click();
await expect(page.getByTestId("back-to-bracket-button")).toBeVisible();
await page.getByTestId("admin-tab").click();
await page.getByLabel("Action").selectOption("ADD_MEMBER");
await page.getByLabel("Team", { exact: true }).selectOption("303"); // a team in the Mako bracket
await selectUser({
labelName: "User",
userName: "Sendou",
page,
});
await submit(page);
await navigate({
page,
url: tournamentTeamsPage(tournamentId),
});
await expect(
page.getByTestId("team-member-name").getByText("Sendou"),
).toHaveCount(2);
});
test("conducts a tournament with many starting brackets", async ({
page,
}) => {
const tournamentId = 4;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentAdminPage(tournamentId),
});
await page.getByTestId("edit-event-info-button").click();
await page.getByTestId("delete-bracket-button").last().click();
for (const toggle of await page
.getByTestId("follow-up-bracket-switch")
.all()) {
await toggle.click();
}
await page.getByLabel("Format").first().selectOption("Single-elimination");
await page.getByLabel("Format").nth(1).selectOption("Single-elimination");
await page.getByLabel("Format").nth(2).selectOption("Swiss");
await page.getByLabel("Format").nth(3).selectOption("Swiss");
await submit(page);
await page.getByText("Seeds").click();
await page.getByTestId("set-starting-brackets").click();
for (let i = 0; i < 16; i++) {
let bracketName: string;
if (i < 4) {
bracketName = "Groups stage";
} else if (i < 8) {
bracketName = "Great White";
} else if (i < 12) {
bracketName = "Hammerhead";
} else {
bracketName = "Mako";
}
await page
.getByTestId("starting-bracket-select")
.nth(i)
.selectOption(bracketName);
}
await submit(page, "set-starting-brackets-submit-button");
await page.getByTestId("brackets-tab").click();
for (const bracketName of [
"Groups stage",
"Great White",
"Hammerhead",
"Mako",
]) {
await page.getByRole("tab", { name: bracketName }).click();
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
}
await expect(page.locator('[data-match-id="11"]')).toBeVisible();
});
test("organizer edits a match after it is done", async ({ page }) => {
const tournamentId = 3;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentPage(tournamentId),
});
await page.getByTestId("brackets-tab").click();
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
await page.locator('[data-match-id="2"]').click();
await reportResult({
page,
amountOfMapsToReport: 2,
points: [100, 0],
});
await page.getByTestId("actions-tab").click();
await page.getByTestId("revise-button").click();
await page.getByTestId("player-checkbox-3").first().click();
await page.getByTestId("player-checkbox-4").first().click();
await page.getByTestId("points-input-1").fill("99");
await submit(page, "save-revise-button");
await expect(page.getByTestId("revise-button")).toBeVisible();
await expect(
page.getByTestId("player-checkbox-3").first(),
).not.toBeChecked();
await expect(page.getByText("99p")).toBeVisible();
});
test("changes to picked map pool & best of", async ({ page }) => {
const tournamentId = 4;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentAdminPage(tournamentId),
});
await page.getByTestId("edit-event-info-button").click();
await page.getByRole("button", { name: "Clear" }).click();
await page.getByLabel("Template").selectOption("preset:CB");
await submit(page);
await page.getByTestId("brackets-tab").click();
await page.getByTestId("finalize-bracket-button").click();
await page.getByTestId("increase-map-count-button").first().click();
await submit(page, "confirm-finalize-bracket-button");
await page.locator('[data-match-id="1"]').click();
await expect(page.getByTestId("mode-progress-CB")).toHaveCount(5);
});
test("reopens round robin match and changes score", async ({ page }) => {
test.slow();
const tournamentId = 3;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
// needs also to be completed so 9 unlocks
await navigateToMatch(page, 7);
await reportResult({
page,
amountOfMapsToReport: 2,
points: [100, 0],
});
await backToBracket(page);
// set situation where match A is completed and its participants also completed their follow up matches B & C
// and then we go back and change the winner of A
await navigateToMatch(page, 8);
await reportResult({
page,
amountOfMapsToReport: 2,
points: [100, 0],
});
await backToBracket(page);
await navigateToMatch(page, 9);
await reportResult({
page,
amountOfMapsToReport: 2,
points: [100, 0],
});
await backToBracket(page);
await navigateToMatch(page, 10);
await reportResult({
page,
amountOfMapsToReport: 2,
points: [100, 0],
});
await backToBracket(page);
await navigateToMatch(page, 8);
await submit(page, "reopen-match-button");
await submit(page, "undo-score-button");
await reportResult({
page,
amountOfMapsToReport: 2,
points: [0, 100],
winner: 2,
});
});
test("reopening round robin match does not lock already-unlocked matches (issue #2690)", async ({
page,
}) => {
const tournamentId = 3;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
// Use Group B which has 4 teams and 2 matches per round
// Group B Round 1: Match 7 (Whatcha Say vs Come Together), Match 8 (We Are Champions vs Please Mr Postman)
// Group B Round 2: Match 9 (Please Mr Postman vs Come Together), Match 10 (Whatcha Say vs We Are Champions)
// Complete R1 matches in group B (matches 7 and 8) to unlock R2 matches
await navigateToMatch(page, 7);
await reportResult({
page,
amountOfMapsToReport: 2,
points: [100, 0],
});
await backToBracket(page);
await navigateToMatch(page, 8);
await reportResult({
page,
amountOfMapsToReport: 2,
points: [100, 0],
});
await backToBracket(page);
// Match 9 is R2 in group B - should now be unlocked since R1 is complete
// Start it but don't complete it
await navigateToMatch(page, 9);
await reportResult({
page,
amountOfMapsToReport: 1,
points: [100, 0],
});
await backToBracket(page);
// Reopen match 7 (R1 match) - simulating a score misreport correction
await navigateToMatch(page, 7);
await submit(page, "reopen-match-button");
await backToBracket(page);
// Verify the R2 match that was already in progress is still playable
// Before the fix, this would become locked and unplayable
await navigateToMatch(page, 9);
await expect(page.getByText("1-0")).toBeVisible();
await page.getByTestId("actions-tab").click();
await expect(page.getByTestId("winner-radio-1")).toBeVisible();
});
test("locks/unlocks matches & sets match as casted", async ({ page }) => {
test.slow();
const tournamentId = 2;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentPage(tournamentId),
});
await page.getByTestId("admin-tab").click();
await page.getByLabel("Action").selectOption("CHECK_OUT");
for (let id = 103; id < 115; id++) {
await page.getByLabel("Team", { exact: true }).selectOption(String(id));
await submit(page);
}
await page.getByLabel("Twitch accounts").fill("test");
await submit(page, "save-cast-twitch-accounts-button");
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
await page.locator('[data-match-id="1"]').click();
await reportResult({
page,
amountOfMapsToReport: 2,
});
await backToBracket(page);
await page.locator('[data-match-id="3"]').click();
await submit(page, "cast-info-submit-button");
await backToBracket(page);
await page.locator('[data-match-id="2"]').click();
await reportResult({
page,
amountOfMapsToReport: 2,
});
await backToBracket(page);
await expect(page.getByText("🔒 CAST")).toBeVisible();
await page.locator('[data-match-id="3"]').click();
await expect(page.getByText("Match locked to be casted")).toBeVisible();
await submit(page, "cast-info-submit-button");
await expect(page.getByTestId("stage-banner")).toBeVisible();
await page.getByTestId("cast-info-select").selectOption("test");
await submit(page, "cast-info-submit-button");
await backToBracket(page);
await expect(page.getByText("🔴 LIVE")).toBeVisible();
});
test("resets bracket", async ({ page }) => {
const tournamentId = 1;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
await isNotVisible(page.locator('[data-match-id="1"]'));
await page.locator('[data-match-id="2"]').click();
await reportResult({
page,
amountOfMapsToReport: 2,
});
await page.getByTestId("admin-tab").click();
await page
.getByLabel('Type bracket name ("Main bracket") to confirm')
.fill("Main bracket");
await submit(page, "reset-bracket-button");
await page.getByLabel("Action").selectOption("CHECK_IN");
await page.getByLabel("Team", { exact: true }).selectOption("1");
await submit(page);
await page.getByTestId("brackets-tab").click();
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
// bye is gone
await expect(page.locator('[data-match-id="1"]')).toBeVisible();
});
test("user no screen setting affects tournament match", async ({ page }) => {
const tournamentId = 4;
await seed(page);
await impersonate(page);
await navigate({
page,
url: SETTINGS_PAGE,
});
const form = createFormHelpers(page, updateNoScreenSchema);
await form.check("newValue");
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
await page.locator('[data-match-id="1"]').click();
await expect(page.getByTestId("screen-banned")).toBeVisible();
await backToBracket(page);
await page.locator('[data-match-id="2"]').click();
await expect(page.getByTestId("screen-allowed")).toBeVisible();
});
test("hosts a 'play all' round robin stage", async ({ page }) => {
const tournamentId = 4;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("finalize-bracket-button").click();
await page
.getByLabel("Count type", { exact: true })
.selectOption("PLAY_ALL");
await submit(page, "confirm-finalize-bracket-button");
await navigateToMatch(page, 1);
await expect(page.getByText("Play all 3")).toBeVisible();
await reportResult({
page,
amountOfMapsToReport: 3,
points: [100, 0],
winner: 1,
});
});
test("swiss tournament with bracket advancing/unadvancing & dropping out a team", async ({
page,
}) => {
test.slow();
const tournamentId = 5;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("finalize-bracket-button").click();
await submit(page, "confirm-finalize-bracket-button");
// report all group A round 1 scores
for (const id of [1, 2, 3, 4]) {
await page.locator(`[data-match-id="${id}"]`).click();
await reportResult({
page,
amountOfMapsToReport: 2,
});
await backToBracket(page);
}
// test that we can change to view different group
await expect(page.getByTestId("start-round-button")).toBeVisible();
await page.getByTestId("group-B-button").click();
await isNotVisible(page.getByTestId("start-round-button"));
await page.getByTestId("group-A-button").click();
await submit(page, "start-round-button");
await expect(page.locator(`[data-match-id="9"]`)).toBeVisible();
await page.getByTestId("admin-tab").click();
await page.getByLabel("Action").selectOption("DROP_TEAM_OUT");
await page.getByLabel("Team", { exact: true }).selectOption("401");
await submit(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("reset-round-button").click();
await submit(page, "confirm-button");
await submit(page, "start-round-button");
await expect(page.getByTestId("bye-team")).toBeVisible();
});
test("prepares maps (including third place match linking)", async ({
page,
}) => {
const tournamentId = 4;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByRole("tab", { name: "Great White" }).click();
await page.getByTestId("prepare-maps-button").click();
await page.getByLabel("Expected teams").selectOption("8");
await submit(page, "confirm-finalize-bracket-button");
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByRole("tab", { name: "Great White" }).click();
await expect(page.getByTestId("prepared-maps-check-icon")).toBeVisible();
// we did not prepare maps for group stage
await page.getByRole("tab", { name: "Groups stage" }).click();
await isNotVisible(page.getByTestId("prepared-maps-check-icon"));
// should reuse prepared maps from Great White
await page.getByRole("tab", { name: "Hammerhead" }).click();
await expect(page.getByTestId("prepared-maps-check-icon")).toBeVisible();
// finally, test third place match linking
await page.getByRole("tab", { name: "Great White" }).click();
await page.getByTestId("prepare-maps-button").click();
await page.getByTestId("unlink-finals-3rd-place-match-button").click();
await page.getByTestId("increase-map-count-button").last().click();
await submit(page, "confirm-finalize-bracket-button");
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByRole("tab", { name: "Great White" }).click();
await page.getByTestId("prepare-maps-button").click();
// link button should be visible because we unlinked and made finals and third place match maps different earlier
await expect(
page.getByTestId("link-finals-3rd-place-match-button"),
).toBeVisible();
});
for (const pickBan of ["COUNTERPICK", "BAN_2"]) {
test(`ban/pick ${pickBan}`, async ({ page }) => {
const tournamentId = 4;
const matchId = 2;
await seed(page);
await impersonate(page);
await navigate({
page,
url: tournamentBracketsPage({ tournamentId }),
});
await page.getByTestId("finalize-bracket-button").click();
await page.getByLabel("Pick/ban").selectOption(pickBan);
await submit(page, "confirm-finalize-bracket-button");
const teamOneCaptainId = 33;
const teamTwoCaptainId = 29;
if (pickBan === "BAN_2") {
for (const id of [teamTwoCaptainId, teamOneCaptainId]) {
await impersonate(page, id);
await navigate({
page,
url: tournamentMatchPage({ tournamentId, matchId }),
});
await page.getByTestId("actions-tab").click();
await page.getByTestId("pick-ban-button").first().click();
await submit(page);
}
await expect(page.getByTestId("mode-progress-banned")).toHaveCount(2);
}
await impersonate(page, teamOneCaptainId);
await navigate({
page,
url: tournamentMatchPage({ tournamentId, matchId }),
});
await page.getByTestId("actions-tab").click();
await page.getByTestId("winner-radio-2").click();
await page.getByTestId("points-input-2").fill("100");
await submit(page, "report-score-button");
if (pickBan === "COUNTERPICK") {
await page.getByTestId("pick-ban-button").first().click();
await submit(page);
}
await impersonate(page, teamTwoCaptainId);
await navigate({
page,
url: tournamentMatchPage({ tournamentId, matchId }),
});
await page.getByTestId("actions-tab").click();
await page.getByTestId("winner-radio-1").click();
await page.getByTestId("points-input-1").fill("100");
await submit(page, "report-score-button");
if (pickBan === "COUNTERPICK") {
await page.getByTestId("pick-ban-button").first().click();
await submit(page);
await submit(page, "undo-score-button");
await expect(
page.getByText("Please select the winner of this map"),
).toBeVisible();
await page.getByTestId("winner-radio-1").click();
await page.getByTestId("points-input-1").fill("100");
await submit(page, "report-score-button");
await page.getByTestId("pick-ban-button").last().click();
await submit(page);
await expect(
page.getByText("Counterpick", { exact: true }),
).toBeVisible();
await expect(page.getByText("1-1")).toBeVisible();
}
});
}
test("can end set early when past time limit and shows timer on bracket and match page", async ({
page,
}) => {
const tournamentId = 2;
const matchId = 5;
await startBracket(page, tournamentId);
await navigateToMatch(page, matchId);
await page.clock.install({ time: new Date() });
await reportResult({ page, amountOfMapsToReport: 1, winner: 1 });
await expect(page.getByTestId("match-timer")).toBeVisible();
await backToBracket(page);
const bracketMatch = page.locator('[data-match-id="5"]');
await expect(bracketMatch).toBeVisible();
// Verify timer shows on bracket page (timer is a sibling of the match link)
const matchWrapper = bracketMatch.locator("..");
await expect(matchWrapper.getByTestId("bracket-match-timer")).toBeVisible();
// Fast forward time past limit (30 minutes for Bo3 = 26min limit)
await page.clock.fastForward("30:00");
await page.reload();
await navigateToMatch(page, matchId);
await page.getByText("End Set").click();
await page.getByRole("radio", { name: /Random/ }).check();
await submit(page, "end-set-button");
// Verify match ended early
await expect(page.getByText("Match ended early")).toBeVisible();
});
test("dropping team out ends ongoing match early and auto-forfeits losers bracket match", async ({
page,
}) => {
const tournamentId = 2;
await startBracket(page, tournamentId);
// 1) Report partial score on match 5 (winners bracket)
await navigateToMatch(page, 5);
await reportResult({ page, amountOfMapsToReport: 1, winner: 1 });
await backToBracket(page);
// 2) Drop team 102 (one of the teams in match 5) via admin
await navigate({
page,
url: tournamentAdminPage(tournamentId),
});
await page.getByLabel("Action").selectOption("DROP_TEAM_OUT");
await page.getByLabel("Team", { exact: true }).selectOption("102");
await submit(page);
// 3) Verify the ongoing match ended early
await navigate({
page,
url: tournamentMatchPage({ tournamentId, matchId: 5 }),
});
await expect(page.getByText("Match ended early")).toBeVisible();
await expect(page.getByText("dropped out of the tournament")).toBeVisible();
await backToBracket(page);
// 4) Complete the adjacent match (match 6) so its loser goes to losers bracket
await navigateToMatch(page, 6);
await reportResult({ page, amountOfMapsToReport: 2 });
await backToBracket(page);
// 5) The losers bracket match (match 18) should now have teams:
// - Loser of match 5 (team 102, dropped)
// - Loser of match 6
// It should have ended early since team 102 is dropped
await navigateToMatch(page, 18);
await expect(page.getByText("Match ended early")).toBeVisible();
await expect(page.getByText("dropped out of the tournament")).toBeVisible();
});
});