mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
bindSettingsScope mirrors the Host-side settings owner seam in the browser: one scope per namespace publishes a snapshot store (status, section value, revision, writability, host/memory mode), validates sections against the namespace's serialized wire schema via dsh-client-schema-form, and keeps the controller's listener-before-read, revisioned serialized writes, latest-wins publication, conflict recovery, and disposal quiescence. Theme, locale, and busy-Enter services now take the scope as a constructor collaborator, which removes the bindPersistence/syncPreference two-phase callback pair and the defaulted no-op persist writers; hand-written wire guards fall away in favor of the registered schema. test-runtime gains a stubSettingsScope double.
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
/** Test double for the client settings-scope seam. */
|
|
import { vi } from 'vitest'
|
|
import type { SettingsScope, SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-runtime/client'
|
|
|
|
/** Handle over one stubbed scope: the scope, its write spy, and publication controls. */
|
|
export interface StubSettingsScope<T> {
|
|
/** The scope face handed to the service under test. */
|
|
scope: SettingsScope<T>
|
|
/** Spy behind `scope.set`; resolves immediately. */
|
|
set: ReturnType<typeof vi.fn>
|
|
/** @returns how many listeners are currently subscribed (disposal assertions). */
|
|
listenerCount(): number
|
|
/**
|
|
* Replace part of the snapshot and notify subscribers, as a Host
|
|
* acceptance would.
|
|
* @param next - snapshot fields to replace.
|
|
*/
|
|
publish(next: Partial<SettingsScopeSnapshot<T>>): void
|
|
}
|
|
|
|
/**
|
|
* Build an in-memory settings scope for service specs: starts in the host
|
|
* loading state, records writes, and lets the test publish Host acceptances.
|
|
* @returns the stub handle.
|
|
*/
|
|
export function stubSettingsScope<T>(): StubSettingsScope<T> {
|
|
let snapshot: SettingsScopeSnapshot<T> = {
|
|
status: 'loading', value: undefined, revision: undefined, writable: false, mode: 'host',
|
|
}
|
|
const listeners = new Set<() => void>()
|
|
const set = vi.fn(() => Promise.resolve())
|
|
return {
|
|
scope: {
|
|
getSnapshot: () => snapshot,
|
|
subscribe: (listener) => {
|
|
listeners.add(listener)
|
|
return () => { listeners.delete(listener) }
|
|
},
|
|
set,
|
|
},
|
|
set,
|
|
listenerCount: () => listeners.size,
|
|
publish: (next) => {
|
|
snapshot = { ...snapshot, ...next }
|
|
for (const listener of [...listeners]) listener()
|
|
},
|
|
}
|
|
}
|