| import { expect, test } from '@playwright/test'; |
|
|
| |
| |
| |
| |
| |
| |
|
|
| test.describe('theme toggle (happy variant)', () => { |
| test.beforeEach(async ({ page }) => { |
| |
| |
| await page.addInitScript(() => { |
| if (!sessionStorage.getItem('__test_init_done')) { |
| localStorage.removeItem('worldmonitor-theme'); |
| localStorage.removeItem('worldmonitor-variant'); |
| localStorage.setItem('worldmonitor-variant', 'happy'); |
| sessionStorage.setItem('__test_init_done', '1'); |
| } |
| }); |
| }); |
|
|
| test('happy variant defaults to light theme', async ({ page }) => { |
| await page.goto('/'); |
| await page.waitForSelector('#headerThemeToggle', { timeout: 15000 }); |
|
|
| const theme = await page.evaluate(() => document.documentElement.dataset.theme); |
| expect(theme).toBe('light'); |
|
|
| |
| const bg = await page.evaluate(() => |
| getComputedStyle(document.documentElement).getPropertyValue('--bg').trim(), |
| ); |
| expect(bg).toBe('#FAFAF5'); |
| }); |
|
|
| test('toggle to dark mode changes CSS variables', async ({ page }) => { |
| await page.goto('/'); |
| await page.waitForSelector('#headerThemeToggle', { timeout: 15000 }); |
|
|
| |
| expect(await page.evaluate(() => document.documentElement.dataset.theme)).toBe('light'); |
|
|
| |
| await page.click('#headerThemeToggle'); |
| await page.waitForTimeout(200); |
|
|
| |
| const theme = await page.evaluate(() => document.documentElement.dataset.theme); |
| expect(theme).toBe('dark'); |
|
|
| |
| const bg = await page.evaluate(() => |
| getComputedStyle(document.documentElement).getPropertyValue('--bg').trim(), |
| ); |
| expect(bg).toBe('#1A2332'); |
|
|
| |
| const text = await page.evaluate(() => |
| getComputedStyle(document.documentElement).getPropertyValue('--text').trim(), |
| ); |
| expect(text).toBe('#E8E4DC'); |
| }); |
|
|
| test('toggle back to light mode restores light CSS variables', async ({ page }) => { |
| await page.goto('/'); |
| await page.waitForSelector('#headerThemeToggle', { timeout: 15000 }); |
|
|
| |
| await page.click('#headerThemeToggle'); |
| await page.waitForTimeout(200); |
| expect(await page.evaluate(() => document.documentElement.dataset.theme)).toBe('dark'); |
|
|
| |
| await page.click('#headerThemeToggle'); |
| await page.waitForTimeout(200); |
|
|
| const theme = await page.evaluate(() => document.documentElement.dataset.theme); |
| expect(theme).toBe('light'); |
|
|
| const bg = await page.evaluate(() => |
| getComputedStyle(document.documentElement).getPropertyValue('--bg').trim(), |
| ); |
| expect(bg).toBe('#FAFAF5'); |
| }); |
|
|
| test('dark mode persists across page reload', async ({ page }) => { |
| await page.goto('/'); |
| await page.waitForSelector('#headerThemeToggle', { timeout: 15000 }); |
|
|
| |
| await page.click('#headerThemeToggle'); |
| await page.waitForTimeout(200); |
| expect(await page.evaluate(() => document.documentElement.dataset.theme)).toBe('dark'); |
|
|
| |
| const stored = await page.evaluate(() => localStorage.getItem('worldmonitor-theme')); |
| expect(stored).toBe('dark'); |
|
|
| |
| await page.reload(); |
| await page.waitForSelector('#headerThemeToggle', { timeout: 15000 }); |
|
|
| |
| const theme = await page.evaluate(() => document.documentElement.dataset.theme); |
| expect(theme).toBe('dark'); |
|
|
| const bg = await page.evaluate(() => |
| getComputedStyle(document.documentElement).getPropertyValue('--bg').trim(), |
| ); |
| expect(bg).toBe('#1A2332'); |
| }); |
|
|
| test('theme toggle icon updates correctly', async ({ page }) => { |
| await page.goto('/'); |
| await page.waitForSelector('#headerThemeToggle', { timeout: 15000 }); |
|
|
| |
| const lightIcon = await page.locator('#headerThemeToggle svg path').count(); |
| |
| const hasMoon = lightIcon > 0; |
| expect(hasMoon).toBe(true); |
|
|
| |
| await page.click('#headerThemeToggle'); |
| await page.waitForTimeout(200); |
|
|
| |
| const hasSun = await page.locator('#headerThemeToggle svg circle').count(); |
| expect(hasSun).toBeGreaterThan(0); |
| }); |
|
|
| test('panel backgrounds update on theme toggle', async ({ page }) => { |
| await page.goto('/'); |
| await page.waitForSelector('.panel', { timeout: 20000 }); |
|
|
| |
| const lightPanelBg = await page.evaluate(() => |
| getComputedStyle(document.documentElement).getPropertyValue('--panel-bg').trim(), |
| ); |
| expect(lightPanelBg).toBe('#FFFFFF'); |
|
|
| |
| await page.click('#headerThemeToggle'); |
| await page.waitForTimeout(300); |
|
|
| |
| const darkPanelBg = await page.evaluate(() => |
| getComputedStyle(document.documentElement).getPropertyValue('--panel-bg').trim(), |
| ); |
| expect(darkPanelBg).toBe('#222E3E'); |
| }); |
|
|
| test('no FOUC: data-theme is set before main CSS loads', async ({ page }) => { |
| |
| await page.addInitScript(() => { |
| localStorage.setItem('worldmonitor-theme', 'dark'); |
| localStorage.setItem('worldmonitor-variant', 'happy'); |
| }); |
|
|
| await page.goto('/'); |
|
|
| |
| |
| const theme = await page.evaluate(() => document.documentElement.dataset.theme); |
| expect(theme).toBe('dark'); |
| }); |
|
|
| test('screenshot comparison: light vs dark', async ({ page }) => { |
| await page.goto('/'); |
| await page.waitForSelector('.panel', { timeout: 20000 }); |
| await page.waitForTimeout(2000); |
|
|
| |
| await page.screenshot({ path: '/tmp/happy-light.png', fullPage: false }); |
|
|
| |
| await page.click('#headerThemeToggle'); |
| await page.waitForTimeout(1000); |
|
|
| |
| await page.screenshot({ path: '/tmp/happy-dark.png', fullPage: false }); |
| }); |
| }); |
|
|