/** * Media Library E2E Tests * * Tests uploading, viewing, and deleting media files. * Runs against an isolated fixture — starts with no media. */ import { writeFileSync, mkdirSync, existsSync } from "node:fs"; import { join } from "node:path"; import { test, expect } from "../fixtures"; // Create a test image for uploads const TEST_ASSETS_DIR = join(process.cwd(), "e2e/fixtures/assets"); // Regex patterns const MEDIA_API_RESPONSE_PATTERN = /\/api\/media/; const UPLOAD_BUTTON_REGEX = /Upload/; function ensureTestAssets(): string { if (!existsSync(TEST_ASSETS_DIR)) { mkdirSync(TEST_ASSETS_DIR, { recursive: true }); } // Create a simple test PNG (1x1 red pixel) const testImagePath = join(TEST_ASSETS_DIR, "test-image.png"); if (!existsSync(testImagePath)) { // Minimal valid PNG file (1x1 red pixel) const pngData = Buffer.from([ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xde, 0x00, 0x00, 0x00, 0x0c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xcf, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x05, 0xfe, 0xd4, 0xef, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, ]); writeFileSync(testImagePath, pngData); } return testImagePath; } test.describe("Media Library", () => { test.beforeAll(() => { ensureTestAssets(); }); test.beforeEach(async ({ admin }) => { await admin.devBypassAuth(); }); test.describe("Media List", () => { test("displays media library page", async ({ admin }) => { await admin.goToMedia(); await admin.waitForLoading(); // Should show the media library heading await admin.expectPageTitle("Media Library"); // Should have upload button await expect( admin.page.getByRole("button", { name: UPLOAD_BUTTON_REGEX }).first(), ).toBeVisible(); }); test("shows grid view by default", async ({ admin }) => { await admin.goToMedia(); await admin.waitForLoading(); // Grid view button should be active const gridButton = admin.page.locator('button[aria-label="Grid view"]'); await expect(gridButton).toBeVisible(); }); test("shows view toggle buttons", async ({ admin }) => { await admin.goToMedia(); await admin.waitForLoading(); // View toggle buttons should be visible (grid and list icons) const buttons = admin.page.locator("button").filter({ has: admin.page.locator("svg") }); const count = await buttons.count(); expect(count).toBeGreaterThan(0); }); }); test.describe("Upload Media", () => { test("uploads a new image file", async ({ admin, page }) => { await admin.goToMedia(); await admin.waitForLoading(); // Upload file const testImagePath = ensureTestAssets(); const fileInput = page.locator('input[type="file"]'); await fileInput.setInputFiles(testImagePath); // Wait for upload await page.waitForResponse( (res) => MEDIA_API_RESPONSE_PATTERN.test(res.url()) && res.status() === 200, { timeout: 10000 }, ); // Wait for the uploaded image to appear in the media grid const mediaGrid = page.locator(".grid.gap-4"); await expect(mediaGrid.locator("img").first()).toBeVisible({ timeout: 5000 }); // Should have at least one image in the grid now const images = mediaGrid.locator("img"); const count = await images.count(); expect(count).toBeGreaterThan(0); }); }); test.describe("List View", () => { test("shows file details in list view", async ({ admin, page }) => { // Upload a file first so there's something to show await admin.goToMedia(); await admin.waitForLoading(); const testImagePath = ensureTestAssets(); const fileInput = page.locator('input[type="file"]'); await fileInput.setInputFiles(testImagePath); await page.waitForResponse( (res) => MEDIA_API_RESPONSE_PATTERN.test(res.url()) && res.status() === 200, { timeout: 10000 }, ); await page.reload(); await admin.waitForLoading(); // Switch to list view await page.click('button[aria-label="List view"]'); // Should show table with columns await expect(page.locator("th:has-text('Filename')")).toBeVisible(); await expect(page.locator("th:has-text('Type')")).toBeVisible(); await expect(page.locator("th:has-text('Size')")).toBeVisible(); }); }); });