fix(web): address settings document review
This commit is contained in:
@@ -39,7 +39,7 @@ async function bench(isLoopback = true) {
|
||||
ok: true as const,
|
||||
value: {
|
||||
writable: true,
|
||||
documentPath: '/tmp/test-settings.yaml',
|
||||
hasDocument: true,
|
||||
namespaces: [{
|
||||
ns: WELCOME_NOTICE_SETTINGS_NAMESPACE,
|
||||
schema: {},
|
||||
@@ -175,10 +175,25 @@ describe('ui-settings-general apply', () => {
|
||||
await vi.waitFor(() => { expect(b.settingsDescribe).toHaveBeenCalledTimes(3) })
|
||||
})
|
||||
|
||||
it('refreshes loaded document availability on reconnect without reading it eagerly', async () => {
|
||||
const b = await bench()
|
||||
declare(b.slots)
|
||||
await b.ctx.plugin({ inject: [...inject], apply }).await()
|
||||
const entry = b.slots.entries('settings.action')[0]!
|
||||
const { controller } = (entry.inject as unknown as () => SettingsDocumentActionInjected)()
|
||||
b.ctx.emit('connection/reset')
|
||||
expect(b.settingsDescribe).not.toHaveBeenCalled()
|
||||
await controller.load()
|
||||
expect(b.settingsDescribe).toHaveBeenCalledOnce()
|
||||
b.ctx.emit('connection/reset')
|
||||
await vi.waitFor(() => { expect(b.settingsDescribe).toHaveBeenCalledTimes(2) })
|
||||
})
|
||||
|
||||
it('keeps remote welcome acknowledgement process-local', async () => {
|
||||
const b = await bench(false)
|
||||
declare(b.slots)
|
||||
await b.ctx.plugin({ inject: [...inject], apply }).await()
|
||||
const fiber = b.ctx.plugin({ inject: [...inject], apply })
|
||||
await fiber.await()
|
||||
const entry = b.slots.entries('settings.onboarding')[0]!
|
||||
const { controller } = (entry.inject as unknown as () => WelcomeNoticeInjected)()
|
||||
|
||||
@@ -187,6 +202,8 @@ describe('ui-settings-general apply', () => {
|
||||
expect(controller.store.getSnapshot()).toMatchObject({ status: 'ready', acknowledged: true })
|
||||
expect(b.settingsDescribe).not.toHaveBeenCalled()
|
||||
expect(b.slots.entries('settings.action')).toEqual([])
|
||||
await fiber.dispose()
|
||||
for (const [name] of SEATS) expect(b.slots.entries(name)).toEqual([])
|
||||
})
|
||||
|
||||
it('re-registers after an HMR collapse of the declaring chain (stale disposers must not block)', async () => {
|
||||
|
||||
@@ -70,7 +70,7 @@ describe('SettingsDocumentAction', () => {
|
||||
rpcId: 'document-action' as never,
|
||||
result: {
|
||||
ok: true as const,
|
||||
value: { writable: true, documentPath: '/tmp/custom.yaml', namespaces: [] },
|
||||
value: { writable: true, hasDocument: true, namespaces: [] },
|
||||
},
|
||||
})),
|
||||
openDocument,
|
||||
@@ -87,17 +87,23 @@ describe('SettingsDocumentAction', () => {
|
||||
await waitFor(() => { expect(openDocument).toHaveBeenCalledWith({}) })
|
||||
})
|
||||
|
||||
it('stays absent when the provider has no local document', async () => {
|
||||
it('stays absent without a document and retries availability after remount', async () => {
|
||||
const describe = vi.fn()
|
||||
.mockResolvedValueOnce({
|
||||
rpcId: 'document-action-absent' as never,
|
||||
result: { ok: true as const, value: { writable: true, hasDocument: false, namespaces: [] } },
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
rpcId: 'document-action-ready' as never,
|
||||
result: { ok: true as const, value: { writable: true, hasDocument: true, namespaces: [] } },
|
||||
})
|
||||
const controller = new SettingsDocumentStore({
|
||||
settings: {
|
||||
describe: vi.fn(() => Promise.resolve({
|
||||
rpcId: 'document-action' as never,
|
||||
result: { ok: true as const, value: { writable: true, namespaces: [] } },
|
||||
})),
|
||||
describe,
|
||||
openDocument: vi.fn(),
|
||||
},
|
||||
} as never)
|
||||
render(<SettingsDocumentAction
|
||||
const first = render(<SettingsDocumentAction
|
||||
{...kit}
|
||||
t={t}
|
||||
controller={controller}
|
||||
@@ -105,6 +111,15 @@ describe('SettingsDocumentAction', () => {
|
||||
/>)
|
||||
await waitFor(() => { expect(controller.store.getSnapshot().status).toBe('unavailable') })
|
||||
expect(screen.queryByRole('button', { name: 'Open configuration file' })).toBeNull()
|
||||
first.unmount()
|
||||
render(<SettingsDocumentAction
|
||||
{...kit}
|
||||
t={t}
|
||||
controller={controller}
|
||||
useSnapshot={bindSnapshotSelector(controller.store)}
|
||||
/>)
|
||||
expect(await screen.findByRole('button', { name: 'Open configuration file' })).toBeTruthy()
|
||||
expect(describe).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('keeps the action available and reports a native-open failure', async () => {
|
||||
@@ -114,7 +129,7 @@ describe('SettingsDocumentAction', () => {
|
||||
rpcId: 'document-action' as never,
|
||||
result: {
|
||||
ok: true as const,
|
||||
value: { writable: true, documentPath: '/tmp/settings.yaml', namespaces: [] },
|
||||
value: { writable: true, hasDocument: true, namespaces: [] },
|
||||
},
|
||||
})),
|
||||
openDocument: vi.fn(() => Promise.resolve({
|
||||
|
||||
@@ -2,16 +2,16 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
import type { RpcResponse } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import { SettingsDocumentStore } from '../src/client/settings-document-store.ts'
|
||||
|
||||
function response(documentPath?: string): RpcResponse<{
|
||||
function response(hasDocument = false): RpcResponse<{
|
||||
writable: boolean
|
||||
documentPath?: string
|
||||
hasDocument: boolean
|
||||
namespaces: []
|
||||
}> {
|
||||
return {
|
||||
rpcId: 'settings-document' as never,
|
||||
result: {
|
||||
ok: true,
|
||||
value: { writable: true, ...documentPath === undefined ? {} : { documentPath }, namespaces: [] },
|
||||
value: { writable: true, hasDocument, namespaces: [] },
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ function describeFailed(message: string): RpcResponse<never> {
|
||||
|
||||
describe('SettingsDocumentStore', () => {
|
||||
it('loads provider metadata and asks the settings domain to open its document', async () => {
|
||||
const describe = vi.fn(() => Promise.resolve(response('/home/test/settings.yaml')))
|
||||
const describe = vi.fn(() => Promise.resolve(response(true)))
|
||||
const openDocument = vi.fn(() => Promise.resolve(opened()))
|
||||
const controller = new SettingsDocumentStore({ settings: { describe, openDocument } } as never)
|
||||
await controller.load()
|
||||
@@ -72,7 +72,7 @@ describe('SettingsDocumentStore', () => {
|
||||
let resolveOpen!: (response: RpcResponse<{ opened: true }>) => void
|
||||
const openDocument = vi.fn(() => new Promise<RpcResponse<{ opened: true }>>((resolve) => { resolveOpen = resolve }))
|
||||
const controller = new SettingsDocumentStore({
|
||||
settings: { describe: () => Promise.resolve(response('/tmp/settings.yaml')), openDocument },
|
||||
settings: { describe: () => Promise.resolve(response(true)), openDocument },
|
||||
} as never)
|
||||
await controller.load()
|
||||
const first = controller.open()
|
||||
@@ -93,7 +93,7 @@ describe('SettingsDocumentStore', () => {
|
||||
const first = new Promise<ReturnType<typeof response>>((resolve) => { resolveFirst = resolve })
|
||||
const describe = vi.fn()
|
||||
.mockReturnValueOnce(first)
|
||||
.mockResolvedValueOnce(response('/tmp/current.yaml'))
|
||||
.mockResolvedValueOnce(response(true))
|
||||
let rejectOpen!: (reason?: unknown) => void
|
||||
const controller = new SettingsDocumentStore({
|
||||
settings: {
|
||||
@@ -119,7 +119,7 @@ describe('SettingsDocumentStore', () => {
|
||||
settings: {
|
||||
describe: vi.fn()
|
||||
.mockReturnValueOnce(rejectedFirst)
|
||||
.mockResolvedValueOnce(response('/tmp/current.yaml')),
|
||||
.mockResolvedValueOnce(response(true)),
|
||||
openDocument: vi.fn(),
|
||||
},
|
||||
} as never)
|
||||
|
||||
@@ -23,6 +23,7 @@ function mount(version?: string, mutateImpl: () => Promise<unknown> = () => Prom
|
||||
settings: {
|
||||
describe: () => Promise.resolve(response({
|
||||
writable: true,
|
||||
hasDocument: false,
|
||||
namespaces: [{
|
||||
ns: WELCOME_NOTICE_SETTINGS_NAMESPACE,
|
||||
schema: {},
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('WelcomeNoticeStore', () => {
|
||||
] as const) {
|
||||
const api = {
|
||||
settings: {
|
||||
describe: vi.fn(() => Promise.resolve(ok({ writable: true, namespaces: [namespace(version)] }))),
|
||||
describe: vi.fn(() => Promise.resolve(ok({ writable: true, hasDocument: false, namespaces: [namespace(version)] }))),
|
||||
},
|
||||
}
|
||||
const controller = new WelcomeNoticeStore(api as never)
|
||||
@@ -101,7 +101,7 @@ describe('WelcomeNoticeStore', () => {
|
||||
rpcId: 'failed' as never,
|
||||
result: { ok: false as const, error: { code: 'internal' as const, message: 'denied', details: {} } },
|
||||
}),
|
||||
() => Promise.resolve(ok({ writable: true, namespaces: [] })),
|
||||
() => Promise.resolve(ok({ writable: true, hasDocument: false, namespaces: [] })),
|
||||
]) {
|
||||
const controller = new WelcomeNoticeStore({ settings: { describe } } as never)
|
||||
await controller.load()
|
||||
@@ -112,6 +112,7 @@ describe('WelcomeNoticeStore', () => {
|
||||
const controller = new WelcomeNoticeStore({
|
||||
settings: { describe: () => Promise.resolve(ok({
|
||||
writable: true,
|
||||
hasDocument: false,
|
||||
namespaces: [{ ...namespace(), value }],
|
||||
})) },
|
||||
} as never)
|
||||
@@ -133,18 +134,20 @@ describe('WelcomeNoticeStore', () => {
|
||||
const first = deferred<ReturnType<typeof ok>>()
|
||||
const describe = vi.fn()
|
||||
.mockImplementationOnce(() => first.promise)
|
||||
.mockImplementationOnce(() => Promise.resolve(ok({ writable: true, namespaces: [namespace()] })))
|
||||
.mockImplementationOnce(() => Promise.resolve(ok({ writable: true, hasDocument: false, namespaces: [namespace()] })))
|
||||
const controller = new WelcomeNoticeStore({ settings: { describe } } as never)
|
||||
const stale = controller.load()
|
||||
await controller.load()
|
||||
first.resolve(ok({ writable: true, namespaces: [namespace(WELCOME_NOTICE_VERSION)] }))
|
||||
first.resolve(ok({ writable: true, hasDocument: false, namespaces: [namespace(WELCOME_NOTICE_VERSION)] }))
|
||||
await stale
|
||||
expect(controller.store.getSnapshot().acknowledged).toBe(false)
|
||||
|
||||
const failed = deferred<ReturnType<typeof ok>>()
|
||||
describe
|
||||
.mockImplementationOnce(() => failed.promise)
|
||||
.mockImplementationOnce(() => Promise.resolve(ok({ writable: true, namespaces: [namespace(WELCOME_NOTICE_VERSION)] })))
|
||||
.mockImplementationOnce(() => Promise.resolve(ok({
|
||||
writable: true, hasDocument: false, namespaces: [namespace(WELCOME_NOTICE_VERSION)],
|
||||
})))
|
||||
const staleFailure = controller.load()
|
||||
await controller.load()
|
||||
failed.reject('stale failure')
|
||||
@@ -154,7 +157,7 @@ describe('WelcomeNoticeStore', () => {
|
||||
|
||||
it('contains stale acknowledgement settlements and refreshes only a loaded store', async () => {
|
||||
const write = deferred<ReturnType<typeof ok>>()
|
||||
const describe = vi.fn(() => Promise.resolve(ok({ writable: true, namespaces: [namespace()] })))
|
||||
const describe = vi.fn(() => Promise.resolve(ok({ writable: true, hasDocument: false, namespaces: [namespace()] })))
|
||||
const controller = new WelcomeNoticeStore({
|
||||
settings: { mutate: () => write.promise, describe },
|
||||
} as never)
|
||||
|
||||
Reference in New Issue
Block a user