mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-27 21:55:15 -05:00
Progress
This commit is contained in:
@@ -55,7 +55,6 @@ export const meta: MetaFunction = (args) => {
|
||||
});
|
||||
};
|
||||
|
||||
// xxx: should seed be just in the dropdown menu?
|
||||
export default function AdminPage() {
|
||||
const isStaff = useHasRole("STAFF");
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ function isBuildFresh(): boolean {
|
||||
try {
|
||||
const marker = JSON.parse(fs.readFileSync(BUILD_MARKER_FILE, "utf8"));
|
||||
if (marker.siteDomain !== `http://localhost:${E2E_BASE_PORT}`) return false;
|
||||
if (marker.skalopWsUrl !== "") return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
@@ -153,11 +154,20 @@ async function globalSetup(config: FullConfig) {
|
||||
...process.env,
|
||||
VITE_E2E_TEST_RUN: "true",
|
||||
VITE_SITE_DOMAIN: `http://localhost:${E2E_BASE_PORT}`,
|
||||
// Skalop is disconnected in e2e: all workers sharing one instance
|
||||
// cross-talk (identical seeded row ids -> colliding room names ->
|
||||
// spurious revalidations). When e2e tests for chat etc. are added
|
||||
// this needs an actual solution: one skalop (or stub) per worker
|
||||
// with a runtime-derived ws URL, since this build is shared.
|
||||
VITE_SKALOP_WS_URL: "",
|
||||
},
|
||||
});
|
||||
fs.writeFileSync(
|
||||
BUILD_MARKER_FILE,
|
||||
JSON.stringify({ siteDomain: `http://localhost:${E2E_BASE_PORT}` }),
|
||||
JSON.stringify({
|
||||
siteDomain: `http://localhost:${E2E_BASE_PORT}`,
|
||||
skalopWsUrl: "",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -197,6 +207,9 @@ async function globalSetup(config: FullConfig) {
|
||||
STORAGE_SECRET: "minio-password",
|
||||
STORAGE_REGION: "us-east-1",
|
||||
STORAGE_BUCKET: "sendou",
|
||||
// no system messages to a shared skalop instance (see build env above)
|
||||
SKALOP_SYSTEM_MESSAGE_URL: "",
|
||||
SKALOP_TOKEN: "",
|
||||
},
|
||||
detached: false,
|
||||
});
|
||||
|
||||
@@ -285,9 +285,9 @@ export async function waitForPOSTResponse(page: Page, cb: () => Promise<void>) {
|
||||
|
||||
// React Aria buttons fire their handler on press end. Occasionally a click
|
||||
// registers the press start (the button goes `:active`) but the press never
|
||||
// completes into a submit, so no POST fires. The match page revalidating on
|
||||
// a websocket message mid-click is one way this happens. Re-issue the action
|
||||
// when the expected POST doesn't arrive within the per-attempt window.
|
||||
// completes into a submit, so no POST fires — e.g. when a re-render lands
|
||||
// mid-press. Re-issue the action when the expected POST doesn't arrive
|
||||
// within the per-attempt window.
|
||||
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
||||
const responsePromise = page.waitForResponse(
|
||||
(res) => res.request().method() === "POST",
|
||||
@@ -317,7 +317,6 @@ export function modalClickConfirmButton(page: Page) {
|
||||
* first when the tab has collapsed into it on the current viewport. Retried as a
|
||||
* whole because the nav can re-collapse between the visibility check and the click.
|
||||
*/
|
||||
// xxx: timeouts?
|
||||
export async function clickNavTab(page: Page, testId: string) {
|
||||
const visibleTab = page.locator(`[data-testid="${testId}"]:visible`);
|
||||
await expect(async () => {
|
||||
@@ -327,18 +326,3 @@ export async function clickNavTab(page: Page, testId: string) {
|
||||
await visibleTab.click({ timeout: 2_000 });
|
||||
}).toPass({ timeout: 15_000 });
|
||||
}
|
||||
|
||||
// xxx: timeout??? anyway can we isolate websocket events? avoiding shared skalop
|
||||
/**
|
||||
* Clicks `trigger` until `expected` is visible, for clicks that open a popover or
|
||||
* dialog — a revalidation re-render (e.g. another worker's websocket event) can
|
||||
* swallow the press.
|
||||
*/
|
||||
export async function clickUntilVisible(trigger: Locator, expected: Locator) {
|
||||
await expect(async () => {
|
||||
if (!(await expected.isVisible())) {
|
||||
await trigger.click({ timeout: 2_000 });
|
||||
}
|
||||
await expect(expected).toBeVisible({ timeout: 2_000 });
|
||||
}).toPass({ timeout: 15_000 });
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { Page } from "@playwright/test";
|
||||
import { SENDOUQ_BEST_OF } from "~/features/sendouq/q-constants";
|
||||
import { sendouQMatchPage } from "~/utils/urls";
|
||||
import {
|
||||
clickUntilVisible,
|
||||
expect,
|
||||
navigate,
|
||||
selectWeapon,
|
||||
@@ -132,10 +131,7 @@ export class SendouQMatchPage {
|
||||
}
|
||||
|
||||
async requestCancel() {
|
||||
await clickUntilVisible(
|
||||
this.locators.requestCancelButton,
|
||||
this.page.getByTestId("confirm-button"),
|
||||
);
|
||||
await this.locators.requestCancelButton.click();
|
||||
await this.confirmDialog();
|
||||
}
|
||||
|
||||
|
||||
@@ -137,10 +137,10 @@ export class TournamentMatchPage {
|
||||
/**
|
||||
* Selects one of the pick/ban options and submits it.
|
||||
*
|
||||
* Selecting and submitting are retried together as one unit because the match
|
||||
* page revalidates on websocket messages: a re-render landing mid-click can
|
||||
* swallow the submit press (see waitForPOSTResponse) and, if the panel
|
||||
* remounted, the selection with it — so re-submitting alone would not be enough.
|
||||
* Selecting and submitting are retried together as one unit: a re-render
|
||||
* landing mid-click can swallow the submit press (see waitForPOSTResponse)
|
||||
* and, if the panel remounted, the selection with it — so re-submitting
|
||||
* alone would not be enough.
|
||||
*/
|
||||
pickBan(option: "first" | "last" = "first") {
|
||||
return waitForPOSTResponse(this.page, async () => {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { reportUserSchema } from "~/features/user-report/user-report-schemas";
|
||||
import {
|
||||
clickUntilVisible,
|
||||
submit,
|
||||
waitForPOSTResponse,
|
||||
} from "../../helpers/playwright";
|
||||
import { expect, submit, waitForPOSTResponse } from "../../helpers/playwright";
|
||||
import { createFormHelpers } from "../../helpers/playwright-form";
|
||||
import { UserCardEditPage } from "./user-card-edit-page";
|
||||
|
||||
@@ -26,10 +22,11 @@ export class UserCard {
|
||||
};
|
||||
}
|
||||
|
||||
/** Opens the card popover through its trigger, retrying a swallowed press. */
|
||||
/** Opens the card popover through its trigger. */
|
||||
static async open(page: Page, trigger: Locator) {
|
||||
const card = new UserCard(page);
|
||||
await clickUntilVisible(trigger, card.locators.banner);
|
||||
await trigger.click();
|
||||
await expect(card.locators.banner).toBeVisible();
|
||||
return card;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ import { TournamentSeedsPage } from "./pages/tournament/tournament-seeds-page";
|
||||
import { TournamentTeamsPage } from "./pages/tournament/tournament-teams-page";
|
||||
import { UserResultsPage } from "./pages/user/user-results-page";
|
||||
|
||||
// xxx: tournament-bracket-elim, tournament-bracket-swiss etc. and pick ban as separate and general another?
|
||||
|
||||
const ROSTER_SIZE = 4;
|
||||
|
||||
type BracketProgression = TournamentSettings["bracketProgression"];
|
||||
@@ -148,7 +146,6 @@ test.describe("Tournament bracket", () => {
|
||||
{},
|
||||
{ rosterSize: 5 },
|
||||
]);
|
||||
// xxx: should be an option
|
||||
const [match] = await factories.TournamentFactory.startBracket(
|
||||
tournament.id,
|
||||
);
|
||||
@@ -342,7 +339,6 @@ test.describe("Tournament bracket", () => {
|
||||
);
|
||||
});
|
||||
|
||||
// xxx: does this and every other test need so big tournaments?
|
||||
test("completes and finalizes a small tournament (RR->SE w/ underground bracket)", async ({
|
||||
page,
|
||||
factories,
|
||||
@@ -1073,8 +1069,9 @@ test.describe("Tournament bracket", () => {
|
||||
winner: 1,
|
||||
setEnds: false,
|
||||
});
|
||||
await match.pickBan("last");
|
||||
await expect(match.locators.counterpickText).toBeVisible();
|
||||
await match.pickBan("last");
|
||||
await expect(match.locators.selectWinnerText).toBeVisible();
|
||||
await expect(match.score([1, 1])).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user