Fixes: 1. media.ts: wrap placeholder generation in try-catch 2. toolbar.ts: check r.ok, display error message in popover
118 lines
3.7 KiB
TypeScript
118 lines
3.7 KiB
TypeScript
/**
|
|
* Keyboard Shortcuts & Panel Dismiss E2E Tests
|
|
*
|
|
* Tests that keyboard shortcuts (Escape to close, Cmd+S to save) work
|
|
* correctly in slide-out panels, and that the Shell sidebar auto-closes
|
|
* on viewport resize.
|
|
*
|
|
* These verify the useStableCallback pattern — event listeners must
|
|
* remain functional across re-renders without churn.
|
|
*/
|
|
|
|
import { test, expect } from "../fixtures";
|
|
|
|
test.describe("Keyboard Shortcuts", () => {
|
|
test.beforeEach(async ({ admin }) => {
|
|
await admin.devBypassAuth();
|
|
});
|
|
|
|
test.describe("Media Detail Panel", () => {
|
|
test("Escape closes the media detail panel", async ({ admin, page }) => {
|
|
await admin.goToMedia();
|
|
await admin.waitForLoading();
|
|
|
|
// Seed data includes uploaded media — click the first grid item (a button)
|
|
const mediaItem = page.locator(".grid.gap-4 button").first();
|
|
await expect(mediaItem).toBeVisible({ timeout: 10000 });
|
|
await mediaItem.click();
|
|
|
|
// Panel should be visible
|
|
const panel = page.locator("text=Media Details");
|
|
await expect(panel).toBeVisible({ timeout: 5000 });
|
|
|
|
// Press Escape
|
|
await page.keyboard.press("Escape");
|
|
|
|
// Panel should be closed
|
|
await expect(panel).not.toBeVisible({ timeout: 3000 });
|
|
});
|
|
|
|
test("Cmd+S saves media detail changes", async ({ admin, page }) => {
|
|
await admin.goToMedia();
|
|
await admin.waitForLoading();
|
|
|
|
// Click the first media item
|
|
const mediaItem = page.locator(".grid.gap-4 button").first();
|
|
await expect(mediaItem).toBeVisible({ timeout: 10000 });
|
|
await mediaItem.click();
|
|
|
|
await expect(page.locator("text=Media Details")).toBeVisible({ timeout: 5000 });
|
|
|
|
// Change alt text (only visible for images)
|
|
const altInput = page.getByLabel("Alt Text");
|
|
if (await altInput.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
await altInput.fill(`E2E Alt ${Date.now()}`);
|
|
|
|
// Listen for the update API call
|
|
const saveResponse = page.waitForResponse(
|
|
(res) =>
|
|
res.url().includes("/api/media/") &&
|
|
res.request().method() === "PUT" &&
|
|
res.status() === 200,
|
|
{ timeout: 10000 },
|
|
);
|
|
|
|
// Press Cmd+S (Control on Linux/CI)
|
|
const modifier = process.platform === "darwin" ? "Meta" : "Control";
|
|
await page.keyboard.press(`${modifier}+s`);
|
|
|
|
// Should trigger the save
|
|
await saveResponse;
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe("User Detail Panel", () => {
|
|
test("Escape closes the user detail panel", async ({ admin, page }) => {
|
|
await admin.goto("/users");
|
|
await admin.waitForShell();
|
|
await admin.waitForLoading();
|
|
|
|
// Click a user row to open the detail panel
|
|
const userRow = page.locator("table tbody tr").first();
|
|
await expect(userRow).toBeVisible({ timeout: 10000 });
|
|
await userRow.click();
|
|
|
|
// Panel should appear
|
|
const panel = page.locator("text=User Details");
|
|
await expect(panel).toBeVisible({ timeout: 5000 });
|
|
|
|
// Press Escape
|
|
await page.keyboard.press("Escape");
|
|
|
|
// Panel should be closed
|
|
await expect(panel).not.toBeVisible({ timeout: 3000 });
|
|
});
|
|
});
|
|
|
|
test.describe("Shell Sidebar", () => {
|
|
test("sidebar becomes mobile sheet when viewport shrinks below md breakpoint", async ({
|
|
admin,
|
|
page,
|
|
}) => {
|
|
await admin.goToDashboard();
|
|
|
|
// Start at desktop width — sidebar should be visible as aside
|
|
await page.setViewportSize({ width: 1280, height: 720 });
|
|
const sidebar = page.locator('aside[aria-label="Admin navigation"]');
|
|
await expect(sidebar).toBeVisible();
|
|
|
|
// Shrink below kumo's mobile breakpoint (768px) — sidebar becomes a dialog sheet
|
|
await page.setViewportSize({ width: 600, height: 720 });
|
|
|
|
// The aside element should no longer be in the viewport
|
|
await expect(sidebar).not.toBeInViewport({ timeout: 3000 });
|
|
});
|
|
});
|
|
});
|