import { test, expect, AdminPage, createCategory, createTag, uniqueSuffix } from './fixtures'; // Relative luminance per WCAG, used to tell "light" from "dark" without // asserting exact hex values, which would break on any palette tweak. function luminance(rgb: string): number { // Defaulted per channel rather than on the match: a colour string with // fewer than three numbers would otherwise leave a channel undefined. const [r = 0, g = 0, b = 0] = (rgb.match(/\d+(\.\d+)?/g) ?? []).slice(0, 3).map(Number); const channel = (c: number) => { const s = c / 255; return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4); }; return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b); } // The Categories and Tags tabs render an empty state when there is nothing to // show, and the shared dev database gets truncated by the backend integration // suite (#116). Seed what each test needs rather than depending on what happens // to be there. async function seed(request: import('@playwright/test').APIRequestContext) { const run = uniqueSuffix(); await createCategory(request, `Theme ${run}`); await createTag(request, `theme-${run}`); } test.describe('Admin dark mode', () => { test('the active tab label is readable against the dark background', async ({ admin }) => { await admin.switchToDark(); // The bug: colorPrimary stayed #1a1a1a in dark mode, so the active tab was // near-black text on a near-black background. await expect .poll(async () => luminance(await AdminPage.colorOf(admin.activeTabLabel))) .toBeGreaterThan(0.5); }); test('the Categories tab follows the dark theme', async ({ page, admin }) => { await seed(page.request); await admin.switchToDark(); await admin.openTab('Categories'); await expect(admin.activeTree).toBeVisible(); // The bug: deep imports from antd/lib loaded a second copy of antd that // never saw ConfigProvider, so this rendered pure white in dark mode. expect(luminance(await AdminPage.backgroundOf(admin.activeTree))).toBeLessThan(0.5); }); test('the Tags tab follows the dark theme', async ({ page, admin }) => { await seed(page.request); await admin.switchToDark(); await admin.openTab('Tags'); await expect(admin.activeTable).toBeVisible(); expect(luminance(await AdminPage.backgroundOf(admin.activeTable))).toBeLessThan(0.5); }); test('the item form category selector follows the dark theme', async ({ admin, adminInventory }) => { await admin.switchToDark(); await adminInventory.openItemForm(); await adminInventory.categoryField.click(); await expect(admin.selectDropdown).toBeVisible(); expect(luminance(await AdminPage.backgroundOf(admin.selectDropdown))).toBeLessThan(0.5); }); }); test.describe('Admin copy', () => { test('uses American English spelling for color', async ({ page, admin }) => { await seed(page.request); await admin.open('Tags'); await expect(page.getByRole('columnheader', { name: 'Color' })).toBeVisible(); await expect(page.getByText('Colour')).toHaveCount(0); }); });