返回 DeepSeek-Reasonix
protocol-recovery-search.test.tsx
根目录 / desktop / frontend / src / __tests__ / protocol-recovery-search.test.tsx
1 import assert from "node:assert/strict";
2 import React from "react";
3 import { LocaleProvider } from "../lib/i18n";
4 import { renderToStaticMarkup } from "react-dom/server";
5 import { historyMessagesToItems, initialState, reducer } from "../lib/useController";
6 import { NoticeCard } from "../components/TranscriptCards";
7 import { createTranscriptHarness } from "./transcript-dom-harness";
8 import { act } from "react";
9 import { searchOutputMetadata, parseSearchSources } from "../lib/searchSources";
10 import type { WireEvent } from "../lib/types";
11 const ev=(s:typeof initialState,e:WireEvent)=>reducer(s,{type:"event",e});
12 let state=ev(initialState,{kind:"turn_started",turnId:"one"});
13 state=ev(state,{kind:"turn_done",turnId:"one",err:"opaque rejection",protocolRecovery:{id:"token"}});
14 const action=state.items.find(i=>i.kind==="notice"&&i.action==="recover_context");
15 assert(action?.kind==="notice");
16 assert.equal(action.recoveryId,"token");
17 const submissions: Array<{ display: string; submit?: string }> = [];
18 const harness = await createTranscriptHarness();
19 try {
20 await harness.render([action], { onPrompt: (display: string, submit?: string) => submissions.push({ display, submit }) });
21 await harness.settle();
22 const button = harness.container.querySelector<HTMLButtonElement>(".chat-notice button");
23 assert.ok(button, "the production chat exposes protocol recovery");
24 await act(async () => button.click());
25 } finally { await harness.unmount(); await harness.close(); }
26 assert.equal(submissions[0]?.submit, "/recover-context token");
27 assert(!submissions[0]?.display.includes("token"), "opaque recovery token is not user-facing copy");
28 assert.match(renderToStaticMarkup(<LocaleProvider><NoticeCard item={action} onAction={()=>{}} /></LocaleProvider>),/button/);
29 state=ev(state,{kind:"turn_started",turnId:"two"});
30 const before=state;
31 state=ev(state,{kind:"turn_done",turnId:"one",protocolRecovery:{id:"stale"}});
32 assert.equal(state,before);
33 state=ev(state,{kind:"turn_done",turnId:"two",status:"interrupted",protocolRecovery:{id:"cancelled"}});
34 assert(!state.items.some(i=>i.kind==="notice"&&i.recoveryId==="cancelled"));
35 const history=historyMessagesToItems([{role:"notice",content:"",code:"protocol_recovery",pending:true,protocolRecovery:{id:"saved"}},{role:"assistant",content:"Summary",serverSearch:[{id:"search",sources_status:"not_provided",results:[]}]}],"h").items;
36 assert(history.some(i=>i.kind==="notice"&&i.recoveryId==="saved"));
37 assert(history.some(i=>i.kind==="tool"&&i.searchSourcesStatus==="not_provided"&&i.status==="done"));
38 const output=JSON.stringify({sources_status:"not_provided",sources:[],summary:"https://unverified.invalid prose"});
39 assert.deepEqual(parseSearchSources(output),[]);
40 assert.deepEqual(searchOutputMetadata(output),{status:"not_provided",summary:"https://unverified.invalid prose"});
41 assert.deepEqual(searchOutputMetadata("old text"),{});
42 console.log("protocol recovery and search presentation passed");
43
43 lines Plain Text