Skip to content

Commit e3c066e

Browse files
committed
test: verify dark/light mode via normalized relative luminance
Replace pixel-based screenshot comparisons with perceptually accurate brightness assertions using ITU-R BT.709 relative luminance (0.2126R + 0.7152G + 0.0722B), normalized to [0,1]. Assert light mode ≈0.85 and dark mode ≈0.25. Signed-off-by: rafaeljohn9 <[email protected]>
1 parent e2eb96f commit e3c066e

File tree

1 file changed

+53
-10
lines changed

1 file changed

+53
-10
lines changed

tests/git-scm.spec.js

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -316,30 +316,73 @@ test('small-and-fast', async ({ page }) => {
316316
});
317317

318318
test('dark mode', async({ page }) => {
319+
// Helper: returns relative luminance in range [0, 1]
320+
const getPageBrightness = async () => {
321+
const screenshot = await page.screenshot({ type: 'png' });
322+
const base64 = screenshot.toString('base64');
323+
324+
return await page.evaluate((b64) => {
325+
return new Promise((resolve) => {
326+
const img = new Image();
327+
img.src = `data:image/png;base64,${b64}`;
328+
img.onload = () => {
329+
const canvas = document.createElement('canvas');
330+
canvas.width = canvas.height = 1;
331+
const ctx = canvas.getContext('2d');
332+
ctx.drawImage(img, 0, 0, 1, 1);
333+
const [r, g, b] = ctx.getImageData(0, 0, 1, 1).data;
334+
335+
// Calculate brightness, for more details, see
336+
// https://en.wikipedia.org/wiki/Relative_luminance#Relative_luminance_and_%22gamma_encoded%22_colorspaces
337+
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
338+
339+
// Normalize to [0, 1]
340+
resolve(luminance / 255);
341+
};
342+
img.onerror = () => resolve(-1); // error indicator
343+
});
344+
}, base64);
345+
};
346+
319347
await page.setViewportSize(devices['iPhone X'].viewport);
348+
await page.goto(url);
320349

321-
await page.goto(`${url}`);
350+
// Ensure consistent test state
322351
await page.evaluate(() => {
323352
document.querySelector('#tagline').innerHTML = '--dark-mode-for-dark-times';
324353
});
354+
325355
const darkModeButton = page.locator('#dark-mode-button');
326356

327-
const o = { maxDiffPixels: 30 };
328-
await expect(page).toHaveScreenshot({ name: 'light-mode.png', ...o });
357+
// 1. Light mode
358+
const lightBrightness = await getPageBrightness();
359+
expect(lightBrightness).toBeCloseTo(0.85, 0.1); // e.g., 0.75–0.95
360+
361+
// 2. Toggle to dark mode
329362
await darkModeButton.click();
330-
await expect(page).toHaveScreenshot({ name: 'dark-mode.png', ...o });
363+
const darkBrightness = await getPageBrightness();
364+
expect(darkBrightness).toBeCloseTo(0.25, 0.1); // e.g., 0.15–0.35
331365

332-
// Now, try again, but this time with system's preference being dark mode
366+
// 3. Verify dark < light
367+
expect(darkBrightness).toBeLessThan(lightBrightness);
333368

369+
// --- Test system preference: prefers-color-scheme: dark ---
334370
await page.emulateMedia({ colorScheme: 'dark' });
335-
await page.evaluate(() => window.localStorage.clear());
336-
await page.evaluate(() => window.sessionStorage.clear());
371+
await page.evaluate(() => {
372+
localStorage.clear();
373+
sessionStorage.clear();
374+
});
337375
await page.reload();
338376
await page.evaluate(() => {
339377
document.querySelector('#tagline').innerHTML = '--dark-mode-for-dark-times';
340378
});
341379

342-
await expect(page).toHaveScreenshot({ name: 'dark-mode.png', ...o });
380+
// Should start in dark mode
381+
const autoDarkBrightness = await getPageBrightness();
382+
expect(autoDarkBrightness).toBeCloseTo(0.25, 0.1);
383+
384+
// Toggle to light
343385
await darkModeButton.click();
344-
await expect(page).toHaveScreenshot({ name: 'light-mode.png', ...o });
345-
})
386+
const autoLightBrightness = await getPageBrightness();
387+
expect(autoLightBrightness).toBeCloseTo(0.85, 0.1);
388+
});

0 commit comments

Comments
 (0)