mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-05-09 12:13:10 -05:00
Fix E2E tests
This commit is contained in:
parent
a54030ce8d
commit
daa099a120
|
|
@ -82,10 +82,10 @@ pnpm exec playwright show-trace test-results/<test-folder>/trace.zip
|
|||
|
||||
## Test pattern reference
|
||||
|
||||
Every test follows this pattern — use these imports from `~/utils/playwright`, NOT raw Playwright APIs:
|
||||
Every test follows this pattern — use these imports from `./helpers/playwright`, NOT raw Playwright APIs:
|
||||
|
||||
```typescript
|
||||
import { expect, impersonate, navigate, seed, test } from "~/utils/playwright";
|
||||
import { expect, impersonate, navigate, seed, test } from "./helpers/playwright";
|
||||
|
||||
test.describe("Feature", () => {
|
||||
test("does something", async ({ page }) => {
|
||||
|
|
@ -104,7 +104,7 @@ Key rules:
|
|||
- Use `seed(page, variation?)` to reset the database. Available variations: DEFAULT, NO_TOURNAMENT_TEAMS, REG_OPEN, SMALL_SOS, NZAP_IN_TEAM, NO_SCRIMS, NO_SQ_GROUPS
|
||||
- Use `impersonate(page, userId?)` to authenticate. Default is admin (ADMIN_ID)
|
||||
- Avoid `page.waitForTimeout` — use assertions or `waitFor` patterns instead
|
||||
- Import `test` from `~/utils/playwright` (not from `@playwright/test`) — it includes worker port fixtures
|
||||
- Import `test` from `./helpers/playwright` (not from `@playwright/test`) — it includes worker port fixtures
|
||||
|
||||
## Environment variables
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ export interface SendouButtonProps
|
|||
shape?: "circle" | "square";
|
||||
icon?: JSX.Element;
|
||||
children?: React.ReactNode;
|
||||
testId?: string;
|
||||
}
|
||||
|
||||
export function SendouButton({
|
||||
|
|
@ -37,10 +38,12 @@ export function SendouButton({
|
|||
shape,
|
||||
className,
|
||||
icon,
|
||||
testId,
|
||||
...rest
|
||||
}: SendouButtonProps) {
|
||||
return (
|
||||
<ReactAriaButton
|
||||
data-testid={testId}
|
||||
{...rest}
|
||||
className={buttonClassName({ className, variant, size, shape })}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ export function MatchActionPickBanTab({
|
|||
if (!selected) return;
|
||||
onSubmit?.({ type, map: selected });
|
||||
}}
|
||||
testId="pick-ban-submit-button"
|
||||
>
|
||||
{t("common:actions.submit")}
|
||||
</SendouButton>
|
||||
|
|
@ -294,6 +295,7 @@ function StageTile({
|
|||
}}
|
||||
onClick={onSelect}
|
||||
disabled={disabled}
|
||||
data-testid="pick-ban-button"
|
||||
/>
|
||||
{isSelected ? (
|
||||
type === "PICK" ? (
|
||||
|
|
@ -353,6 +355,7 @@ function ModeTile({
|
|||
})}
|
||||
onClick={onSelect}
|
||||
disabled={disabled}
|
||||
data-testid="pick-ban-button"
|
||||
>
|
||||
<ModeImage mode={option.mode!} size={48} />
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ export function MatchActionTab({
|
|||
isOwnTeam={teams[0].id === ownTeamId}
|
||||
hideLabel={ownTeamId == null}
|
||||
className={styles.alpha}
|
||||
testId="winner-radio-1"
|
||||
/>
|
||||
<StageImage
|
||||
stageId={stageId}
|
||||
|
|
@ -150,6 +151,7 @@ export function MatchActionTab({
|
|||
isOwnTeam={teams[1].id === ownTeamId}
|
||||
hideLabel={ownTeamId == null}
|
||||
className={clsx(styles.bravo)}
|
||||
testId="winner-radio-2"
|
||||
/>
|
||||
</RadioGroup>
|
||||
|
||||
|
|
@ -160,6 +162,7 @@ export function MatchActionTab({
|
|||
type="checkbox"
|
||||
checked={isKo}
|
||||
onChange={(e) => setIsKo(e.target.checked)}
|
||||
data-testid="ko-checkbox"
|
||||
/>
|
||||
{t("q:match.action.ko")}
|
||||
</label>
|
||||
|
|
@ -178,6 +181,7 @@ export function MatchActionTab({
|
|||
}
|
||||
}}
|
||||
className={styles.submit}
|
||||
testId="report-score-button"
|
||||
>
|
||||
{t("common:actions.submit")}
|
||||
</SendouButton>
|
||||
|
|
@ -248,6 +252,7 @@ function SetEndingConfirmation({
|
|||
variant="primary"
|
||||
isDisabled={isSubmitting}
|
||||
onPress={onConfirm}
|
||||
testId="confirm-set-end-button"
|
||||
>
|
||||
{t("common:actions.confirm")}
|
||||
</SendouButton>
|
||||
|
|
@ -264,11 +269,13 @@ function TeamRadioOption({
|
|||
isOwnTeam,
|
||||
hideLabel,
|
||||
className,
|
||||
testId,
|
||||
}: {
|
||||
team: ActionTabTeam;
|
||||
isOwnTeam: boolean;
|
||||
hideLabel?: boolean;
|
||||
className?: string;
|
||||
testId?: string;
|
||||
}) {
|
||||
const { t } = useTranslation(["q"]);
|
||||
|
||||
|
|
@ -279,6 +286,7 @@ function TeamRadioOption({
|
|||
value={String(team.id)}
|
||||
aria-label={team.name}
|
||||
className={clsx(styles.teamRadioContainer, className)}
|
||||
data-testid={testId}
|
||||
>
|
||||
{({ isSelected, isFocusVisible }) => (
|
||||
<span
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ export function MatchBanner({
|
|||
style={{
|
||||
"--stage-img": `url(${stageBannerImageUrl(stageId)})`,
|
||||
}}
|
||||
data-testid="stage-banner"
|
||||
>
|
||||
<div className={clsx(styles.map, styles.thickText)}>
|
||||
<ModeImage mode={mode} size={24} />
|
||||
|
|
@ -73,6 +74,7 @@ interface IconBannerProps {
|
|||
subtitle?: string;
|
||||
screenLegal?: boolean;
|
||||
topRight?: React.ReactNode;
|
||||
testId?: string;
|
||||
}
|
||||
|
||||
export function IconBanner({
|
||||
|
|
@ -81,9 +83,10 @@ export function IconBanner({
|
|||
subtitle,
|
||||
screenLegal,
|
||||
topRight,
|
||||
testId,
|
||||
}: IconBannerProps) {
|
||||
return (
|
||||
<div className={styles.iconBanner}>
|
||||
<div className={styles.iconBanner} data-testid={testId}>
|
||||
{icon}
|
||||
<div className={styles.iconBannerHeader}>{header}</div>
|
||||
{subtitle ? (
|
||||
|
|
@ -109,7 +112,11 @@ function ScreenNotice({ screenLegal }: { screenLegal: boolean }) {
|
|||
return (
|
||||
<SendouPopover
|
||||
trigger={
|
||||
<SendouButton variant="minimal" className={styles.notice}>
|
||||
<SendouButton
|
||||
variant="minimal"
|
||||
className={styles.notice}
|
||||
testId={screenLegal ? "screen-allowed" : "screen-banned"}
|
||||
>
|
||||
<Icon
|
||||
size={imgSize}
|
||||
className={screenLegal ? styles.legalIcon : styles.illegalIcon}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,10 @@ function ModeProgress({ games }: Pick<MatchBannerBottomRowProps, "games">) {
|
|||
if (allSameMode) {
|
||||
return (
|
||||
<div className={styles.modeProgress}>
|
||||
<div className={styles.mode}>
|
||||
<div
|
||||
className={styles.mode}
|
||||
data-testid={`mode-progress-${knownModes[0]}`}
|
||||
>
|
||||
<ModeImage mode={knownModes[0]} size={16} />
|
||||
</div>
|
||||
<div className={styles.modeCount}>×{games.length}</div>
|
||||
|
|
@ -49,11 +52,19 @@ function ModeProgress({ games }: Pick<MatchBannerBottomRowProps, "games">) {
|
|||
<div className={styles.modeProgress}>
|
||||
{games.map((game, i) =>
|
||||
game.mode ? (
|
||||
<div key={i} className={styles.mode}>
|
||||
<div
|
||||
key={i}
|
||||
className={styles.mode}
|
||||
data-testid={`mode-progress-${game.mode}`}
|
||||
>
|
||||
<ModeImage mode={game.mode} size={16} />
|
||||
</div>
|
||||
) : (
|
||||
<div key={i} className={clsx(styles.mode, styles.modePlaceholder)}>
|
||||
<div
|
||||
key={i}
|
||||
className={clsx(styles.mode, styles.modePlaceholder)}
|
||||
data-testid="mode-progress-banned"
|
||||
>
|
||||
<MousePointerClick size={16} />
|
||||
</div>
|
||||
),
|
||||
|
|
|
|||
|
|
@ -33,7 +33,10 @@ function Score({ score }: { score: MatchBannerTopRowProps["score"] }) {
|
|||
<div>
|
||||
{score.alpha}-{score.bravo}
|
||||
</div>
|
||||
<div className={styles.sub}>
|
||||
<div
|
||||
className={styles.sub}
|
||||
data-testid={score.isFinal ? "match-final" : undefined}
|
||||
>
|
||||
{score.isFinal
|
||||
? t("q:match.banner.final")
|
||||
: score.bestOf
|
||||
|
|
@ -73,7 +76,7 @@ function Timer({
|
|||
: minuteFormatter.format(minutes);
|
||||
|
||||
return (
|
||||
<div className={styles.values}>
|
||||
<div className={styles.values} data-testid="match-timer">
|
||||
<time dateTime={dateTime(time.currentMinutes)} className={styles.sub}>
|
||||
{displayValue(time.currentMinutes)}
|
||||
</time>
|
||||
|
|
|
|||
|
|
@ -86,7 +86,11 @@ export function MatchJoinTab({
|
|||
<InfoWithHeader header={t("q:match.hostedBy")} value={hostedBy} />
|
||||
) : null}
|
||||
<InfoWithHeader header={t("q:match.pool")} value={pool} />
|
||||
<InfoWithHeader header={t("q:match.password.short")} value={pass} />
|
||||
<InfoWithHeader
|
||||
header={t("q:match.password.short")}
|
||||
value={pass}
|
||||
testId="room-pass"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -122,11 +126,21 @@ function StaleRoomPrompt({
|
|||
);
|
||||
}
|
||||
|
||||
function InfoWithHeader({ header, value }: { header: string; value: string }) {
|
||||
function InfoWithHeader({
|
||||
header,
|
||||
value,
|
||||
testId,
|
||||
}: {
|
||||
header: string;
|
||||
value: string;
|
||||
testId?: string;
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.infoHeader}>{header}</div>
|
||||
<div className={styles.infoValue}>{value}</div>
|
||||
<div className={styles.infoValue} data-testid={testId}>
|
||||
{value}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,13 +138,14 @@ function TeamRoster({
|
|||
{team.members.length > 0 ? (
|
||||
<ul className={styles.rosterMembers}>
|
||||
{isEditing
|
||||
? team.members.map((member) => (
|
||||
? team.members.map((member, index) => (
|
||||
<li key={member.id}>
|
||||
<label className="stack horizontal sm items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedMemberIds.includes(member.id)}
|
||||
onChange={() => handleToggleMember(member.id)}
|
||||
data-testid={`player-checkbox-${side}-${index}`}
|
||||
/>
|
||||
<Avatar user={member} size="xxs" />
|
||||
<span>{member.username}</span>
|
||||
|
|
@ -188,6 +189,7 @@ function TeamRoster({
|
|||
isSubmitting || selectedMemberIds.length !== minMembersPerTeam
|
||||
}
|
||||
onPress={handleSubmit}
|
||||
testId={`save-active-roster-button-${side}`}
|
||||
>
|
||||
{t("common:actions.submit")}
|
||||
</SendouButton>
|
||||
|
|
@ -210,6 +212,7 @@ function TeamRoster({
|
|||
setSelectedMemberIds(activeMembers.map((m) => m.id));
|
||||
setIsEditing(true);
|
||||
}}
|
||||
testId={`edit-active-roster-button-${side}`}
|
||||
>
|
||||
{t("common:actions.edit")}
|
||||
</SendouButton>
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ export function TournamentMatchActionTab({
|
|||
{ method: "post" },
|
||||
);
|
||||
}}
|
||||
testId="undo-score-button"
|
||||
>
|
||||
{t("q:match.undoReport")}
|
||||
</SendouButton>
|
||||
|
|
|
|||
|
|
@ -512,7 +512,7 @@ function EditReportedScoreForm({
|
|||
<fieldset key={team.id} className={styles.teamFieldset}>
|
||||
<legend>{team.name}</legend>
|
||||
<div className="stack sm">
|
||||
{team.members.map((member) => {
|
||||
{team.members.map((member, memberIdx) => {
|
||||
const checked = checkedPlayers[teamIdx as 0 | 1].includes(
|
||||
member.userId,
|
||||
);
|
||||
|
|
@ -527,6 +527,7 @@ function EditReportedScoreForm({
|
|||
onChange={() =>
|
||||
togglePlayer(teamIdx as 0 | 1, member.userId)
|
||||
}
|
||||
data-testid={`edit-result-player-checkbox-${teamIdx === 0 ? "alpha" : "bravo"}-${memberIdx}`}
|
||||
/>
|
||||
<span>{member.username}</span>
|
||||
</label>
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ export function TournamentMatchBanner({
|
|||
teams: teamsMissingActiveRoster.join(" & "),
|
||||
})}
|
||||
screenLegal={screenLegal}
|
||||
testId="active-roster-needed-text"
|
||||
/>
|
||||
) : data.matchIsOver ? (
|
||||
<MultiMatchBanner
|
||||
|
|
|
|||
|
|
@ -41,7 +41,16 @@ export function TournamentMatchTabs({
|
|||
turnOfResult,
|
||||
isPickBanStep,
|
||||
} = useMatch();
|
||||
if (!teamOne || !teamTwo) return null;
|
||||
|
||||
// Preview matches (participants TBD) only render the admin tab so organizers
|
||||
// can pre-cast or pre-prepare; everything else needs both teams.
|
||||
if (!teamOne || !teamTwo) {
|
||||
return tabs.includes(TAB_KEYS.ADMIN) ? (
|
||||
<MatchTabs tabs={[TAB_KEYS.ADMIN]}>
|
||||
<TournamentMatchAdminTab data={data} />
|
||||
</MatchTabs>
|
||||
) : null;
|
||||
}
|
||||
|
||||
const opponentOneId = teamOne.id;
|
||||
const opponentTwoId = teamTwo.id;
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ export const loader = async ({ params }: LoaderFunctionArgs) => {
|
|||
const isParticipant = match.players.some((p) => p.id === user?.id);
|
||||
const canJoin =
|
||||
!matchIsOver &&
|
||||
isParticipant &&
|
||||
(isParticipant || tournament.isOrganizerOrStreamer(user)) &&
|
||||
!isLeagueRoundLocked(tournament, match.roundId);
|
||||
|
||||
const [roomLinks, anyUserPrefersNoSplatnet] = canJoin
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export const handle: SendouRouteHandle = {
|
|||
i18n: ["q"],
|
||||
};
|
||||
|
||||
// xxx: check page when both teams are not resolved yet
|
||||
export default function TournamentMatchPage() {
|
||||
const data = useLoaderData<typeof loader>();
|
||||
|
||||
|
|
|
|||
|
|
@ -574,7 +574,7 @@ Run `pnpm run i18n:sync` after adding English translations to initialize other l
|
|||
Use `createFormHelpers` for type-safe form interactions:
|
||||
|
||||
```ts
|
||||
import { createFormHelpers } from "~/utils/playwright-form";
|
||||
import { createFormHelpers } from "./helpers/playwright-form";
|
||||
import { myFormSchema } from "~/features/my/my-schemas";
|
||||
|
||||
test("fills and submits form", async ({ page }) => {
|
||||
|
|
@ -628,7 +628,7 @@ import {
|
|||
selectStage,
|
||||
selectWeapon,
|
||||
selectUser,
|
||||
} from "~/utils/playwright";
|
||||
} from "./helpers/playwright";
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
|
@ -717,9 +717,9 @@ export const action = async ({ request }: ActionFunctionArgs) => {
|
|||
### E2E Test (`feature.spec.ts`)
|
||||
|
||||
```ts
|
||||
import { createFormHelpers } from "~/utils/playwright-form";
|
||||
import { createFormHelpers } from "./helpers/playwright-form";
|
||||
import { createItemSchema } from "~/features/item/feature-schemas";
|
||||
import { test, navigate, impersonate, seed } from "~/utils/playwright";
|
||||
import { test, navigate, impersonate, seed } from "./helpers/playwright";
|
||||
|
||||
test("creates new item", async ({ page }) => {
|
||||
await seed(page);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { ANALYZER_URL } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -6,8 +7,7 @@ import {
|
|||
seed,
|
||||
selectWeapon,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import { ANALYZER_URL } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
test.describe("Build Analyzer", () => {
|
||||
test("analyzes a build and links to new build page with same abilities", async ({
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
import type { Page } from "@playwright/test";
|
||||
import { ORG_ADMIN_TEST_ID } from "~/db/seed/constants";
|
||||
import { ADMIN_ID } from "~/features/admin/admin-constants";
|
||||
import { expect, impersonate, navigate, seed, test } from "~/utils/playwright";
|
||||
import { tournamentTeamPage } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
navigate,
|
||||
seed,
|
||||
test,
|
||||
} from "./helpers/playwright";
|
||||
|
||||
const ITZ_TOURNAMENT_ID = 2;
|
||||
const ITZ_TEAM_ID = 101;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { expect, impersonate, navigate, seed, test } from "~/utils/playwright";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
navigate,
|
||||
seed,
|
||||
test,
|
||||
} from "./helpers/playwright";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { ADMIN_ID } from "~/features/admin/admin-constants";
|
||||
import { associationsPage, scrimsPage } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -8,8 +9,7 @@ import {
|
|||
seed,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import { associationsPage, scrimsPage } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
test.describe("Associations", () => {
|
||||
test("creates a new association", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { badgePage } from "~/utils/urls";
|
||||
import { NZAP_TEST_ID } from "../app/db/seed/constants";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -5,9 +7,7 @@ import {
|
|||
seed,
|
||||
selectUser,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import { badgePage } from "~/utils/urls";
|
||||
import { NZAP_TEST_ID } from "../app/db/seed/constants";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
test.describe("Badges", () => {
|
||||
test("adds a badge owner sending a notification", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { Page } from "@playwright/test";
|
||||
import { NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { ADMIN_ID } from "~/features/admin/admin-constants";
|
||||
import { ADMIN_PAGE, SUSPENDED_PAGE } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -8,8 +9,7 @@ import {
|
|||
seed,
|
||||
test,
|
||||
waitForPOSTResponse,
|
||||
} from "~/utils/playwright";
|
||||
import { ADMIN_PAGE, SUSPENDED_PAGE } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
async function banUser(
|
||||
page: Page,
|
||||
|
|
|
|||
|
|
@ -4,9 +4,15 @@ import type { GearType } from "~/db/tables";
|
|||
import { ADMIN_DISCORD_ID } from "~/features/admin/admin-constants";
|
||||
import { newBuildBaseSchema } from "~/features/user-page/user-page-schemas";
|
||||
import invariant from "~/utils/invariant";
|
||||
import { expect, impersonate, navigate, seed, test } from "~/utils/playwright";
|
||||
import { createFormHelpers } from "~/utils/playwright-form";
|
||||
import { BUILDS_PAGE, userBuildsPage, userNewBuildPage } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
navigate,
|
||||
seed,
|
||||
test,
|
||||
} from "./helpers/playwright";
|
||||
import { createFormHelpers } from "./helpers/playwright-form";
|
||||
|
||||
test.describe("Builds", () => {
|
||||
test("adds a build", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { calendarPage } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
expectIsHydrated,
|
||||
|
|
@ -7,8 +8,7 @@ import {
|
|||
navigate,
|
||||
seed,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import { calendarPage } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
const SENDOU_INK_TOURNAMENTS_COUNT = 6;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, navigate, test } from "~/utils/playwright";
|
||||
import { COMP_ANALYZER_URL } from "~/utils/urls";
|
||||
import { expect, navigate, test } from "./helpers/playwright";
|
||||
|
||||
test.describe("Composition Analyzer", () => {
|
||||
test("weapon selection, removal, and URL persistence", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import { expect, impersonate, navigate, seed, test } from "~/utils/playwright";
|
||||
import { EVENTS_PAGE } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
navigate,
|
||||
seed,
|
||||
test,
|
||||
} from "./helpers/playwright";
|
||||
|
||||
test.describe("Events", () => {
|
||||
test("filters between tabs and navigates to an event", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { FRIENDS_PAGE } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -8,8 +9,7 @@ import {
|
|||
submit,
|
||||
test,
|
||||
waitForPOSTResponse,
|
||||
} from "~/utils/playwright";
|
||||
import { FRIENDS_PAGE } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
test.describe("Friends", () => {
|
||||
test("send friend request, accept it, then delete friend", async ({
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
import { expect, impersonate, navigate, seed, test } from "~/utils/playwright";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
navigate,
|
||||
seed,
|
||||
test,
|
||||
} from "./helpers/playwright";
|
||||
|
||||
test.describe("Global search", () => {
|
||||
test("searches for users and organizations", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { type ChildProcess, execSync, spawn } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import type { FullConfig } from "@playwright/test";
|
||||
import { E2E_BASE_PORT } from "~/utils/playwright";
|
||||
import { E2E_BASE_PORT } from "./helpers/playwright";
|
||||
|
||||
const WORKER_COUNT = Number(process.env.E2E_WORKERS) || 4;
|
||||
const DEBUG = process.env.E2E_DEBUG === "true";
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
import dotenv from "dotenv";
|
||||
import { ADMIN_ID } from "~/features/admin/admin-constants";
|
||||
import type { SeedVariation } from "~/features/api-private/routes/seed";
|
||||
import { tournamentBracketsPage } from "./urls";
|
||||
import { tournamentBracketsPage } from "~/utils/urls";
|
||||
|
||||
dotenv.config();
|
||||
export const E2E_BASE_PORT = Number(process.env.PORT || 5173) + 500;
|
||||
108
e2e/helpers/tournament-match.ts
Normal file
108
e2e/helpers/tournament-match.ts
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import type { Page } from "@playwright/test";
|
||||
import { expect, submit, waitForPOSTResponse } from "./playwright";
|
||||
|
||||
/**
|
||||
* Helpers for interacting with the tournament match page in e2e tests.
|
||||
*
|
||||
* The match page splits its UI into URL-driven tabs (rosters/action/admin/etc.)
|
||||
* — these helpers handle the navigation so individual tests can stay focused on
|
||||
* the assertion they care about.
|
||||
*/
|
||||
|
||||
type Side = 1 | 2;
|
||||
|
||||
export const navigateToMatch = async (page: Page, matchId: number) => {
|
||||
await expect(async () => {
|
||||
await page.locator(`[data-match-id="${matchId}"]`).click();
|
||||
await expect(page.getByTestId("back-to-bracket-button")).toBeVisible();
|
||||
}).toPass();
|
||||
};
|
||||
|
||||
export const backToBracket = async (page: Page) => {
|
||||
await expect(async () => {
|
||||
await page.getByTestId("back-to-bracket-button").click();
|
||||
await expect(page.getByTestId("brackets-viewer")).toBeVisible();
|
||||
}).toPass();
|
||||
};
|
||||
|
||||
export const expectScore = (page: Page, score: [number, number]) =>
|
||||
expect(page.getByText(score.join("-")).first()).toBeVisible();
|
||||
|
||||
const TAB_LABELS = {
|
||||
action: "Action",
|
||||
admin: "Admin",
|
||||
result: "Result",
|
||||
rosters: "Rosters",
|
||||
join: "Join",
|
||||
} as const;
|
||||
|
||||
export const goToTab = async (
|
||||
page: Page,
|
||||
tab: "action" | "admin" | "result" | "rosters" | "join",
|
||||
) => {
|
||||
// When teams have more members than the minimum, the action tab is hidden
|
||||
// until each team's active roster is locked in via the rosters tab. Auto-set
|
||||
// any roster that's still in default-editing mode so callers can stay focused
|
||||
// on the flow they actually care about.
|
||||
if (tab === "action") {
|
||||
await ensureActiveRostersSet(page);
|
||||
}
|
||||
await page.getByRole("tab", { name: TAB_LABELS[tab] }).click();
|
||||
};
|
||||
|
||||
const ensureActiveRostersSet = async (page: Page) => {
|
||||
const sides = ["alpha", "bravo"] as const;
|
||||
|
||||
// If the action tab is already there, no rosters need setting.
|
||||
if ((await page.getByRole("tab", { name: TAB_LABELS.action }).count()) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Editing inputs only render on the rosters tab — switch there.
|
||||
await page.getByRole("tab", { name: TAB_LABELS.rosters }).click();
|
||||
// Wait for the rosters panel to be ready before probing for editing UI.
|
||||
await expect(page.getByRole("tabpanel", { name: "Rosters" })).toBeVisible();
|
||||
|
||||
for (const side of sides) {
|
||||
const submitButton = page.getByTestId(`save-active-roster-button-${side}`);
|
||||
if ((await submitButton.count()) === 0) continue;
|
||||
|
||||
// Default-editing renders all members unchecked; pick the first 4.
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const checkbox = page.getByTestId(`player-checkbox-${side}-${i}`);
|
||||
if (!(await checkbox.isChecked())) await checkbox.click();
|
||||
}
|
||||
await submit(page, `save-active-roster-button-${side}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sweeps `mapsToReport` maps in a row, all won by `winner`. By default the
|
||||
* last map ends the set (the typical case — full Bo3/Bo5 sweep), and the
|
||||
* helper goes through the confirmation screen for that map. Pass
|
||||
* `setEnds: false` when reporting a partial set (e.g. only 1 of a Bo3).
|
||||
*/
|
||||
export const reportResult = async (
|
||||
page: Page,
|
||||
{
|
||||
mapsToReport,
|
||||
winner = 1,
|
||||
setEnds = true,
|
||||
}: { mapsToReport: number; winner?: Side; setEnds?: boolean },
|
||||
) => {
|
||||
for (let i = 0; i < mapsToReport; i++) {
|
||||
const isFinal = setEnds && i === mapsToReport - 1;
|
||||
await page.getByTestId(`winner-radio-${winner}`).click();
|
||||
if (isFinal) {
|
||||
await page.getByTestId("report-score-button").click();
|
||||
await submit(page, "confirm-set-end-button");
|
||||
} else {
|
||||
await submit(page, "report-score-button");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const undoLastReport = (page: Page) =>
|
||||
waitForPOSTResponse(page, async () => {
|
||||
await page.getByTestId("undo-score-button").click();
|
||||
});
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import { LFG_PAGE } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -5,8 +6,7 @@ import {
|
|||
seed,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import { LFG_PAGE } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
test.describe("LFG", () => {
|
||||
test("adds a new lfg post", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
import { expect, impersonate, navigate, seed, test } from "~/utils/playwright";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
navigate,
|
||||
seed,
|
||||
test,
|
||||
} from "./helpers/playwright";
|
||||
|
||||
test.describe("Navigation", () => {
|
||||
test("desktop navigation", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, navigate, selectWeapon, test } from "~/utils/playwright";
|
||||
import { OBJECT_DAMAGE_CALCULATOR_URL } from "~/utils/urls";
|
||||
import { expect, navigate, selectWeapon, test } from "./helpers/playwright";
|
||||
|
||||
test.describe("Object Damage Calculator", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@ import {
|
|||
newOrganizationSchema,
|
||||
updateIsEstablishedSchema,
|
||||
} from "~/features/tournament-organization/tournament-organization-schemas";
|
||||
import {
|
||||
TOURNAMENT_NEW_PAGE,
|
||||
tournamentOrganizationPage,
|
||||
tournamentPage,
|
||||
} from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -14,13 +19,8 @@ import {
|
|||
submit,
|
||||
test,
|
||||
waitForPOSTResponse,
|
||||
} from "~/utils/playwright";
|
||||
import { createFormHelpers } from "~/utils/playwright-form";
|
||||
import {
|
||||
TOURNAMENT_NEW_PAGE,
|
||||
tournamentOrganizationPage,
|
||||
tournamentPage,
|
||||
} from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
import { createFormHelpers } from "./helpers/playwright-form";
|
||||
|
||||
const url = tournamentOrganizationPage({
|
||||
organizationSlug: "sendouink",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { ADMIN_ID } from "~/features/admin/admin-constants";
|
||||
import { scrimsNewFormSchema } from "~/features/scrims/scrims-schemas";
|
||||
import { newScrimPostPage, scrimsPage } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -9,9 +10,8 @@ import {
|
|||
selectUser,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import { createFormHelpers } from "~/utils/playwright-form";
|
||||
import { newScrimPostPage, scrimsPage } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
import { createFormHelpers } from "./helpers/playwright-form";
|
||||
|
||||
test.describe("Scrims", () => {
|
||||
test("creates a new scrim & deletes it", async ({ page }) => {
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,6 +1,11 @@
|
|||
import type { Page } from "@playwright/test";
|
||||
import { NZAP_TEST_ID, STAFF_TEST_ID } from "~/db/seed/constants";
|
||||
import { ADMIN_ID } from "~/features/admin/admin-constants";
|
||||
import {
|
||||
SENDOUQ_LOOKING_PAGE,
|
||||
SENDOUQ_PAGE,
|
||||
sendouQMatchPage,
|
||||
} from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -9,12 +14,9 @@ import {
|
|||
selectWeapon,
|
||||
test,
|
||||
waitForPOSTResponse,
|
||||
} from "~/utils/playwright";
|
||||
import {
|
||||
SENDOUQ_LOOKING_PAGE,
|
||||
SENDOUQ_PAGE,
|
||||
sendouQMatchPage,
|
||||
} from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
// xxx: fix failing tests
|
||||
|
||||
/**
|
||||
* Tests for the SendouQ match page (`/q/match/$id`).
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import { NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { ADMIN_ID } from "~/features/admin/admin-constants";
|
||||
import {
|
||||
SENDOUQ_LOOKING_PAGE,
|
||||
SENDOUQ_PAGE,
|
||||
SENDOUQ_PREPARING_PAGE,
|
||||
sendouQInviteLink,
|
||||
} from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -7,13 +13,7 @@ import {
|
|||
seed,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import {
|
||||
SENDOUQ_LOOKING_PAGE,
|
||||
SENDOUQ_PAGE,
|
||||
SENDOUQ_PREPARING_PAGE,
|
||||
sendouQInviteLink,
|
||||
} from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
test.describe("SendouQ", () => {
|
||||
test("Group preparation flow - add friends and users via invite link", async ({
|
||||
|
|
|
|||
|
|
@ -4,6 +4,12 @@ import {
|
|||
disableBuildAbilitySortingSchema,
|
||||
spoilerFreeModeSchema,
|
||||
} from "~/features/settings/settings-schemas";
|
||||
import {
|
||||
CALENDAR_PAGE,
|
||||
SETTINGS_PAGE,
|
||||
tournamentBracketsPage,
|
||||
tournamentResultsPage,
|
||||
} from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -12,14 +18,8 @@ import {
|
|||
seed,
|
||||
test,
|
||||
waitForPOSTResponse,
|
||||
} from "~/utils/playwright";
|
||||
import { createFormHelpers } from "~/utils/playwright-form";
|
||||
import {
|
||||
CALENDAR_PAGE,
|
||||
SETTINGS_PAGE,
|
||||
tournamentBracketsPage,
|
||||
tournamentResultsPage,
|
||||
} from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
import { createFormHelpers } from "./helpers/playwright-form";
|
||||
|
||||
test.describe("Settings", () => {
|
||||
test("updates 'disableBuildAbilitySorting'", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { ADMIN_DISCORD_ID, ADMIN_ID } from "~/features/admin/admin-constants";
|
||||
import { createTeamSchema } from "~/features/team/team-schemas";
|
||||
import { editTeamPage, teamPage, userPage } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -10,9 +11,8 @@ import {
|
|||
seed,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import { createFormHelpers } from "~/utils/playwright-form";
|
||||
import { editTeamPage, teamPage, userPage } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
import { createFormHelpers } from "./helpers/playwright-form";
|
||||
|
||||
test.describe("New team creation", () => {
|
||||
test("creates new team", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, navigate, test } from "~/utils/playwright";
|
||||
import { TIER_LIST_MAKER_URL } from "~/utils/urls";
|
||||
import { expect, navigate, test } from "./helpers/playwright";
|
||||
|
||||
test.describe("Tier List Maker", () => {
|
||||
test("toggles work, items can be dragged, and state persists after reload", async ({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { expect, navigate, seed, test } from "~/utils/playwright";
|
||||
import { topSearchPage, userPage } from "~/utils/urls";
|
||||
import { expect, navigate, seed, test } from "./helpers/playwright";
|
||||
|
||||
test.describe("Top search", () => {
|
||||
test("views different x rank placements", async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { tournamentBracketsPage } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -5,8 +6,7 @@ import {
|
|||
seed,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import { tournamentBracketsPage } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
const AB_RR_TOURNAMENT_ID = 8;
|
||||
const TEAMS_PER_DIVISION = 6;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,16 @@
|
|||
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 {
|
||||
NOTIFICATIONS_URL,
|
||||
SETTINGS_PAGE,
|
||||
tournamentAdminPage,
|
||||
tournamentBracketsPage,
|
||||
tournamentMatchPage,
|
||||
tournamentPage,
|
||||
tournamentTeamsPage,
|
||||
userResultsPage,
|
||||
} from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -13,137 +22,16 @@ import {
|
|||
submit,
|
||||
test,
|
||||
waitForPOSTResponse,
|
||||
} from "~/utils/playwright";
|
||||
import { createFormHelpers } from "~/utils/playwright-form";
|
||||
} from "./helpers/playwright";
|
||||
import { createFormHelpers } from "./helpers/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();
|
||||
backToBracket,
|
||||
expectScore,
|
||||
goToTab,
|
||||
navigateToMatch,
|
||||
reportResult,
|
||||
undoLastReport,
|
||||
} from "./helpers/tournament-match";
|
||||
|
||||
test.describe("Tournament bracket", () => {
|
||||
test("sets active roster as regular member", async ({ page }) => {
|
||||
|
|
@ -161,35 +49,32 @@ test.describe("Tournament bracket", () => {
|
|||
|
||||
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");
|
||||
// Team 10 (5 players) is opponentTwo in match 2 → bravo side.
|
||||
// The roster tab opens in editing mode by default when active roster is missing.
|
||||
await goToTab(page, "rosters");
|
||||
await page.getByTestId("player-checkbox-bravo-0").click();
|
||||
await page.getByTestId("player-checkbox-bravo-1").click();
|
||||
await page.getByTestId("player-checkbox-bravo-2").click();
|
||||
await page.getByTestId("player-checkbox-bravo-3").click();
|
||||
await submit(page, "save-active-roster-button-bravo");
|
||||
|
||||
// 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 goToTab(page, "rosters");
|
||||
await page.getByTestId("edit-active-roster-button-bravo").click();
|
||||
// Swap player 3 out for player 4
|
||||
await page.getByTestId("player-checkbox-bravo-3").click();
|
||||
await page.getByTestId("player-checkbox-bravo-4").click();
|
||||
await submit(page, "save-active-roster-button-bravo");
|
||||
|
||||
await expect(page.getByTestId("edit-active-roster-button")).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId("player-checkbox-3").last(),
|
||||
).not.toBeChecked();
|
||||
page.getByTestId("edit-active-roster-button-bravo"),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
// 1) Report winner of N-ZAP's first match
|
||||
|
|
@ -212,7 +97,8 @@ test.describe("Tournament bracket", () => {
|
|||
|
||||
// 1)
|
||||
await navigateToMatch(page, 5);
|
||||
await reportResult({ page, amountOfMapsToReport: 2 });
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
|
||||
// 2)
|
||||
|
|
@ -222,30 +108,32 @@ test.describe("Tournament bracket", () => {
|
|||
url: tournamentBracketsPage({ tournamentId }),
|
||||
});
|
||||
await navigateToMatch(page, 6);
|
||||
await reportResult({ page, amountOfMapsToReport: 2 });
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
|
||||
// 3)
|
||||
await navigateToMatch(page, 18);
|
||||
await reportResult({
|
||||
page,
|
||||
amountOfMapsToReport: 1,
|
||||
});
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 1, setEnds: false });
|
||||
await backToBracket(page);
|
||||
|
||||
// 4)
|
||||
await navigateToMatch(page, 5);
|
||||
await goToTab(page, "admin");
|
||||
await isNotVisible(page.getByTestId("reopen-match-button"));
|
||||
await backToBracket(page);
|
||||
|
||||
// 5)
|
||||
await navigateToMatch(page, 18);
|
||||
await submit(page, "undo-score-button");
|
||||
await goToTab(page, "action");
|
||||
await undoLastReport(page);
|
||||
await expectScore(page, [0, 0]);
|
||||
await backToBracket(page);
|
||||
|
||||
// 6)
|
||||
await navigateToMatch(page, 5);
|
||||
await goToTab(page, "admin");
|
||||
await submit(page, "reopen-match-button");
|
||||
await expectScore(page, [1, 0]);
|
||||
|
||||
|
|
@ -256,13 +144,10 @@ test.describe("Tournament bracket", () => {
|
|||
url: tournamentBracketsPage({ tournamentId }),
|
||||
});
|
||||
await navigateToMatch(page, 5);
|
||||
await submit(page, "undo-score-button");
|
||||
await goToTab(page, "action");
|
||||
await undoLastReport(page);
|
||||
await expectScore(page, [0, 0]);
|
||||
await reportResult({
|
||||
page,
|
||||
amountOfMapsToReport: 2,
|
||||
winner: 2,
|
||||
});
|
||||
await reportResult(page, { mapsToReport: 2, winner: 2 });
|
||||
await backToBracket(page);
|
||||
await expect(
|
||||
page.locator("[data-round-id='5'] [data-participant-id='102']"),
|
||||
|
|
@ -335,11 +220,9 @@ test.describe("Tournament bracket", () => {
|
|||
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 navigateToMatch(page, 1);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
|
||||
await page.getByTestId("finalize-tournament-button").click();
|
||||
|
|
@ -408,11 +291,8 @@ test.describe("Tournament bracket", () => {
|
|||
|
||||
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 goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
}
|
||||
|
||||
|
|
@ -447,10 +327,8 @@ test.describe("Tournament bracket", () => {
|
|||
await submit(page, "confirm-finalize-bracket-button");
|
||||
|
||||
await navigateToMatch(page, 13);
|
||||
await reportResult({
|
||||
page,
|
||||
amountOfMapsToReport: 3,
|
||||
});
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 3 });
|
||||
|
||||
await navigate({
|
||||
page,
|
||||
|
|
@ -460,10 +338,8 @@ test.describe("Tournament bracket", () => {
|
|||
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 goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 3 });
|
||||
|
||||
await backToBracket(page);
|
||||
}
|
||||
|
|
@ -471,8 +347,10 @@ test.describe("Tournament bracket", () => {
|
|||
await page.getByTestId("assign-badges-later-switch").click();
|
||||
await submit(page, "confirm-button");
|
||||
|
||||
// not possible to reopen finals match anymore
|
||||
// after finalizing the tournament, the admin tab disappears so the
|
||||
// reopen action is no longer reachable
|
||||
await navigateToMatch(page, 14);
|
||||
await isNotVisible(page.getByRole("tab", { name: "Admin" }));
|
||||
await isNotVisible(page.getByTestId("reopen-match-button"));
|
||||
await backToBracket(page);
|
||||
});
|
||||
|
|
@ -508,23 +386,18 @@ test.describe("Tournament bracket", () => {
|
|||
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 navigateToMatch(page, 1);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
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 navigateToMatch(page, 2);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 3 });
|
||||
await backToBracket(page);
|
||||
|
||||
await page.getByTestId("finalize-tournament-button").click();
|
||||
|
|
@ -573,12 +446,9 @@ test.describe("Tournament bracket", () => {
|
|||
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 navigateToMatch(page, matchId);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
}
|
||||
|
||||
|
|
@ -591,7 +461,7 @@ test.describe("Tournament bracket", () => {
|
|||
await page.getByTestId("finalize-bracket-button").click();
|
||||
await submit(page, "confirm-finalize-bracket-button");
|
||||
|
||||
await page.locator('[data-match-id="7"]').click();
|
||||
await navigateToMatch(page, 7);
|
||||
await expect(page.getByTestId("back-to-bracket-button")).toBeVisible();
|
||||
|
||||
await page.getByTestId("admin-tab").click();
|
||||
|
|
@ -696,25 +566,22 @@ test.describe("Tournament bracket", () => {
|
|||
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 navigateToMatch(page, 2);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
|
||||
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 goToTab(page, "admin");
|
||||
await page.getByTestId("edit-result-0-button").click();
|
||||
// Swap player 3 out for player 4 on the alpha (winner) team
|
||||
await page.getByTestId("edit-result-player-checkbox-alpha-3").click();
|
||||
await page.getByTestId("edit-result-player-checkbox-alpha-4").click();
|
||||
// Toggle KO so we can verify the edit went through (RR collects KO).
|
||||
await page.getByLabel("KO").check();
|
||||
await submit(page, "save-result-0-button");
|
||||
|
||||
await expect(page.getByTestId("revise-button")).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId("player-checkbox-3").first(),
|
||||
).not.toBeChecked();
|
||||
await expect(page.getByText("99p")).toBeVisible();
|
||||
// Edit returns to read-only view, now showing the KO label
|
||||
await expect(page.getByTestId("edit-result-0-button")).toBeVisible();
|
||||
await expect(page.getByText(/\(KO\)/).first()).toBeVisible();
|
||||
});
|
||||
|
||||
test("changes to picked map pool & best of", async ({ page }) => {
|
||||
|
|
@ -740,8 +607,10 @@ test.describe("Tournament bracket", () => {
|
|||
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);
|
||||
await navigateToMatch(page, 1);
|
||||
// Bo5 of clam blitz: one mode icon + ×5 count text
|
||||
await expect(page.getByTestId("mode-progress-CB")).toBeVisible();
|
||||
await expect(page.getByText("×5")).toBeVisible();
|
||||
});
|
||||
|
||||
test("reopens round robin match and changes score", async ({ page }) => {
|
||||
|
|
@ -761,47 +630,36 @@ test.describe("Tournament bracket", () => {
|
|||
|
||||
// needs also to be completed so 9 unlocks
|
||||
await navigateToMatch(page, 7);
|
||||
await reportResult({
|
||||
page,
|
||||
amountOfMapsToReport: 2,
|
||||
points: [100, 0],
|
||||
});
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
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 goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
|
||||
await navigateToMatch(page, 9);
|
||||
await reportResult({
|
||||
page,
|
||||
amountOfMapsToReport: 2,
|
||||
points: [100, 0],
|
||||
});
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
|
||||
await navigateToMatch(page, 10);
|
||||
await reportResult({
|
||||
page,
|
||||
amountOfMapsToReport: 2,
|
||||
points: [100, 0],
|
||||
});
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
|
||||
await navigateToMatch(page, 8);
|
||||
await goToTab(page, "admin");
|
||||
await submit(page, "reopen-match-button");
|
||||
await submit(page, "undo-score-button");
|
||||
await reportResult({
|
||||
page,
|
||||
amountOfMapsToReport: 2,
|
||||
points: [0, 100],
|
||||
await goToTab(page, "action");
|
||||
await undoLastReport(page);
|
||||
await reportResult(page, {
|
||||
mapsToReport: 2,
|
||||
winner: 2,
|
||||
setEnds: true,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -827,41 +685,33 @@ test.describe("Tournament bracket", () => {
|
|||
|
||||
// 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 goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
|
||||
await navigateToMatch(page, 8);
|
||||
await reportResult({
|
||||
page,
|
||||
amountOfMapsToReport: 2,
|
||||
points: [100, 0],
|
||||
});
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
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 goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 1, setEnds: false });
|
||||
await backToBracket(page);
|
||||
|
||||
// Reopen match 7 (R1 match) - simulating a score misreport correction
|
||||
await navigateToMatch(page, 7);
|
||||
await goToTab(page, "admin");
|
||||
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 expectScore(page, [1, 0]);
|
||||
await goToTab(page, "action");
|
||||
await expect(page.getByTestId("winner-radio-1")).toBeVisible();
|
||||
});
|
||||
|
||||
|
|
@ -898,32 +748,35 @@ test.describe("Tournament bracket", () => {
|
|||
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 navigateToMatch(page, 1);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
|
||||
await page.locator('[data-match-id="3"]').click();
|
||||
await navigateToMatch(page, 3);
|
||||
await goToTab(page, "admin");
|
||||
// Picking a chip auto-submits the cast channel; lock the match afterwards.
|
||||
await waitForPOSTResponse(page, async () => {
|
||||
await page.locator('label[for$="-test"]').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 navigateToMatch(page, 2);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 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 navigateToMatch(page, 3);
|
||||
await goToTab(page, "admin");
|
||||
// Lock state is signalled by the toggle being "Unlock" instead of "Lock"
|
||||
await expect(page.getByRole("button", { name: "Unlock" })).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");
|
||||
// Cast channel "test" persists across unlock; the bracket badge flips
|
||||
// from 🔒 CAST to 🔴 LIVE once the match is unlocked and ongoing.
|
||||
await backToBracket(page);
|
||||
await expect(page.getByText("🔴 LIVE")).toBeVisible();
|
||||
});
|
||||
|
|
@ -943,11 +796,9 @@ test.describe("Tournament bracket", () => {
|
|||
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 navigateToMatch(page, 2);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
|
||||
await page.getByTestId("admin-tab").click();
|
||||
await page
|
||||
|
|
@ -988,11 +839,11 @@ test.describe("Tournament bracket", () => {
|
|||
await page.getByTestId("finalize-bracket-button").click();
|
||||
await submit(page, "confirm-finalize-bracket-button");
|
||||
|
||||
await page.locator('[data-match-id="1"]').click();
|
||||
await navigateToMatch(page, 1);
|
||||
await expect(page.getByTestId("screen-banned")).toBeVisible();
|
||||
|
||||
await backToBracket(page);
|
||||
await page.locator('[data-match-id="2"]').click();
|
||||
await navigateToMatch(page, 2);
|
||||
await expect(page.getByTestId("screen-allowed")).toBeVisible();
|
||||
});
|
||||
|
||||
|
|
@ -1015,12 +866,8 @@ test.describe("Tournament bracket", () => {
|
|||
|
||||
await navigateToMatch(page, 1);
|
||||
await expect(page.getByText("Play all 3")).toBeVisible();
|
||||
await reportResult({
|
||||
page,
|
||||
amountOfMapsToReport: 3,
|
||||
points: [100, 0],
|
||||
winner: 1,
|
||||
});
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 3 });
|
||||
});
|
||||
|
||||
test("swiss tournament with bracket advancing/unadvancing & dropping out a team", async ({
|
||||
|
|
@ -1043,11 +890,9 @@ test.describe("Tournament bracket", () => {
|
|||
|
||||
// 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 navigateToMatch(page, id);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
}
|
||||
|
||||
|
|
@ -1171,13 +1016,15 @@ test.describe("Tournament bracket", () => {
|
|||
page,
|
||||
url: tournamentMatchPage({ tournamentId, matchId }),
|
||||
});
|
||||
await page.getByTestId("actions-tab").click();
|
||||
await goToTab(page, "action");
|
||||
|
||||
await page.getByTestId("pick-ban-button").first().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
}
|
||||
|
||||
await expect(page.getByTestId("mode-progress-banned")).toHaveCount(2);
|
||||
// once both teams banned the ban prompt is gone and the actual map
|
||||
// banner takes over.
|
||||
await expect(page.getByTestId("stage-banner")).toBeVisible();
|
||||
}
|
||||
|
||||
await impersonate(page, teamOneCaptainId);
|
||||
|
|
@ -1187,14 +1034,12 @@ test.describe("Tournament bracket", () => {
|
|||
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");
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 1, winner: 2, setEnds: false });
|
||||
|
||||
if (pickBan === "COUNTERPICK") {
|
||||
await page.getByTestId("pick-ban-button").first().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
}
|
||||
|
||||
await impersonate(page, teamTwoCaptainId);
|
||||
|
|
@ -1204,24 +1049,22 @@ test.describe("Tournament bracket", () => {
|
|||
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");
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 1, winner: 1, setEnds: false });
|
||||
|
||||
if (pickBan === "COUNTERPICK") {
|
||||
await page.getByTestId("pick-ban-button").first().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
|
||||
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 undoLastReport(page);
|
||||
await expect(page.getByText("Select the winner")).toBeVisible();
|
||||
await reportResult(page, {
|
||||
mapsToReport: 1,
|
||||
winner: 1,
|
||||
setEnds: false,
|
||||
});
|
||||
await page.getByTestId("pick-ban-button").last().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
await expect(
|
||||
page.getByText("Counterpick", { exact: true }),
|
||||
).toBeVisible();
|
||||
|
|
@ -1241,7 +1084,8 @@ test.describe("Tournament bracket", () => {
|
|||
|
||||
await page.clock.install({ time: new Date() });
|
||||
|
||||
await reportResult({ page, amountOfMapsToReport: 1, winner: 1 });
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 1, winner: 1, setEnds: false });
|
||||
|
||||
await expect(page.getByTestId("match-timer")).toBeVisible();
|
||||
|
||||
|
|
@ -1260,12 +1104,13 @@ test.describe("Tournament bracket", () => {
|
|||
|
||||
await navigateToMatch(page, matchId);
|
||||
|
||||
await page.getByText("End Set").click();
|
||||
await goToTab(page, "admin");
|
||||
await page.getByRole("button", { name: "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();
|
||||
// Match is now finalized (no longer ongoing) → "Final" appears in banner
|
||||
await expect(page.getByTestId("match-final")).toBeVisible();
|
||||
});
|
||||
|
||||
test("dropping team out ends ongoing match early and auto-forfeits losers bracket match", async ({
|
||||
|
|
@ -1277,7 +1122,8 @@ test.describe("Tournament bracket", () => {
|
|||
|
||||
// 1) Report partial score on match 5 (winners bracket)
|
||||
await navigateToMatch(page, 5);
|
||||
await reportResult({ page, amountOfMapsToReport: 1, winner: 1 });
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 1, winner: 1, setEnds: false });
|
||||
await backToBracket(page);
|
||||
|
||||
// 2) Drop team 102 (one of the teams in match 5) via admin
|
||||
|
|
@ -1289,18 +1135,18 @@ test.describe("Tournament bracket", () => {
|
|||
await page.getByLabel("Team", { exact: true }).selectOption("102");
|
||||
await submit(page);
|
||||
|
||||
// 3) Verify the ongoing match ended early
|
||||
// 3) Verify the ongoing match ended early (no longer ongoing → "Final")
|
||||
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 expect(page.getByTestId("match-final")).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 goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 2 });
|
||||
await backToBracket(page);
|
||||
|
||||
// 5) The losers bracket match (match 18) should now have teams:
|
||||
|
|
@ -1308,8 +1154,7 @@ test.describe("Tournament bracket", () => {
|
|||
// - 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();
|
||||
await expect(page.getByTestId("match-final")).toBeVisible();
|
||||
});
|
||||
|
||||
test("ban/pick CUSTOM flow", async ({ page }) => {
|
||||
|
|
@ -1378,14 +1223,14 @@ test.describe("Tournament bracket", () => {
|
|||
page,
|
||||
url: tournamentMatchPage({ tournamentId, matchId }),
|
||||
});
|
||||
await page.getByTestId("actions-tab").click();
|
||||
await goToTab(page, "action");
|
||||
|
||||
await page.getByTestId("pick-ban-button").first().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
|
||||
await expect(page.getByText(/Ban a map \(2\/2\)/)).toBeVisible();
|
||||
await page.getByTestId("pick-ban-button").first().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
|
||||
// 3) PreSet: Lower seed bans 2 maps
|
||||
await impersonate(page, lowerSeedCaptainId);
|
||||
|
|
@ -1393,32 +1238,30 @@ test.describe("Tournament bracket", () => {
|
|||
page,
|
||||
url: tournamentMatchPage({ tournamentId, matchId }),
|
||||
});
|
||||
await page.getByTestId("actions-tab").click();
|
||||
await goToTab(page, "action");
|
||||
|
||||
await page.getByTestId("pick-ban-button").first().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
|
||||
await expect(page.getByText(/Ban a map \(2\/2\)/)).toBeVisible();
|
||||
await page.getByTestId("pick-ban-button").first().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
|
||||
// 4) Roll auto-executed after last ban; report game 1 score
|
||||
await expect(page.getByTestId("stage-banner")).toBeVisible();
|
||||
await page.getByTestId("actions-tab").click();
|
||||
await goToTab(page, "action");
|
||||
|
||||
await page.getByTestId("winner-radio-1").click();
|
||||
await page.getByTestId("points-input-1").fill("100");
|
||||
await submit(page, "report-score-button");
|
||||
await reportResult(page, { mapsToReport: 1, winner: 1, setEnds: false });
|
||||
await expectScore(page, [1, 0]);
|
||||
|
||||
// 5) PostGame: Winner (team 1, captain 33) bans 2 maps
|
||||
await expect(page.getByText(/Ban a map/)).toBeVisible();
|
||||
await page.getByTestId("pick-ban-button").first().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
|
||||
await expect(page.getByText(/Ban a map \(2\/2\)/)).toBeVisible();
|
||||
await page.getByTestId("pick-ban-button").first().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
|
||||
// PostGame: Loser (team 2, captain 29) picks a map
|
||||
await impersonate(page, higherSeedCaptainId);
|
||||
|
|
@ -1426,24 +1269,22 @@ test.describe("Tournament bracket", () => {
|
|||
page,
|
||||
url: tournamentMatchPage({ tournamentId, matchId }),
|
||||
});
|
||||
await page.getByTestId("actions-tab").click();
|
||||
await goToTab(page, "action");
|
||||
|
||||
await expect(page.getByText(/Pick a map/)).toBeVisible();
|
||||
await page.getByTestId("pick-ban-button").first().click();
|
||||
await submit(page);
|
||||
await submit(page, "pick-ban-submit-button");
|
||||
|
||||
// 6) Undo game 1 score — also deletes postGame pick/ban events
|
||||
await expect(page.getByTestId("stage-banner")).toBeVisible();
|
||||
await submit(page, "undo-score-button");
|
||||
await undoLastReport(page);
|
||||
|
||||
await expectScore(page, [0, 0]);
|
||||
await expect(page.getByTestId("stage-banner")).toBeVisible();
|
||||
|
||||
// 7) Re-report game 1 and verify postGame cycle restarts
|
||||
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");
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 1, winner: 1, setEnds: false });
|
||||
await expectScore(page, [1, 0]);
|
||||
|
||||
await expect(page.getByText(/Ban a map/)).toBeVisible();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { ADMIN_ID } from "~/features/admin/admin-constants";
|
||||
import {
|
||||
tournamentAdminPage,
|
||||
tournamentBracketsPage,
|
||||
tournamentMatchPage,
|
||||
} from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -11,12 +16,7 @@ import {
|
|||
startBracket,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import {
|
||||
tournamentAdminPage,
|
||||
tournamentBracketsPage,
|
||||
tournamentMatchPage,
|
||||
} from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
const TOURNAMENT_ID = 2;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
import type { Page } from "@playwright/test";
|
||||
import {
|
||||
tournamentAdminPage,
|
||||
tournamentBracketsPage,
|
||||
tournamentStreamsPage,
|
||||
} from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -7,49 +11,13 @@ import {
|
|||
startBracket,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
} from "./helpers/playwright";
|
||||
import {
|
||||
tournamentAdminPage,
|
||||
tournamentBracketsPage,
|
||||
tournamentStreamsPage,
|
||||
} 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 selectRosterIfNeeded = async (page: Page, teamIndex: 0 | 1) => {
|
||||
const position = teamIndex === 0 ? "first" : "last";
|
||||
const checkbox = page.getByTestId("player-checkbox-0")[position]();
|
||||
|
||||
if ((await checkbox.count()) > 0 && !(await checkbox.isDisabled())) {
|
||||
await page.getByTestId("player-checkbox-0")[position]().click();
|
||||
await page.getByTestId("player-checkbox-1")[position]().click();
|
||||
await page.getByTestId("player-checkbox-2")[position]().click();
|
||||
await page.getByTestId("player-checkbox-3")[position]().click();
|
||||
await submit(page, `save-active-roster-button-${teamIndex}`);
|
||||
await expect(
|
||||
page.getByTestId("player-checkbox-0")[position](),
|
||||
).toBeDisabled();
|
||||
}
|
||||
};
|
||||
|
||||
const reportPartialScore = async (page: Page) => {
|
||||
await page.getByTestId("actions-tab").click();
|
||||
await selectRosterIfNeeded(page, 0);
|
||||
await selectRosterIfNeeded(page, 1);
|
||||
await page.getByTestId("winner-radio-1").click();
|
||||
await submit(page, "report-score-button");
|
||||
await expect(page.getByText("1-0")).toBeVisible();
|
||||
};
|
||||
|
||||
const backToBracket = async (page: Page) => {
|
||||
await page.getByTestId("back-to-bracket-button").click();
|
||||
await expect(page.getByTestId("brackets-viewer")).toBeVisible();
|
||||
};
|
||||
backToBracket,
|
||||
goToTab,
|
||||
navigateToMatch,
|
||||
reportResult,
|
||||
} from "./helpers/tournament-match";
|
||||
|
||||
test.describe("Tournament streams", () => {
|
||||
test("can set cast twitch accounts in admin", async ({ page }) => {
|
||||
|
|
@ -95,7 +63,8 @@ test.describe("Tournament streams", () => {
|
|||
|
||||
await navigateToMatch(page, matchId);
|
||||
// Report partial score to set startedAt (match becomes "in progress")
|
||||
await reportPartialScore(page);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 1, setEnds: false });
|
||||
await backToBracket(page);
|
||||
|
||||
// The LIVE button should be visible since team 102 members are streaming
|
||||
|
|
@ -158,11 +127,12 @@ test.describe("Tournament streams", () => {
|
|||
|
||||
// Navigate to match and start it
|
||||
await navigateToMatch(page, matchId);
|
||||
await reportPartialScore(page);
|
||||
await goToTab(page, "action");
|
||||
await reportResult(page, { mapsToReport: 1, setEnds: false });
|
||||
|
||||
// Set match as casted
|
||||
await page.getByTestId("cast-info-select").selectOption("test_cast_stream");
|
||||
await submit(page, "cast-info-submit-button");
|
||||
// Set match as casted via chip radio
|
||||
await goToTab(page, "admin");
|
||||
await page.locator('label[for$="-test_cast_stream"]').click();
|
||||
await backToBracket(page);
|
||||
|
||||
// Verify LIVE button appears (multiple may exist from player streams)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { calendarPage, tournamentBracketsPage } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -5,8 +6,7 @@ import {
|
|||
seed,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import { calendarPage, tournamentBracketsPage } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
test.describe("Tournament tiers", () => {
|
||||
test("shows tentative tier before bracket starts and confirmed tier after", async ({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
import { BANNED_MAPS } from "~/features/sendouq-settings/banned-maps";
|
||||
import { rankedModesShort } from "~/modules/in-game-lists/modes";
|
||||
import type { StageId } from "~/modules/in-game-lists/types";
|
||||
import {
|
||||
tournamentBracketsPage,
|
||||
tournamentPage,
|
||||
tournamentTeamsPage,
|
||||
} from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -9,12 +14,7 @@ import {
|
|||
seed,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import {
|
||||
tournamentBracketsPage,
|
||||
tournamentPage,
|
||||
tournamentTeamsPage,
|
||||
} from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
|
||||
// TODO: restore operates admin controls after single fetch tested in prod
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type { Page } from "@playwright/test";
|
|||
import { NZAP_TEST_DISCORD_ID, NZAP_TEST_ID } from "~/db/seed/constants";
|
||||
import { ADMIN_DISCORD_ID } from "~/features/admin/admin-constants";
|
||||
import { userEditProfileBaseSchema } from "~/features/user-page/user-page-schemas";
|
||||
import { userEditProfilePage, userPage } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -11,9 +12,8 @@ import {
|
|||
submit,
|
||||
test,
|
||||
waitForPOSTResponse,
|
||||
} from "~/utils/playwright";
|
||||
import { createFormHelpers } from "~/utils/playwright-form";
|
||||
import { userEditProfilePage, userPage } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
import { createFormHelpers } from "./helpers/playwright-form";
|
||||
|
||||
const goToEditPage = (page: Page) =>
|
||||
page.getByText("Edit", { exact: true }).click();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { vodFormBaseSchema } from "~/features/vods/vods-schemas";
|
||||
import { newVodPage, VODS_PAGE, vodVideoPage } from "~/utils/urls";
|
||||
import {
|
||||
expect,
|
||||
impersonate,
|
||||
|
|
@ -10,9 +11,8 @@ import {
|
|||
selectWeapon,
|
||||
submit,
|
||||
test,
|
||||
} from "~/utils/playwright";
|
||||
import { createFormHelpers } from "~/utils/playwright-form";
|
||||
import { newVodPage, VODS_PAGE, vodVideoPage } from "~/utils/urls";
|
||||
} from "./helpers/playwright";
|
||||
import { createFormHelpers } from "./helpers/playwright-form";
|
||||
|
||||
const VIDEO_DATE = new Date(2024, 4, 15, 12, 0); // May 15, 2024 at 12:00
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user