| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 |
- // @vitest-environment jsdom
- /**
- * App-shell assembly plugin on the real machinery: bare Context + production
- * SlotsService + the test-runtime session/workspace doubles. Deliberately NOT
- * mounted through SlotTestRuntime — its create() installs the capturing
- * renderer and install() is boot-once; app-shell IS the production installer,
- * so this bench hands it the uninstalled service exactly as boot does.
- */
- import { afterEach, describe, expect, it, vi } from 'vitest'
- import { act, cleanup, render } from '@testing-library/react'
- import { Context } from 'cordis'
- import { SlotsService } from '@deepseek-ai/dsh-client-runtime/client'
- import { TestSessions, TestWorkspaces } from '@deepseek-ai/dsh-client-test-runtime'
- import type { Stabilizer } from '@deepseek-ai/dsh-client-test-runtime'
- import * as AppShell from '@deepseek-ai/dsh-client-web/src/app-shell.ts'
- afterEach(cleanup)
- const stabilize: Stabilizer = async (fn) => { await act(async () => { await fn() }) }
- async function bench() {
- const ctx = new Context()
- await ctx.plugin(SlotsService).await()
- const slots = ctx.get('slots') as SlotsService
- ctx.provide('sessions', new TestSessions(stabilize, ctx))
- ctx.provide('workspaces', new TestWorkspaces(stabilize))
- ctx.provide('layout', { openDetails: vi.fn(), closeDetails: vi.fn() })
- const fiber = ctx.plugin({ inject: [...AppShell.inject], apply: AppShell.apply })
- await fiber.await()
- return { ctx, slots, fiber }
- }
- describe('app-shell assembly plugin', () => {
- it('installs the renderer and provides the assembled appShell face', async () => {
- const { ctx, slots } = await bench()
- slots.register({ name: 'root' }, () => <div data-testid="root-probe" />)
- const shell = ctx.get('appShell')
- expect(shell).toBeDefined()
- const view = render(<>{shell!.renderApp()}</>)
- expect(view.getByTestId('root-probe')).toBeTruthy()
- })
- it('assembles once: repeated renderApp calls reuse the built closure', async () => {
- const { ctx, slots } = await bench()
- slots.register({ name: 'root' }, () => <div data-testid="root-probe" />)
- const shell = ctx.get('appShell')!
- const first = render(<>{shell.renderApp()}</>)
- expect(first.getByTestId('root-probe')).toBeTruthy()
- first.unmount()
- // Second call rides the cached closure (renderApp ??=) and still renders.
- const second = render(<>{shell.renderApp()}</>)
- expect(second.getByTestId('root-probe')).toBeTruthy()
- })
- it('fiber dispose retracts the service and uninstalls the renderer', async () => {
- const { ctx, slots, fiber } = await bench()
- await stabilize(() => fiber.dispose())
- expect(ctx.get('appShell')).toBeUndefined()
- expect(() => slots.renderSlot('root', {})).toThrow('not installed')
- })
- })
|