fix(panel): unify fixed headers and collapsible auth sources
This commit is contained in:
15 files changed
+223
-63
No files matched your search
@@ -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"],
|
||||
|
||||
@@ -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");
|
||||
@@ -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"]);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
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");
|
||||
@@ -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);
|
||||
});
|
||||
+54
-1
@@ -1,4 +1,57 @@
|
||||
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");
|
||||
|
||||
Reference in new issue
Block a user