| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 |
- /** 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()
- },
- }
- }
|