Cover safe material intake across browser paths
Why: The first reply and task reuse need end-to-end checks across long and small material inputs. Evidence: Dev evidence receipts for ten Playwright scenarios, Frontend tests, and build. Impact: Adds browser-only coverage; production UI and API behavior are unchanged. Refs: U3 r0.5 implementation plan Task 4
This commit is contained in:
@@ -7,17 +7,17 @@ test.skip(!manifestPath,'Run explicitly with a task-owned mechanism instance man
|
||||
const manifest=manifestPath?JSON.parse(readFileSync(manifestPath,'utf8')):null
|
||||
if(manifest&&(manifest.mode!=='mechanism'||!manifest.dataDir.includes('fast-slow-u2-u3-')||readlinkSync(`/proc/${manifest.pid}/exe`)!==manifest.binary||createHash('sha256').update(readFileSync(manifest.binary)).digest('hex')!==manifest.binarySHA256))throw new Error('Owned mechanism instance verification failed')
|
||||
|
||||
type Scenario='normal'|'slow-stages'|'zero-failure'|'partial-failure'|'choice'
|
||||
async function setup(request:any,scenario:Scenario='normal',awaitTask=true){
|
||||
type Scenario='normal'|'fast-ack'|'slow-stages'|'zero-failure'|'partial-failure'|'choice'
|
||||
async function setup(request:any,scenario:Scenario='normal',awaitTask=true,options:{text?:string,small?:boolean}={}){
|
||||
const project=await(await request.post(manifest.base+'/api/projects',{data:{name:'browser-'+Date.now()}})).json()
|
||||
const conv=await(await request.post(manifest.base+`/api/projects/${project.id}/conversations`,{data:{title:'材料整理',profileId:'checkpoint-eval'}})).json()
|
||||
const ids:string[]=[]
|
||||
for(let i=0;i<3;i++){
|
||||
for(let i=0;i<(options.small?1:3);i++){
|
||||
const marker=i===0&&scenario!=='normal'?`[fixture:${scenario}]\n`:''
|
||||
const res=await request.post(manifest.base+`/api/projects/${project.id}/uploads`,{multipart:{file:{name:`来源${i+1}.txt`,mimeType:'text/plain',buffer:Buffer.from(marker+'上线六月。验收条件需要补齐,预算50万元尚未审批。交付包含12项需求,其中3项依赖外部接口。第一期先完成8项核心需求。\n\n'+('整理记录说明:保留日期、金额、限制和待确认事项。\n\n').repeat(100))}}})
|
||||
const res=await request.post(manifest.base+`/api/projects/${project.id}/uploads`,{multipart:{file:{name:`来源${i+1}.txt`,mimeType:'text/plain',buffer:Buffer.from(marker+'上线六月。验收条件需要补齐,预算50万元尚未审批。交付包含12项需求,其中3项依赖外部接口。第一期先完成8项核心需求。\n\n'+(options.small?'':('整理记录说明:保留日期、金额、限制和待确认事项。\n\n').repeat(options.text?250:100)))}}})
|
||||
expect(res.ok()).toBeTruthy();ids.push((await res.json()).artifactId)
|
||||
}
|
||||
const sent=await request.post(manifest.base+`/api/conversations/${conv.id}/messages`,{data:{text:'',attachmentIds:ids,requestId:'browser-'+Date.now()}})
|
||||
const sent=await request.post(manifest.base+`/api/conversations/${conv.id}/messages`,{data:{text:options.text??'',attachmentIds:ids,requestId:'browser-'+Date.now()}})
|
||||
expect(sent.ok()).toBeTruthy()
|
||||
const sendBody=await sent.json()
|
||||
await expect.poll(async()=> (await(await request.get(manifest.base+`/api/runs/${sendBody.run.id}`)).json()).run.status).toBe('completed')
|
||||
@@ -46,6 +46,55 @@ async function open(page:any,seed:any){
|
||||
await page.goto('/')
|
||||
await expect(page.locator('[data-conversation-work]')).toContainText('上线六月')
|
||||
}
|
||||
test('attachment-only intake gives a safe first reply before sourced findings',async({page,request})=>{
|
||||
const seed=await setup(request,'fast-ack',false)
|
||||
const cards=(await(await request.get(manifest.base+`/api/conversations/${seed.conv.id}/cards`)).json()).cards
|
||||
expect(cards.filter((c:any)=>c.task)).toHaveLength(1)
|
||||
expect(cards.find((c:any)=>c.task).task.checkpointSeq??0).toBe(0)
|
||||
await open(page,seed)
|
||||
const reply=page.getByText(/已收到 3 份材料.*待确认/)
|
||||
await expect(reply).toBeVisible()
|
||||
await expect(page.getByText(/剩余\s*4\s*项.*含\s*3\s*项依赖接口/)).toHaveCount(0)
|
||||
await page.setViewportSize({width:390,height:844})
|
||||
await expect(reply).toBeVisible()
|
||||
if(process.env.WORK_CHECKPOINT_SCREENSHOT)await page.screenshot({path:process.env.WORK_CHECKPOINT_SCREENSHOT.replace(/\.png$/, '-mobile.png'),fullPage:true})
|
||||
await page.reload()
|
||||
await expect(reply).toBeVisible()
|
||||
})
|
||||
test('text with long material keeps the user focus in the host reply',async({page,request})=>{
|
||||
const seed=await setup(request,'fast-ack',false,{text:'重点核对预算审批'})
|
||||
await open(page,seed)
|
||||
await expect(page.getByText(/你提出的工作重点已带入整理任务.*待确认/)).toBeVisible()
|
||||
const cards=(await(await request.get(manifest.base+`/api/conversations/${seed.conv.id}/cards`)).json()).cards
|
||||
expect(cards.filter((c:any)=>c.task)).toHaveLength(1)
|
||||
})
|
||||
test('running and completed resends reuse one material card',async({page,request})=>{
|
||||
const seed=await setup(request,'slow-stages',false)
|
||||
const resend=async(key:string)=>{
|
||||
const response=await request.post(manifest.base+`/api/conversations/${seed.conv.id}/messages`,{data:{text:'',attachmentIds:seed.ids,requestId:key}})
|
||||
expect(response.ok()).toBeTruthy()
|
||||
const body=await response.json()
|
||||
await expect.poll(async()=> (await(await request.get(manifest.base+`/api/runs/${body.run.id}`)).json()).run.status).toBe('completed')
|
||||
}
|
||||
await resend('active-resend-'+Date.now())
|
||||
await open(page,seed)
|
||||
await expect(page.getByText(/这批材料仍在整理.*待确认/)).toBeVisible()
|
||||
await expect.poll(async()=>{
|
||||
const cards=(await(await request.get(manifest.base+`/api/conversations/${seed.conv.id}/cards`)).json()).cards
|
||||
return cards.find((c:any)=>c.task)?.task.executionState
|
||||
}).toBe('completed')
|
||||
await resend('completed-resend-'+Date.now())
|
||||
await expect(page.getByText(/这批材料已整理完成.*待确认/)).toBeVisible()
|
||||
const cards=(await(await request.get(manifest.base+`/api/conversations/${seed.conv.id}/cards`)).json()).cards
|
||||
expect(cards.filter((c:any)=>c.task)).toHaveLength(1)
|
||||
})
|
||||
test('text with a small attachment retains the ordinary reply path',async({page,request})=>{
|
||||
const seed=await setup(request,'normal',true,{text:'请先解释材料要点',small:true})
|
||||
await open(page,seed)
|
||||
await expect(page.getByText('已收到材料,正在后台整理;请结合阶段发现继续工作。').first()).toBeVisible()
|
||||
const cards=(await(await request.get(manifest.base+`/api/conversations/${seed.conv.id}/cards`)).json()).cards
|
||||
expect(cards.filter((c:any)=>c.task)).toHaveLength(1)
|
||||
})
|
||||
test('real HTTP task recovery, source navigation and changed-version limitation',async({page,request})=>{
|
||||
const seed=await setup(request);const errors:string[]=[];page.on('pageerror',e=>errors.push(e.message));await open(page,seed)
|
||||
await expect(page.locator('[data-conversation-work]')).toContainText('验收条件需要补齐')
|
||||
|
||||
Reference in New Issue
Block a user