| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- import { Context } from '@deepseek-ai/cordis'
- import { afterEach, describe, expect, it, vi } from 'vitest'
- import { SlotRegistry } from '@deepseek-ai/dsh-client-ui-renderer/client'
- import type { SessionId } from '@deepseek-ai/dsh-session/types'
- import { LocaleRuntime } from '@deepseek-ai/dsh-client-locale/client'
- import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
- import { SessionLogDownloadHeaderAction } from '../src/client/HeaderAction.tsx'
- import { apply, inject } from '../src/client/index.ts'
- const SID = 'session-export-apply' as SessionId
- afterEach(() => { vi.unstubAllGlobals() })
- function declare(slots: SlotRegistry): () => void {
- return slots.register({
- name: 'root',
- children: {
- 'conversation.session.header.actions': { kind: 'list', scope: 'session' },
- 'conversation.session.header.utilities': { kind: 'list', scope: 'session' },
- },
- } as never, () => null)
- }
- async function bench() {
- const ctx = new Context()
- await ctx.plugin(SlotRegistry).await()
- const slots = ctx.get('slots') as SlotRegistry
- const declaration = declare(slots)
- ctx.provide('locale', new LocaleRuntime(ctx))
- const fiber = ctx.plugin({ inject: [...inject], apply })
- await fiber.await()
- return { ctx, slots, declaration, fiber }
- }
- describe('session-log-download browser plugin', () => {
- it('provides one controller and removes its Header contribution on disposal', async () => {
- vi.stubGlobal('fetch', vi.fn(async () => new Response('', { status: 500 })))
- const b = await bench()
- expect(inject).toEqual(['slots', 'locale'])
- expect(b.ctx.sessionLogDownload).toBeDefined()
- expect(b.slots.entries('conversation.session.header.actions')).toHaveLength(0)
- const entry = b.slots.entries('conversation.session.header.utilities')[0]
- expect(entry?.component).toBe(SessionLogDownloadHeaderAction)
- expect(entry?.options).toMatchObject({ id: 'session-log-download' })
- const injected = (entry?.inject as unknown as () => import('../src/client/Dialog.tsx').SessionLogDownloadDialogInjected)()
- await injected.request(SID)
- expect(b.ctx.sessionLogDownload.store.getSnapshot().bySession[SID]?.status).toBe('error')
- injected.dismiss(SID)
- expect(b.ctx.sessionLogDownload.store.getSnapshot().bySession[SID]?.open).toBe(false)
- await b.fiber.dispose()
- expect(b.slots.entries('conversation.session.header.utilities')).toHaveLength(0)
- })
- it('downloads only for an export execution acknowledged by this browser client', async () => {
- const fetcher = vi.fn(async () => new Response('', { status: 500 }))
- vi.stubGlobal('fetch', fetcher)
- const first = await bench()
- const second = await bench()
- first.ctx.emit('command/executed', SID, 'plan', { kind: 'success' })
- expect(fetcher).not.toHaveBeenCalled()
- first.ctx.emit('command/executed', SID, 'export', { kind: 'error', text: 'bad path' })
- expect(fetcher).not.toHaveBeenCalled()
- first.ctx.emit('command/executed', SID, 'export', { kind: 'success' })
- await vi.waitFor(() => {
- expect(fetcher).toHaveBeenCalledOnce()
- expect(first.ctx.sessionLogDownload.store.getSnapshot().bySession[SID]?.status).toBe('error')
- })
- expect(second.ctx.sessionLogDownload.store.getSnapshot().bySession[SID]).toBeUndefined()
- await first.fiber.dispose()
- await second.fiber.dispose()
- })
- it('re-registers after the declaring Header slot collapses and returns', async () => {
- const b = await bench()
- b.declaration()
- expect(b.slots.entries('conversation.session.header.utilities')).toHaveLength(0)
- const redeclare = declare(b.slots)
- await Promise.resolve()
- expect(b.slots.entries('conversation.session.header.utilities')[0]?.component).toBe(SessionLogDownloadHeaderAction)
- redeclare()
- await b.fiber.dispose()
- })
- })
|