Why: Unrelated browser suites should skip this opt-in runtime acceptance instead of importing an absent manifest. Evidence: Playwright discovers the two tests without an instance; explicit owned-instance replay passed previously. Impact: Preserves strict manifest verification when invoked. Refs: fast-slow-u2-u3 Task 7
63 lines
5.3 KiB
TypeScript
63 lines
5.3 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
import { readFileSync, readlinkSync } from 'node:fs'
|
|
import { createHash } from 'node:crypto'
|
|
|
|
const manifestPath=process.env.WORK_CHECKPOINT_HTTP_MANIFEST
|
|
test.skip(!manifestPath,'Run explicitly with a task-owned mechanism instance manifest')
|
|
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')
|
|
|
|
async function setup(request:any){
|
|
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++){
|
|
const res=await request.post(manifest.base+`/api/projects/${project.id}/uploads`,{multipart:{file:{name:`来源${i+1}.txt`,mimeType:'text/plain',buffer:Buffer.from('上线六月。验收条件需要补齐,预算50万元尚未审批。\n\n'+('整理记录说明:保留日期、金额、限制和待确认事项。\n\n').repeat(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()}})
|
|
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')
|
|
await expect.poll(async()=>{
|
|
const out=await(await request.get(manifest.base+`/api/conversations/${conv.id}/cards`)).json()
|
|
return out.cards.find((c:any)=>c.task)?.task.executionState
|
|
}).toBe('completed')
|
|
return {project,conv,ids}
|
|
}
|
|
async function open(page:any,seed:any){
|
|
await page.addInitScript(({id}:{id:string})=>{localStorage.setItem('as.conv',id);localStorage.setItem('as.ui',JSON.stringify({theme:'light',rightCollapsed:true,fontSize:14}))},{id:seed.conv.id})
|
|
await page.goto('/')
|
|
await expect(page.locator('[data-conversation-work]')).toContainText('材料记载上线六月')
|
|
}
|
|
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('验收条件尚需补齐')
|
|
await page.reload();await expect(page.locator('[data-conversation-work]')).toContainText('材料记载上线六月')
|
|
await page.getByRole('button',{name:'查看依据',exact:true}).first().click()
|
|
await page.getByRole('button',{name:/查看来源/}).first().click()
|
|
await expect(page.locator('.preview-pane')).toBeVisible();await expect(page.getByText('任务处理时引用的来源版本;下方是本项发现引用的片段')).toBeVisible()
|
|
const card=(await(await request.get(manifest.base+`/api/conversations/${seed.conv.id}/cards`)).json()).cards.find((c:any)=>c.task)
|
|
const source=card.task.findings[0].sources[0]
|
|
const update=await request.put(manifest.base+`/api/artifacts/${source.artifactId}/content`,{data:'上线七月。文件内容已经更新。',headers:{'Content-Type':'text/plain'}});expect(update.ok()).toBeTruthy()
|
|
const old=await request.get(manifest.base+`/api/artifacts/${source.artifactId}/content?expectedHash=${source.contentHash}`);expect(old.status()).toBe(409)
|
|
await page.reload();await expect(page.locator('[data-conversation-work]')).toContainText('依据文件已更新')
|
|
await expect(page.locator('[data-conversation-work] .acard-findings').first()).not.toContainText('材料记载上线六月')
|
|
expect(errors).toEqual([])
|
|
if(process.env.WORK_CHECKPOINT_SCREENSHOT)await page.screenshot({path:process.env.WORK_CHECKPOINT_SCREENSHOT,fullPage:true})
|
|
})
|
|
test('background replay does not steal the current file, focus or viewport',async({page,request})=>{
|
|
const seed=await setup(request);await open(page,seed)
|
|
await page.getByRole('button',{name:'查看依据',exact:true}).first().click();await page.getByRole('button',{name:/查看来源/}).first().click();await expect(page.locator('.preview-pane')).toBeVisible()
|
|
const tabs=await page.locator('.tab-strip').textContent()
|
|
const composer=page.locator('textarea').last();await composer.fill('正在记录自己的想法');await composer.focus()
|
|
const focus=await composer.evaluate((el:any)=>document.activeElement===el);expect(focus).toBe(true)
|
|
const sent=await request.post(manifest.base+`/api/conversations/${seed.conv.id}/messages`,{data:{text:'重点核对预算',attachmentIds:seed.ids,requestId:'another-'+Date.now()}});expect(sent.ok()).toBeTruthy()
|
|
await expect.poll(async()=>{
|
|
const cards=(await(await request.get(manifest.base+`/api/conversations/${seed.conv.id}/cards`)).json()).cards
|
|
return cards.filter((c:any)=>c.task?.executionState==='completed').length
|
|
}).toBe(2)
|
|
await expect(composer).toBeFocused();await expect(composer).toHaveValue('正在记录自己的想法')
|
|
expect(await page.locator('.tab-strip').textContent()).toBe(tabs)
|
|
})
|