Loading panel/e2e/a11y.spec.ts +1 −0 Changes for panel/e2e/a11y.spec.ts: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ for (const [account, path] of [ ["owner", "/"], ["owner", "/servers"], ["owner", "/admin/lobby?space=login"], ["owner", "/admin/auth-sources"], ["owner", "/admin/images"], ["owner", "/admin/builds"], ["owner", "/admin/submissions"], Loading panel/e2e/auth-sources.smoke.spec.ts +3 −2 Changes for panel/e2e/auth-sources.smoke.spec.ts: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ test("Owner manages durable authentication sources from the sidebar", async ({ p await expect(page).toHaveURL(/\/admin\/auth-sources$/); await expect(page.getByLabel(t("authSources:tag"))).toHaveValue("littleskin"); await expect(page.getByLabel(t("authSources:tag"))).toHaveAttribute("readonly", ""); await page.getByRole("button", { name: t("authSources:expand", { name: "littleskin" }) }).click(); await page.getByRole("button", { name: t("authSources:add"), exact: true }).click(); await page.getByLabel(t("authSources:tag")).nth(1).fill("custom"); await page.getByLabel(t("authSources:prefix")).nth(1).fill("CS"); Loading @@ -14,12 +15,12 @@ test("Owner manages durable authentication sources from the sidebar", async ({ p await page.getByRole("button", { name: t("authSources:test"), exact: true }).nth(1).click(); await expect(page.getByText(t("authSources:test_ok", { ms: 20 }), { exact: true })).toBeVisible(); await page.getByRole("button", { name: t("authSources:move_up"), exact: true }).nth(1).click(); await page.getByRole("checkbox", { name: t("authSources:enabled"), exact: true }).nth(1).uncheck(); await page.getByRole("switch", { name: t("authSources:enabled"), exact: true }).nth(1).uncheck(); await page.getByRole("button", { name: t("authSources:save"), exact: true }).click(); await expect(page.getByText(t("authSources:saved"), { exact: true })).toBeVisible(); await page.reload(); await expect(page.getByLabel(t("authSources:tag")).nth(0)).toHaveValue("custom"); await expect(page.getByRole("checkbox", { name: t("authSources:enabled"), exact: true }).nth(1)).not.toBeChecked(); await expect(page.getByRole("switch", { name: t("authSources:enabled"), exact: true }).nth(1)).not.toBeChecked(); await expect(page.getByRole("button", { name: t("authSources:remove"), exact: true })).toHaveCount(0); const available = await page.request.get("/api/v1/account/link/sources"); expect((await available.json()).sources.map((source: { tag: string }) => source.tag)).toEqual(["mojang", "custom"]); Loading panel/e2e/fixtures.ts +12 −0 Changes for panel/e2e/fixtures.ts: 12 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -36,6 +36,18 @@ export const test = base.extend<{ signIn: (account: Account) => Promise<void> }> export { expect }; export async function expectPinnedHeading(page: Page, title: string, top: number) { const heading = page.getByRole("heading", { name: title, exact: true }); const before = (await heading.boundingBox())!; const pane = page.getByRole("main"); await pane.evaluate((el) => { el.scrollTop = el.scrollHeight; }); await expect.poll(() => pane.evaluate((el) => el.scrollTop)).toBeGreaterThan(100); const after = (await heading.boundingBox())!; expect(after.y).toBeCloseTo(before.y, 0); expect(after.y).toBeGreaterThanOrEqual(top); await expect(heading).toBeInViewport({ ratio: 1 }); } /** expectFitsScreen fails when anything scrolls sideways or a visible element * pokes past the viewport edge (an overflow-hidden parent would just cut it * off). The shell scrolls in an overflow-y-auto pane, whose computed Loading panel/e2e/mobile.spec.ts +10 −1 Changes for panel/e2e/mobile.spec.ts: 10 added lines, 1 removed line. Original line number Diff line number Diff line import { test, expect, t, expectFitsScreen } from "./fixtures"; import { test, expect, t, expectFitsScreen, expectPinnedHeading } from "./fixtures"; test("the menu drawer reaches the other sections", async ({ page, signIn }) => { await signIn("linked"); Loading Loading @@ -71,3 +71,12 @@ test("authentication source drafts with long IDs fit a phone", async ({ page, si await expectFitsScreen(page); await expect(page.getByRole("button", { name: t("authSources:remove"), exact: true })).toBeVisible(); }); test("the mobile navigation and page heading stay visible above a scrolling form", async ({ page, signIn }) => { await signIn("owner"); await page.goto("/admin/lobby"); await expect(page.getByLabel(t("lobby:bookTitle"))).toBeEnabled(); await expectPinnedHeading(page, t("lobby:title"), 56); await expect(page.getByRole("button", { name: t("common:open_menu") })).toBeInViewport({ ratio: 1 }); await expectFitsScreen(page); }); panel/e2e/smoke.spec.ts +54 −1 Changes for panel/e2e/smoke.spec.ts: 54 added lines, 1 removed line. Original line number Diff line number Diff line import { test, expect, t, expectFitsScreen } from "./fixtures"; import { test, expect, t, expectFitsScreen, expectPinnedHeading } from "./fixtures"; test("admin headings share their size and gutters and stay pinned while content scrolls", async ({ page, signIn }) => { await signIn("owner"); await page.setViewportSize({ width: 1440, height: 600 }); const metrics = []; for (const [path, title] of [ ["/admin/submissions", "admin:submissions_title"], ["/admin/lobby", "lobby:title"], ["/admin/auth-sources", "authSources:title"], ]) { await page.goto(path); const heading = page.getByRole("heading", { name: t(title), exact: true }); await expect(heading).toBeVisible(); metrics.push(await heading.evaluate((el) => ({ x: el.getBoundingClientRect().x, y: el.getBoundingClientRect().y, size: getComputedStyle(el).fontSize }))); expect(await page.getByRole("main").getByRole("heading", { level: 1 }).count()).toBe(0); if (path === "/admin/auth-sources") { await page.getByRole("button", { name: t("authSources:expand", { name: "littleskin" }) }).click(); await expectPinnedHeading(page, t(title), 0); } else if (path === "/admin/lobby") { await expect(page.getByLabel(t("lobby:bookTitle"))).toBeEnabled(); await expectPinnedHeading(page, t(title), 0); } } expect(metrics[1]).toEqual(metrics[0]); expect(metrics[2]).toEqual(metrics[0]); }); test("saved authentication sources start closed and switches leave them closed", async ({ page, signIn }) => { await signIn("owner"); await page.goto("/admin/auth-sources"); const expand = page.getByRole("button", { name: t("authSources:expand", { name: "littleskin" }) }); await expect(expand).toHaveAttribute("aria-expanded", "false"); await expect(page.getByLabel(t("authSources:prefix"))).toBeHidden(); const enabled = page.getByRole("switch", { name: t("authSources:enabled"), exact: true }); await enabled.focus(); await page.keyboard.press("Space"); await expect(enabled).toHaveAttribute("aria-checked", "false"); await expect(expand).toHaveAttribute("aria-expanded", "false"); await page.getByRole("button", { name: t("authSources:save"), exact: true }).click(); await expect(page.getByText(t("authSources:saved"), { exact: true })).toBeVisible(); await expand.click(); await expect(page.getByLabel(t("authSources:prefix"))).toBeVisible(); }); test("the console keeps a bounded log pane below the fixed heading", async ({ page, signIn }) => { await signIn("owner"); await page.setViewportSize({ width: 1440, height: 960 }); await page.goto("/servers/lobby"); await expect(page.getByRole("textbox", { name: t("servers:command_label") })).toBeInViewport({ ratio: 1 }); await expect(page.getByRole("button", { name: t("servers:log_clear_btn") })).toBeInViewport({ ratio: 1 }); await expect(page.getByRole("heading", { name: "Hub Lobby", exact: true })).toBeInViewport({ ratio: 1 }); expect(await page.getByRole("main").evaluate((el) => el.scrollTop)).toBe(0); }); test("space settings keep the form visible while reading configuration", async ({ page, signIn }) => { await signIn("owner"); Loading Loading
panel/e2e/a11y.spec.ts +1 −0 Changes for panel/e2e/a11y.spec.ts: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ for (const [account, path] of [ ["owner", "/"], ["owner", "/servers"], ["owner", "/admin/lobby?space=login"], ["owner", "/admin/auth-sources"], ["owner", "/admin/images"], ["owner", "/admin/builds"], ["owner", "/admin/submissions"], Loading
panel/e2e/auth-sources.smoke.spec.ts +3 −2 Changes for panel/e2e/auth-sources.smoke.spec.ts: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ test("Owner manages durable authentication sources from the sidebar", async ({ p await expect(page).toHaveURL(/\/admin\/auth-sources$/); await expect(page.getByLabel(t("authSources:tag"))).toHaveValue("littleskin"); await expect(page.getByLabel(t("authSources:tag"))).toHaveAttribute("readonly", ""); await page.getByRole("button", { name: t("authSources:expand", { name: "littleskin" }) }).click(); await page.getByRole("button", { name: t("authSources:add"), exact: true }).click(); await page.getByLabel(t("authSources:tag")).nth(1).fill("custom"); await page.getByLabel(t("authSources:prefix")).nth(1).fill("CS"); Loading @@ -14,12 +15,12 @@ test("Owner manages durable authentication sources from the sidebar", async ({ p await page.getByRole("button", { name: t("authSources:test"), exact: true }).nth(1).click(); await expect(page.getByText(t("authSources:test_ok", { ms: 20 }), { exact: true })).toBeVisible(); await page.getByRole("button", { name: t("authSources:move_up"), exact: true }).nth(1).click(); await page.getByRole("checkbox", { name: t("authSources:enabled"), exact: true }).nth(1).uncheck(); await page.getByRole("switch", { name: t("authSources:enabled"), exact: true }).nth(1).uncheck(); await page.getByRole("button", { name: t("authSources:save"), exact: true }).click(); await expect(page.getByText(t("authSources:saved"), { exact: true })).toBeVisible(); await page.reload(); await expect(page.getByLabel(t("authSources:tag")).nth(0)).toHaveValue("custom"); await expect(page.getByRole("checkbox", { name: t("authSources:enabled"), exact: true }).nth(1)).not.toBeChecked(); await expect(page.getByRole("switch", { name: t("authSources:enabled"), exact: true }).nth(1)).not.toBeChecked(); await expect(page.getByRole("button", { name: t("authSources:remove"), exact: true })).toHaveCount(0); const available = await page.request.get("/api/v1/account/link/sources"); expect((await available.json()).sources.map((source: { tag: string }) => source.tag)).toEqual(["mojang", "custom"]); Loading
panel/e2e/fixtures.ts +12 −0 Changes for panel/e2e/fixtures.ts: 12 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -36,6 +36,18 @@ export const test = base.extend<{ signIn: (account: Account) => Promise<void> }> export { expect }; export async function expectPinnedHeading(page: Page, title: string, top: number) { const heading = page.getByRole("heading", { name: title, exact: true }); const before = (await heading.boundingBox())!; const pane = page.getByRole("main"); await pane.evaluate((el) => { el.scrollTop = el.scrollHeight; }); await expect.poll(() => pane.evaluate((el) => el.scrollTop)).toBeGreaterThan(100); const after = (await heading.boundingBox())!; expect(after.y).toBeCloseTo(before.y, 0); expect(after.y).toBeGreaterThanOrEqual(top); await expect(heading).toBeInViewport({ ratio: 1 }); } /** expectFitsScreen fails when anything scrolls sideways or a visible element * pokes past the viewport edge (an overflow-hidden parent would just cut it * off). The shell scrolls in an overflow-y-auto pane, whose computed Loading
panel/e2e/mobile.spec.ts +10 −1 Changes for panel/e2e/mobile.spec.ts: 10 added lines, 1 removed line. Original line number Diff line number Diff line import { test, expect, t, expectFitsScreen } from "./fixtures"; import { test, expect, t, expectFitsScreen, expectPinnedHeading } from "./fixtures"; test("the menu drawer reaches the other sections", async ({ page, signIn }) => { await signIn("linked"); Loading Loading @@ -71,3 +71,12 @@ test("authentication source drafts with long IDs fit a phone", async ({ page, si await expectFitsScreen(page); await expect(page.getByRole("button", { name: t("authSources:remove"), exact: true })).toBeVisible(); }); test("the mobile navigation and page heading stay visible above a scrolling form", async ({ page, signIn }) => { await signIn("owner"); await page.goto("/admin/lobby"); await expect(page.getByLabel(t("lobby:bookTitle"))).toBeEnabled(); await expectPinnedHeading(page, t("lobby:title"), 56); await expect(page.getByRole("button", { name: t("common:open_menu") })).toBeInViewport({ ratio: 1 }); await expectFitsScreen(page); });
panel/e2e/smoke.spec.ts +54 −1 Changes for panel/e2e/smoke.spec.ts: 54 added lines, 1 removed line. Original line number Diff line number Diff line import { test, expect, t, expectFitsScreen } from "./fixtures"; import { test, expect, t, expectFitsScreen, expectPinnedHeading } from "./fixtures"; test("admin headings share their size and gutters and stay pinned while content scrolls", async ({ page, signIn }) => { await signIn("owner"); await page.setViewportSize({ width: 1440, height: 600 }); const metrics = []; for (const [path, title] of [ ["/admin/submissions", "admin:submissions_title"], ["/admin/lobby", "lobby:title"], ["/admin/auth-sources", "authSources:title"], ]) { await page.goto(path); const heading = page.getByRole("heading", { name: t(title), exact: true }); await expect(heading).toBeVisible(); metrics.push(await heading.evaluate((el) => ({ x: el.getBoundingClientRect().x, y: el.getBoundingClientRect().y, size: getComputedStyle(el).fontSize }))); expect(await page.getByRole("main").getByRole("heading", { level: 1 }).count()).toBe(0); if (path === "/admin/auth-sources") { await page.getByRole("button", { name: t("authSources:expand", { name: "littleskin" }) }).click(); await expectPinnedHeading(page, t(title), 0); } else if (path === "/admin/lobby") { await expect(page.getByLabel(t("lobby:bookTitle"))).toBeEnabled(); await expectPinnedHeading(page, t(title), 0); } } expect(metrics[1]).toEqual(metrics[0]); expect(metrics[2]).toEqual(metrics[0]); }); test("saved authentication sources start closed and switches leave them closed", async ({ page, signIn }) => { await signIn("owner"); await page.goto("/admin/auth-sources"); const expand = page.getByRole("button", { name: t("authSources:expand", { name: "littleskin" }) }); await expect(expand).toHaveAttribute("aria-expanded", "false"); await expect(page.getByLabel(t("authSources:prefix"))).toBeHidden(); const enabled = page.getByRole("switch", { name: t("authSources:enabled"), exact: true }); await enabled.focus(); await page.keyboard.press("Space"); await expect(enabled).toHaveAttribute("aria-checked", "false"); await expect(expand).toHaveAttribute("aria-expanded", "false"); await page.getByRole("button", { name: t("authSources:save"), exact: true }).click(); await expect(page.getByText(t("authSources:saved"), { exact: true })).toBeVisible(); await expand.click(); await expect(page.getByLabel(t("authSources:prefix"))).toBeVisible(); }); test("the console keeps a bounded log pane below the fixed heading", async ({ page, signIn }) => { await signIn("owner"); await page.setViewportSize({ width: 1440, height: 960 }); await page.goto("/servers/lobby"); await expect(page.getByRole("textbox", { name: t("servers:command_label") })).toBeInViewport({ ratio: 1 }); await expect(page.getByRole("button", { name: t("servers:log_clear_btn") })).toBeInViewport({ ratio: 1 }); await expect(page.getByRole("heading", { name: "Hub Lobby", exact: true })).toBeInViewport({ ratio: 1 }); expect(await page.getByRole("main").evaluate((el) => el.scrollTop)).toBe(0); }); test("space settings keep the form visible while reading configuration", async ({ page, signIn }) => { await signIn("owner"); Loading