Merge remote-tracking branch 'origin/master' into feat/web-message-feedback-ui
Adapt to two contract changes master introduced: - The generated Remote face now wraps every business result in RemoteResult, folding carrier failures into an ok:false branch instead of rejecting. The controller reads that envelope at its three call sites and maps a carrier failure onto the same settled shape the controls already render; three specs cover the new branch. - Client packages split their tsconfig into host and client halves, and the host aggregate now compiles any test not named *.client.spec.*. Rename this package's specs to the client convention and drop the ../connection project reference, which pointed at a solution file that no longer carries the client sources. Keep master's mount loop with its rollback-on-failure in api-remotes and add messageFeedbackRemote to it.
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
// @vitest-environment jsdom
|
||||
/** Host index injection and the resulting pre-plugin browser theme. */
|
||||
import { runInNewContext } from 'node:vm'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { injectBootTheme } 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,
|
||||
html = '<html><body><div id="root"></div><script type="module"></script></body></html>',
|
||||
): string {
|
||||
const injected = injectBootTheme(html, preference)
|
||||
const source = /<script>([\s\S]*?)<\/script>/.exec(injected)?.[1]
|
||||
if (source === undefined) throw new Error('theme bootstrap script missing')
|
||||
runInNewContext(source, { document, matchMedia: globalThis.matchMedia })
|
||||
return injected
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
vi.unstubAllGlobals()
|
||||
document.documentElement.style.removeProperty('color-scheme')
|
||||
document.body.removeAttribute(DARK_ATTRIBUTE)
|
||||
})
|
||||
|
||||
describe('theme boot index transform', () => {
|
||||
it('runs immediately inside the body before the shell mount', () => {
|
||||
mockSystemDark(false)
|
||||
const html = executeBootstrap('dark', '<html><body class="app"><div id="root"></div></body></html>')
|
||||
expect(html.indexOf('<script>')).toBeGreaterThan(html.indexOf('<body class="app">'))
|
||||
expect(html.indexOf('<script>')).toBeLessThan(html.indexOf('<div id="root">'))
|
||||
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)
|
||||
})
|
||||
|
||||
it('appends the script to a body-less fragment', () => {
|
||||
const html = injectBootTheme('<main>loading</main>', 'dark')
|
||||
expect(html.startsWith('<main>loading</main><script>')).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user