Files
Agent-System-Frontend/src/surface.test.ts
T
weichen df4ca1e470 Render saved surfaces in the preview pane with refresh recovery
Why: U4 read-only experience - surface.updated events project into a
surfaces slice with a strict revision guard (stale/duplicate events
never overwrite; server snapshot is the single owner), preview tabs
gain a surface: kind that renders SurfaceView (doc-refs bridge into
artifact previews), a new page auto-opens a tab without stealing the
user's active non-surface tab, and opening a conversation reloads the
authoritative surface list so refresh/断线 restores pages.

Evidence: tsc clean; vitest 87/87 including new surface projection
tests (stale/duplicate/multi-surface); UI SurfaceView suite green in
its repo.

Impact: Frontend-only; no backend or contract changes.

Refs: Core PRs #27/#28; UI PRs #42/#43/#44; Dev task
feature/generative-ui-u4
2026-10-11 11:39:57 +00:00

40 lines
1.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest'
import { store } from './store'
import type { StreamEvent, SurfaceSnapshot } from './contracts'
// U4/R5:surface.updated 投影的 revision 守卫——旧修订/重复事件不得覆盖新修订;
// 服务端快照是唯一权威(KTD8 单一状态所有者)。
function surfEvent(seq: number, surfaceId: string, revision: number, title: string): StreamEvent<SurfaceSnapshot> {
return {
seq, conversationId: 'c1', ts: new Date().toISOString(), v: 1, type: 'surface.updated',
payload: {
identity: { surfaceId, owner: 'alice', pluginId: 'generative-ui', conversationId: 'c1' },
compat: { schemaVersion: 1, catalogVersion: 'ui-v1' },
revision, activationEpoch: 1,
spec: { title, nodes: [{ type: 'markdown', id: 'n1', markdown: 'x' }] },
},
}
}
describe('surface.updated projection', () => {
it('新事件入库;旧修订与重复事件不覆盖', () => {
store.applyEvent(surfEvent(1, 's1', 1, '初版'))
store.applyEvent(surfEvent(2, 's1', 2, '修订二'))
store.applyEvent(surfEvent(3, 's1', 1, '迟到的旧修订'))
store.applyEvent(surfEvent(4, 's1', 2, '重复事件'))
const list = store.getState().surfaces
expect(list).toHaveLength(1)
expect(list[0].revision).toBe(2)
expect(list[0].spec.title).toBe('修订二')
})
it('多页面并存,互不覆盖', () => {
store.applyEvent(surfEvent(5, 's2', 1, '页面二'))
const list = store.getState().surfaces
expect(list.filter(x => String(x.identity.surfaceId) === 's1')).toHaveLength(1)
expect(list.filter(x => String(x.identity.surfaceId) === 's2')).toHaveLength(1)
})
})