// @vitest-environment jsdom /** First-run DeepSeek prompt behavior over the shared Models join. */ import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react' import { afterEach, describe, expect, it, vi } from 'vitest' import Schema from '@deepseek-ai/schemastery' import type { RpcResponse, SettingsNamespaceView } from '@deepseek-ai/dsh-api-remotes/client' import { bindSnapshotSelector } from '@deepseek-ai/dsh-client-web-react' import { DeepSeekOnboardingDialog } from '../src/client/DeepSeekOnboardingDialog.tsx' import type { DeepSeekOnboardingDialogProps } from '../src/client/DeepSeekOnboardingDialog.tsx' import { ModelsSettingsStore } from '../src/client/store.ts' import { en } from '../src/client/locales.ts' afterEach(() => { cleanup() document.getElementById('root')?.remove() }) let nextRpc = 0 function ok(value: T): RpcResponse { return { rpcId: `onboarding-${nextRpc++}` as never, result: { ok: true, value } } } function fail(message: string): RpcResponse { return { rpcId: `onboarding-${nextRpc++}` as never, result: { ok: false, error: { code: 'internal', message, details: {} } }, } } const DeepSeekConfig = Schema.object({ apiKeyEnv: Schema.string().role('credential-ref'), baseURL: Schema.string().pattern(/^https:\/\//), reasoningEffort: Schema.union(['off', 'high', 'max']), defaultContextWindow: Schema.number().step(1).min(1), models: Schema.array(Schema.object({ id: Schema.string().required(), name: Schema.string(), description: Schema.string(), contextWindow: Schema.number().step(1).min(1), })), }) function deepSeekNamespace(apiKeyEnv: string | null): SettingsNamespaceView { const value = apiKeyEnv === null ? {} : { apiKeyEnv } return { ns: 'llm-deepseek', schema: JSON.parse(JSON.stringify(DeepSeekConfig.toJSON())) as unknown, value, base: value, user: {}, applies: 'live', secrets: [], revision: 0, } } function harness(options: { provider?: boolean providerSettingsNs?: string providerActive?: boolean settingsNamespace?: boolean apiKeyEnv?: string | null configured?: () => boolean credential?: { source?: string; writable: boolean } describeFailure?: string settingsWritable?: boolean providersReject?: boolean setFailure?: string setReject?: string } = {}) { if (document.getElementById('root') === null) { const appRoot = document.createElement('div') appRoot.id = 'root' document.body.append(appRoot) } let fileConfigured = false const configured = options.configured ?? (() => fileConfigured) const apiKeyEnv = options.apiKeyEnv === undefined ? 'DEEPSEEK_API_KEY' : options.apiKeyEnv const mutate = vi.fn(() => Promise.resolve(ok(deepSeekNamespace(apiKeyEnv)))) const set = vi.fn((_payload: { ref: string; value: string }) => { if (options.setReject !== undefined) return Promise.reject(new Error(options.setReject)) if (options.setFailure !== undefined) return Promise.resolve(fail(options.setFailure)) fileConfigured = true return Promise.resolve(ok({})) }) const face = { llm: { providers: () => { if (options.providersReject === true) return Promise.reject(new Error('provider transport unavailable')) return Promise.resolve(ok({ providers: options.provider === false ? [] : [{ provider: 'deepseek-official', displayName: 'DeepSeek', settingsNs: options.providerSettingsNs ?? 'llm-deepseek', settingsPath: [], active: options.providerActive ?? true, }], })) }, }, settings: { describe: () => Promise.resolve(ok({ writable: options.settingsWritable ?? true, hasDocument: false, namespaces: options.settingsNamespace === false ? [] : [deepSeekNamespace(apiKeyEnv)], })), mutate, }, credentials: { describe: () => options.describeFailure === undefined ? Promise.resolve(ok({ credentials: { DEEPSEEK_API_KEY: { configured: configured(), ...configured() && options.credential?.source !== undefined ? { source: options.credential.source } : {}, writable: options.credential?.writable ?? true, }, }, })) : Promise.resolve(fail(options.describeFailure)), set, }, } const controller = new ModelsSettingsStore(face as never) const openSection = vi.fn() const complete = vi.fn() const unusedHook = (() => { throw new Error('unused standard hook') }) as never const props: DeepSeekOnboardingDialogProps = { stepId: 'deepseek-official', complete, openSection, useSessions: unusedHook, useWorkspaces: unusedHook, controller, useModels: bindSnapshotSelector(controller.store), api: face as never, t: key => en[key], } return { controller, complete, openSection, props, mutate, set, configure: () => { fileConfigured = true }, } } describe('DeepSeekOnboardingDialog', () => { it('renders when the shell root is absent', async () => { const h = harness() document.getElementById('root')!.remove() render() expect(await screen.findByRole('dialog', { name: en.onboardingTitle })).toBeTruthy() }) it('loads a credential-only modal, inerts the product, and focuses the key', async () => { const h = harness() render() expect(await screen.findByRole('dialog', { name: en.onboardingTitle })).toBeTruthy() expect(document.getElementById('root')?.inert).toBe(true) expect(screen.getByText(en.onboardingDescription)).toBeTruthy() const key = screen.getByLabelText(en.keyInput) await waitFor(() => { expect(document.activeElement).toBe(key) }) expect(screen.queryByText(en.customized)).toBeNull() }) it('cannot be dismissed implicitly and restores the previous inert state', async () => { const h = harness() const appRoot = document.getElementById('root')! appRoot.inert = true const view = render() await screen.findByRole('dialog') fireEvent.keyDown(document, { key: 'Escape' }) fireEvent.click(document.querySelector('[class*="mask"]')!) expect(screen.getByRole('dialog')).toBeTruthy() expect(h.complete).not.toHaveBeenCalled() view.unmount() expect(appRoot.inert).toBe(true) }) it('requires a non-blank key before Save and continue is available', async () => { const h = harness() render() await screen.findByRole('dialog') const save = screen.getByRole('button', { name: en.onboardingSave }) expect(save.disabled).toBe(true) fireEvent.change(screen.getByLabelText(en.keyInput), { target: { value: ' ' } }) expect(save.disabled).toBe(true) expect(screen.getByText(en.keyRequired)).toBeTruthy() expect(h.set).not.toHaveBeenCalled() }) it('keeps the modal open and reports rejected and failed credential writes', async () => { for (const [options, message] of [ [{ setFailure: 'credential was rejected' }, 'credential was rejected'], [{ setReject: 'connection lost' }, 'connection lost'], ] as const) { const h = harness(options) const view = render() await screen.findByRole('dialog') fireEvent.change(screen.getByLabelText(en.keyInput), { target: { value: 'sk-live' } }) fireEvent.click(screen.getByRole('button', { name: en.onboardingSave })) expect(await screen.findByText(message)).toBeTruthy() expect(screen.getByRole('dialog')).toBeTruthy() expect(screen.getByRole('button', { name: en.onboardingSave }).disabled).toBe(false) expect(h.complete).not.toHaveBeenCalled() expect(h.mutate).not.toHaveBeenCalled() view.unmount() } }) it('allows configure-later dismissal without opening settings', async () => { const h = harness() render() await screen.findByRole('dialog') fireEvent.click(screen.getByRole('button', { name: en.onboardingLater })) expect(h.complete).toHaveBeenCalledOnce() expect(h.openSection).not.toHaveBeenCalled() expect(h.set).not.toHaveBeenCalled() expect(h.mutate).not.toHaveBeenCalled() }) it('does not block the product when DeepSeek setup is unavailable', async () => { for (const h of [ harness({ describeFailure: 'credentials service is absent' }), harness({ credential: { writable: false } }), harness({ settingsWritable: false }), harness({ providersReject: true }), harness({ providerActive: false }), harness({ settingsNamespace: false }), harness({ apiKeyEnv: null }), ]) { const view = render() await act(async () => { await h.controller.load() }) expect(screen.queryByRole('dialog')).toBeNull() await waitFor(() => { expect(h.complete).toHaveBeenCalledOnce() }) expect(h.openSection).not.toHaveBeenCalled() view.unmount() } }) it('skips an absent adapter and an already-configured environment credential', async () => { for (const h of [ harness({ provider: false }), harness({ providerSettingsNs: '' }), harness({ configured: () => true, credential: { source: 'env', writable: false } }), ]) { const view = render() await act(async () => { await h.controller.load() }) expect(screen.queryByRole('dialog')).toBeNull() await waitFor(() => { expect(h.complete).toHaveBeenCalledOnce() }) view.unmount() } }) it('closes when an external credential invalidation refreshes the shared join', async () => { const h = harness() render() await screen.findByRole('dialog') h.configure() await act(async () => { await h.controller.load() }) await waitFor(() => { expect(screen.queryByRole('dialog')).toBeNull() }) expect(h.complete).toHaveBeenCalledOnce() }) })