|
| 1 | +import { describe, expect, test } from 'vitest' |
| 2 | + |
| 3 | +import { colorModeScript } from '../lib/color-mode-script' |
| 4 | +import { getCssTheme } from '../components/useTheme' |
| 5 | + |
| 6 | +// The inline script can't import the React `useTheme` module at runtime (it |
| 7 | +// runs before any bundle loads), so it reimplements the same validation. These |
| 8 | +// tests run the script against a fake `document` and assert it produces the |
| 9 | +// exact same result as `getCssTheme`, which keeps the two in sync. |
| 10 | +function runScript(rawCookie: string) { |
| 11 | + const attrs: Record<string, string> = {} |
| 12 | + const fakeDocument = { |
| 13 | + cookie: rawCookie, |
| 14 | + documentElement: { |
| 15 | + setAttribute(name: string, value: string) { |
| 16 | + attrs[name] = value |
| 17 | + }, |
| 18 | + }, |
| 19 | + } |
| 20 | + new Function('document', colorModeScript)(fakeDocument) |
| 21 | + return attrs |
| 22 | +} |
| 23 | + |
| 24 | +function cookieFor(value: object) { |
| 25 | + // The real cookie value is URL-encoded JSON, like the browser stores it. |
| 26 | + return `color_mode=${encodeURIComponent(JSON.stringify(value))}` |
| 27 | +} |
| 28 | + |
| 29 | +function expectMatchesGetCssTheme(rawCookie: string, cookieValue: string) { |
| 30 | + const css = getCssTheme(cookieValue) |
| 31 | + expect(runScript(rawCookie)).toEqual({ |
| 32 | + 'data-color-mode': css.colorMode, |
| 33 | + 'data-light-theme': css.lightTheme, |
| 34 | + 'data-dark-theme': css.darkTheme, |
| 35 | + }) |
| 36 | +} |
| 37 | + |
| 38 | +describe('colorModeScript', () => { |
| 39 | + test('falls back to defaults when no cookie is set', () => { |
| 40 | + expectMatchesGetCssTheme('', '') |
| 41 | + }) |
| 42 | + |
| 43 | + test('falls back to defaults on junk cookie values', () => { |
| 44 | + expectMatchesGetCssTheme('color_mode=not-valid-json', '') |
| 45 | + }) |
| 46 | + |
| 47 | + test('respects a valid color_mode cookie', () => { |
| 48 | + const value = { |
| 49 | + color_mode: 'dark', |
| 50 | + light_theme: { name: 'light_colorblind', color_mode: 'light' }, |
| 51 | + dark_theme: { name: 'dark_tritanopia', color_mode: 'dark' }, |
| 52 | + } |
| 53 | + expectMatchesGetCssTheme(cookieFor(value), JSON.stringify(value)) |
| 54 | + }) |
| 55 | + |
| 56 | + test('honors supported named themes', () => { |
| 57 | + const value = { |
| 58 | + color_mode: 'auto', |
| 59 | + light_theme: { name: 'light', color_mode: 'light' }, |
| 60 | + dark_theme: { name: 'dark_dimmed', color_mode: 'dark' }, |
| 61 | + } |
| 62 | + expectMatchesGetCssTheme(cookieFor(value), JSON.stringify(value)) |
| 63 | + }) |
| 64 | + |
| 65 | + test('ignores unknown modes and themes', () => { |
| 66 | + const value = { |
| 67 | + color_mode: 'sepia', |
| 68 | + light_theme: { name: 'rainbow', color_mode: 'rainbow' }, |
| 69 | + dark_theme: { name: 'midnight', color_mode: 'midnight' }, |
| 70 | + } |
| 71 | + expectMatchesGetCssTheme(cookieFor(value), JSON.stringify(value)) |
| 72 | + }) |
| 73 | + |
| 74 | + test('reads the cookie even when other cookies are present', () => { |
| 75 | + const value = { color_mode: 'light' } |
| 76 | + const rawCookie = `_octo=GH1.1; color_mode=${encodeURIComponent( |
| 77 | + JSON.stringify(value), |
| 78 | + )}; logged_in=no` |
| 79 | + expectMatchesGetCssTheme(rawCookie, JSON.stringify(value)) |
| 80 | + }) |
| 81 | +}) |
0 commit comments