HH-846 / HH-799: add task recovery and audit (#27)
This commit is contained in:
@@ -171,3 +171,68 @@ test('keeps draft review responsive and restores focus after dialog close and su
|
||||
await expect(page.getByRole('dialog')).toBeHidden()
|
||||
await expect(trigger).toBeFocused()
|
||||
})
|
||||
|
||||
test('keeps task recovery and audit traceable without blind retry at 599px, 900px and 1280px', async ({ page }) => {
|
||||
let verified = false
|
||||
let resumed = false
|
||||
let auditPage = 0
|
||||
const baseTask = {
|
||||
id: 'task-a', account_id: 'account-a', draft_id: 'draft-a', confirmation_id: 'confirmation-a', state: 'needs_confirmation',
|
||||
hold_reason: 'task_result_uncertain', browser_env_alias: 'env-a', network_exit_id: 'exit-a', runtime_instance_id: 'runtime-a', binding_version: 4,
|
||||
confirmation: { id: 'confirmation-a', version: 1, account_version: 2, draft_version: 1, browser_env_alias: 'env-a', network_exit_id: 'exit-a', runtime_instance_id: 'runtime-a', binding_version: 4 },
|
||||
attempts: [{ id: 'attempt-a', started_at: '2026-08-30T00:00:00Z', outcome: 'uncertain', evidence: { mock_outcome: 'uncertain' } }],
|
||||
}
|
||||
const listTask = { ...baseTask, confirmation: undefined, attempts: undefined, allowed_action: undefined, updated_at: '2026-08-30T00:01:00Z' }
|
||||
await page.route(/\/api\/phase-a\/tasks(?:\/.*)?(?:\?.*)?$/, async route => {
|
||||
const request = route.request()
|
||||
const url = new URL(request.url())
|
||||
if (request.method() === 'POST' && url.pathname.endsWith('/verify')) {
|
||||
expect(request.postDataJSON()).toEqual({ result: 'not_executed' })
|
||||
verified = true
|
||||
return route.fulfill({ status: 204 })
|
||||
}
|
||||
if (request.method() === 'POST' && url.pathname.endsWith('/resume')) {
|
||||
resumed = true
|
||||
return route.fulfill({ status: 204 })
|
||||
}
|
||||
if (url.pathname.endsWith('/task-a')) return route.fulfill({ json: { ...baseTask, state: resumed ? 'queued' : baseTask.state, allowed_action: resumed ? '' : verified ? 'resume' : 'verify', verification_result: verified ? 'not_executed' : undefined } })
|
||||
return route.fulfill({ json: [listTask] })
|
||||
})
|
||||
await page.route('**/api/phase-a/attempts/attempt-a', route => route.fulfill({ json: { ...baseTask.attempts[0], task_id: 'task-a', browser_env_alias: 'env-a', network_exit_id: 'exit-a', binding_version: 4 } }))
|
||||
await page.route('**/api/browsers/env-a', route => route.fulfill({ json: { alias: 'env-a', name: '店铺环境', account_id: 'account-a', image_version: '148', binding_version: 4, runtime_instance_id: 'runtime-a', network_exit: { id: 'exit-a', health_status: 'healthy' } } }))
|
||||
await page.route('**/api/network-exits/exit-a', route => route.fulfill({ json: { id: 'exit-a', protocol: 'socks5', host: 'proxy.example', port: 1080, health_status: 'healthy', version: 2 } }))
|
||||
await page.route('**/api/phase-a/audit*', route => {
|
||||
const currentPage = Number(new URL(route.request().url()).searchParams.get('page') || 1)
|
||||
auditPage = Math.max(auditPage, currentPage)
|
||||
return route.fulfill({ json: { data: [{
|
||||
id: 7, event_type: 'task_verified', account_id: 'account-a', task_id: 'task-a', attempt_id: 'attempt-a', browser_env_alias: 'env-a', network_exit_id: 'exit-a', binding_version: 4, reason_code: 'manual_verification_recorded', created_at: '2026-08-30T00:01:00Z',
|
||||
}], total: 26, page: currentPage, page_size: 25 } })
|
||||
})
|
||||
|
||||
for (const path of ['/#/tasks', '/#/tasks/task-a', '/#/attempts/attempt-a', '/#/browsers/env-a', '/#/network-exits/exit-a', '/#/audit?task_id=task-a']) {
|
||||
for (const width of [599, 900, 1280]) {
|
||||
await page.setViewportSize({ width, height: 900 })
|
||||
await page.goto(path)
|
||||
await expect(page.getByRole('heading', { level: 1 })).toBeVisible()
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(width)
|
||||
}
|
||||
}
|
||||
|
||||
verified = false
|
||||
await page.setViewportSize({ width: 599, height: 900 })
|
||||
await page.goto('/#/tasks/task-a')
|
||||
await expect(page.getByRole('button', { name: /恢复排队/ })).toHaveCount(0)
|
||||
await page.getByRole('button', { name: '记录人工核验' }).click()
|
||||
await expect(page.getByRole('button', { name: '按核验结论恢复排队' })).toBeVisible()
|
||||
await page.getByRole('button', { name: '按核验结论恢复排队' }).click()
|
||||
await expect.poll(() => resumed).toBe(true)
|
||||
await expect(page.getByText('已排队')).toBeVisible()
|
||||
await page.getByRole('link', { name: '查看关联审计' }).click()
|
||||
await expect(page).toHaveURL(/#\/audit\?task_id=task-a$/)
|
||||
await expect(page.getByRole('link', { name: 'task-a' }).first()).toBeVisible()
|
||||
await page.getByRole('button', { name: '下一页' }).click()
|
||||
await expect.poll(() => auditPage).toBe(2)
|
||||
await page.getByRole('link', { name: 'attempt-a' }).first().click()
|
||||
await expect(page).toHaveURL(/#\/attempts\/attempt-a$/)
|
||||
await expect(page.getByRole('link', { name: '返回任务' })).toHaveAttribute('href', '#/tasks/task-a')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user