fix: close alignment review races and preserve local conversation state
This commit is contained in:
1 parent
c7231be2c5
commit
37ddb2ce24
14 files changed
+203
-45
No files matched your search
@@ -10,6 +10,9 @@ const React=require('react') as typeof import('react')
|
||||
const {act}=React
|
||||
const {createRoot}=require('react-dom/client') as typeof import('react-dom/client')
|
||||
const {QuestionFloating}=require('../src/renderer/src/workbuddy/conversation/QuestionFloating') as typeof import('../src/renderer/src/workbuddy/conversation/QuestionFloating')
|
||||
const {projectQuestionAnswers}=require('../src/renderer/src/workbuddy/conversation/question-projection') as typeof import('../src/renderer/src/workbuddy/conversation/question-projection')
|
||||
const {renderToStaticMarkup}=require('react-dom/server') as typeof import('react-dom/server')
|
||||
const MessageBubble=require('../src/renderer/src/components/MessageBubble').default as typeof import('../src/renderer/src/components/MessageBubble').default
|
||||
const {CompletedFold,LiveEventDisclosure}=require('../src/renderer/src/workbuddy/conversation/CompletedFold') as typeof import('../src/renderer/src/workbuddy/conversation/CompletedFold')
|
||||
const root=createRoot(document.getElementById('root')!)
|
||||
const click=(el:Element)=>el.dispatchEvent(new MouseEvent('click',{bubbles:true}))
|
||||
@@ -54,6 +57,26 @@ async function main(){
|
||||
await act(async()=>root.render(<QuestionFloating key="replace" config={{...config,toolCallId:'new'}}/>))
|
||||
await act(async()=>new Promise(r=>setTimeout(r,140)))
|
||||
check(document.querySelector('[role="dialog"]')?.getAttribute('aria-label')==='First','request replacement cancels old delayed advance')
|
||||
// Manual pagination must retire a previously selected option's delayed navigation.
|
||||
const three={toolCallId:'three',questions:[{id:'a',question:'Page A',options:['A']},{id:'b',question:'Page B',options:['B']},{id:'c',question:'Page C',options:['C']}]}
|
||||
await act(async()=>root.render(<QuestionFloating key="manual-page" config={three}/>))
|
||||
await act(async()=>click(document.querySelector('.question-floating__option')!))
|
||||
await act(async()=>click(document.querySelectorAll('.question-floating__page-button')[1]))
|
||||
await act(async()=>new Promise(r=>setTimeout(r,140)))
|
||||
check(document.querySelector('[role="dialog"]')?.getAttribute('aria-label')==='Page B','manual next retires delayed advance instead of skipping a page')
|
||||
await act(async()=>root.render(<QuestionFloating key="manual-skip" config={three}/>))
|
||||
await act(async()=>click(document.querySelector('.question-floating__option')!))
|
||||
await act(async()=>click(document.querySelector('.question-floating__skip')!))
|
||||
await act(async()=>new Promise(r=>setTimeout(r,140)))
|
||||
check(document.querySelector('[role="dialog"]')?.getAttribute('aria-label')==='Page B','skip retires delayed advance instead of skipping two pages')
|
||||
const legacyAnswer={questions:[{id:'legacy-question',question:'Legacy unique question',answers:['yes']}]}
|
||||
const legacy: import('../src/shared/types').ChatMessage={id:'legacy',role:'assistant',createdAt:1,content:'Final prose',status:'done',tools:[{id:'legacy-tool',name:'AskUserQuestion',args:{},argsRaw:'{}',status:'ok',metadata:{questionAnswer:legacyAnswer}}],interactions:[{id:'legacy-interaction',runId:'old',kind:'question',toolCallId:'legacy-tool',title:'Question',questions:[],status:'answered',answer:legacyAnswer}]}
|
||||
const projected=projectQuestionAnswers(legacy)
|
||||
check(projected.positionedAnswers.size===0 && projected.unpositioned.length===1,'fallback tool order is not treated as recorded question position')
|
||||
check(projected.unpositionedToolIds.has('legacy-tool'),'legacy duplicate tool rendering is suppressed')
|
||||
const legacyMarkup=renderToStaticMarkup(<MessageBubble message={legacy}/>)
|
||||
check(legacyMarkup.includes('历史问答(原始位置不可用)') && (legacyMarkup.match(/Legacy unique question/g)||[]).length===1,'legacy answer displayed exactly once with unknown-position label')
|
||||
check(projectQuestionAnswers({...legacy,interactions:[]}).unpositioned.length===1,'metadata-only legacy answer preserves unknown-position compatibility path')
|
||||
const parts=[{type:'reasoning',id:'r',text:'thought'},{type:'tool',toolId:'t'},{type:'text',text:'A'},{type:'tool',toolId:'later'}] as const
|
||||
await act(async()=>root.render(<CompletedFold parts={parts} turnFinished turnDurationMs={1000} renderUnit={(_p,i)=><i data-order={i}/>}/>))
|
||||
check(document.querySelector('.cr-collapse__header')?.getAttribute('aria-expanded')==='false','completion initially collapsed')
|
||||
|
||||
Reference in new issue
Block a user