Files
deepseek-harness/packages/client/ui-theme/tests/boot-theme.client.spec.ts
T
imccyu 156bd075a9 feat(webserver): structured index injection table and the client boot seams
Replace per-plugin tapIndex regex edits with pure-data IndexInjection rows
collected fresh per render over one webserver/index-inject event. One table,
two renderers: the served form renders rows into index.html; a static worker
form ships the same rows over its boot payload. tapIndex survives as the
raw-HTML escape hatch, applied after row rendering; client-modules and
ui-theme move to the event, and the manifest global renders as
globalThis["__DSH_BOOT__"].

The client boot chain gains the seams a pre-injected transport needs: the
module loader takes loadBundle from the transport global by default, HTTP
prefetch stands down when a transport owns bundle bytes, the web-app bundle
can decline frontend serving, the gateway client installs a namespace's
whole method group inside its fiber apply so a parked dependent never
observes the service without its methods, and the dynamic-code precheck
gates through new Function so hosts without a real node:vm keep the
define-time parse gate.
2026-08-20 16:13:04 +08:00

62 lines
2.3 KiB
TypeScript

// @vitest-environment jsdom
/** The theme bootstrap injection row and the resulting pre-plugin browser theme. */
import { runInNewContext } from 'node:vm'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { bootThemeInjection } from '../src/boot-theme.ts'
import type { ThemePreference } from '../src/theme-settings.ts'
const DARK_ATTRIBUTE = 'data-ds-dark-theme'
function mockSystemDark(matches: boolean): void {
vi.stubGlobal('matchMedia', vi.fn(() => ({ matches }) as MediaQueryList))
}
function executeBootstrap(preference?: ThemePreference): void {
const row = bootThemeInjection(preference)
if (row.kind !== 'script') throw new Error('theme bootstrap row is not a script')
runInNewContext(row.text, { document, matchMedia: globalThis.matchMedia })
}
afterEach(() => {
vi.restoreAllMocks()
vi.unstubAllGlobals()
document.documentElement.style.removeProperty('color-scheme')
document.body.removeAttribute(DARK_ATTRIBUTE)
})
describe('theme bootstrap row', () => {
it('is a body script row, so it runs before the shell mount', () => {
mockSystemDark(false)
const row = bootThemeInjection('dark')
expect(row).toMatchObject({ kind: 'script', placement: 'body' })
executeBootstrap('dark')
expect(document.documentElement.style.colorScheme).toBe('dark')
expect(document.body.hasAttribute(DARK_ATTRIBUTE)).toBe(true)
})
it('lets durable light override a dark OS and clears stale dark state', () => {
document.body.setAttribute(DARK_ATTRIBUTE, '')
mockSystemDark(true)
executeBootstrap('light')
expect(document.documentElement.style.colorScheme).toBe('light')
expect(document.body.hasAttribute(DARK_ATTRIBUTE)).toBe(false)
})
it.each([
[true, 'dark', true],
[false, 'light', false],
] as const)('resolves system=%s to %s', (matches, colorScheme, dark) => {
mockSystemDark(matches)
executeBootstrap('system')
expect(document.documentElement.style.colorScheme).toBe(colorScheme)
expect(document.body.hasAttribute(DARK_ATTRIBUTE)).toBe(dark)
})
it('defaults to system and falls back to light when matchMedia is unavailable', () => {
vi.stubGlobal('matchMedia', undefined)
executeBootstrap()
expect(document.documentElement.style.colorScheme).toBe('light')
expect(document.body.hasAttribute(DARK_ATTRIBUTE)).toBe(false)
})
})