# Conflicts: # apps/web/tests/expected/agent-preset-selection/header.expected.md # docs/architecture.i18n.yaml # docs/config-catalog.i18n.yaml # docs/config-catalog.md # docs/event-producer-consumer.i18n.yaml # docs/event-producer-consumer.md # docs/event-producer-consumer.zh.md # docs/module-graph.i18n.yaml # docs/module-graph.md # docs/module-graph.zh.md # docs/persistence-catalog.i18n.yaml # docs/persistence-catalog.md # docs/persistence-catalog.zh.md # docs/persistence-schema.json # docs/subsystems/web-client.i18n.yaml # packages/api/README.i18n.yaml # packages/api/README.md # packages/api/README.zh.md # packages/api/session-controller/README.i18n.yaml # packages/api/session-controller/README.md # packages/api/session-controller/README.zh.md # packages/api/session-controller/src/client/sessions/manager.ts # packages/api/session-controller/src/client/sessions/service.ts # packages/api/session-controller/tests/manager.client.spec.ts # packages/client/locale/tests/language-row.client.spec.tsx # packages/client/ui-chat/tests/chat-view.client.spec.tsx # packages/client/ui-chat/tests/transcript-view-row.client.spec.tsx # packages/client/ui-conversation/tests/conversation-registry.client.spec.ts # packages/client/ui-conversation/tests/enter-behavior-row.client.spec.tsx # packages/client/ui-conversation/tests/input-bar.client.spec.tsx # packages/client/ui-conversation/tests/input-matrix.client.spec.tsx # packages/client/ui-conversation/tests/input-scenarios.client.spec.tsx # packages/client/ui-conversation/tests/skeleton.client.spec.tsx # packages/client/ui-deliverables/tests/deliverables.client.spec.tsx # packages/client/ui-jobs/tests/job-list-action.client.spec.tsx # packages/client/ui-layout/tests/app-frame.client.spec.tsx # packages/client/ui-layout/tests/document-title.client.spec.tsx # packages/client/ui-open-in-app/tests/open-in-app-action.client.spec.tsx # packages/client/ui-primitives/README.i18n.yaml # packages/client/ui-session/tests/ui-session.client.spec.ts # packages/client/ui-settings-general/tests/settings-root.client.spec.tsx # packages/client/ui-settings-unarchive-sessions/tests/components.client.spec.tsx # packages/client/ui-subagent/README.i18n.yaml # packages/client/ui-subagent/README.md # packages/client/ui-subagent/README.zh.md # packages/client/ui-subagent/src/client/SubagentHeaderLineage.tsx # packages/client/ui-subagent/tests/conversation-ui.client.spec.tsx # packages/client/ui-theme/tests/appearance-row.client.spec.tsx # packages/client/ui-theme/tests/font-size-row.client.spec.tsx # packages/client/ui-tool/tests/coverage-tails.client.spec.tsx # packages/client/ui-tool/tests/diff-card.client.spec.tsx # packages/client/ui-tool/tests/image-card.client.spec.tsx # packages/client/ui-tool/tests/read-card.client.spec.tsx # packages/client/ui-tool/tests/terminal-card.client.spec.tsx # packages/client/ui-trajectory/tests/views.client.spec.tsx # packages/client/ui-user-questions/tests/plan-review-panel.client.spec.tsx # packages/client/ui-user-questions/tests/user-questions-composer.client.spec.tsx # packages/client/ui-workflow-run/tests/workflow-run.client.spec.tsx # packages/client/ui-workspace/tests/apply.client.spec.ts # packages/client/ui-workspace/tests/tree.client.spec.ts # packages/client/ui-workspace/tests/workspace-browser.client.spec.tsx # packages/client/ui-workspace/tests/workspace-picker.client.spec.tsx # packages/client/ui-workspace/tests/workspaces-service.client.spec.ts # packages/extensions/cordis-client-runner/src/client/slot-catalog.ts # packages/jobs/tool-jobs/src/index.ts # packages/shell/tool-bash/README.i18n.yaml # packages/test-support/client-runtime/src/sessions.ts
86 lines
4.0 KiB
TypeScript
86 lines
4.0 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
import { act, cleanup, render } from '@testing-library/react'
|
|
import { createSnapshotStore } from '@deepseek-ai/dsh-client-store'
|
|
import { bindSnapshotSelector } from '@deepseek-ai/dsh-client-test-runtime'
|
|
import type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'
|
|
import type { SessionId } from '@deepseek-ai/dsh-session/types'
|
|
import { DocumentTitle } from '../src/client/DocumentTitle.tsx'
|
|
import type { MainPanelId, PanelInfo } from '../src/client/service.ts'
|
|
|
|
let originalTitle: string
|
|
beforeEach(() => { originalTitle = document.title })
|
|
afterEach(() => {
|
|
try { cleanup() } finally { document.title = originalTitle }
|
|
})
|
|
|
|
function titleSources() {
|
|
const sessionId = 'session-title' as SessionId
|
|
const sessions = createSnapshotStore<SessionListState>({
|
|
ids: [sessionId],
|
|
byId: { [sessionId]: { id: sessionId, displayTitle: 'Test', running: false, retainedBy: { mainView: 1 }, blank: false, updatedAt: 1 } },
|
|
phase: 'ready',
|
|
projectionsBySession: {},
|
|
})
|
|
const panelInfo = createSnapshotStore<PanelInfo>({ activePanelId: null })
|
|
return {
|
|
sessionId, sessions, panelInfo,
|
|
props: { useSessions: bindSnapshotSelector(sessions), usePanelInfo: bindSnapshotSelector(panelInfo) },
|
|
}
|
|
}
|
|
|
|
describe('DocumentTitle', () => {
|
|
it('projects a durable title and restores the product title', () => {
|
|
const { sessionId, sessions, props } = titleSources()
|
|
document.title = 'stale title'
|
|
const mounted = render(<DocumentTitle {...props} productTitle="DeepSeek Harness" />)
|
|
expect(document.title).toBe('DeepSeek Harness')
|
|
act(() => { sessions.update((state) => { state.byId[sessionId]!.title = 'First title' }) })
|
|
expect(document.title).toBe('First title — DeepSeek Harness')
|
|
act(() => { sessions.update((state) => { state.byId[sessionId]!.title = 'Revised title' }) })
|
|
expect(document.title).toBe('Revised title — DeepSeek Harness')
|
|
act(() => {
|
|
const state = sessions.getSnapshot()
|
|
sessions.set({
|
|
...state,
|
|
byId: { ...state.byId, [sessionId]: { ...state.byId[sessionId]!, retainedBy: {} } },
|
|
})
|
|
})
|
|
expect(document.title).toBe('DeepSeek Harness')
|
|
mounted.unmount()
|
|
expect(document.title).toBe('DeepSeek Harness')
|
|
})
|
|
|
|
it('uses the localized product title supplied by the frame', () => {
|
|
const { sessionId, sessions, props } = titleSources()
|
|
sessions.update((state) => { state.byId[sessionId]!.title = 'First title' })
|
|
const mounted = render(<DocumentTitle {...props} productTitle="DSH Local Build" />)
|
|
expect(document.title).toBe('First title — DSH Local Build')
|
|
mounted.unmount()
|
|
expect(document.title).toBe('DSH Local Build')
|
|
})
|
|
|
|
it('keeps the product title across global panels and restores the latest Session title on return', () => {
|
|
const { sessionId, sessions, panelInfo, props } = titleSources()
|
|
sessions.update((state) => { state.byId[sessionId]!.title = 'Session title' })
|
|
render(<DocumentTitle {...props} productTitle="Product" />)
|
|
expect(document.title).toBe('Session title — Product')
|
|
act(() => { panelInfo.set({ activePanelId: 'panel-a' as MainPanelId }) })
|
|
expect(document.title).toBe('Product')
|
|
act(() => { sessions.update((state) => { state.byId[sessionId]!.title = 'Updated title' }) })
|
|
expect(document.title).toBe('Product')
|
|
act(() => { panelInfo.set({ activePanelId: 'panel-b' as MainPanelId }) })
|
|
expect(document.title).toBe('Product')
|
|
expect(sessions.getSnapshot().byId[sessionId]?.retainedBy.mainView).toBe(1)
|
|
act(() => { panelInfo.set({ activePanelId: null }) })
|
|
expect(document.title).toBe('Updated title — Product')
|
|
})
|
|
|
|
it('uses the product title when the current Session row is not available', () => {
|
|
const { sessions, props } = titleSources()
|
|
sessions.update((state) => { state.byId = {}; state.ids = [] })
|
|
render(<DocumentTitle {...props} productTitle="Product" />)
|
|
expect(document.title).toBe('Product')
|
|
})
|
|
})
|