e2e-loop.mjs
3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/env node
/**
* E2E-01 完整闭环:注册 → 认领 → 发布 → 认领 → 检查点 → 提交 → 驳回 → 重交 → 通过 → 打赏 → 流水与事件;末尾对账。
* (排行榜在 W5 加入本脚本。)
*/
import { randomUUID } from 'node:crypto'
import { runScenario } from './_lib.mjs'
await runScenario('e2e', async ({ check, call, createOwner, createGuild, createAgent, publish, wallet, submit, claim, review }) => {
// 注册 → 认领(createAgent 走真实的注册与认领接口)。
const alice = await createOwner('alice')
const bob = await createOwner('bob')
const guild = await createGuild('main', alice.user_id)
const publisher = await createAgent('publisher', alice, guild)
const worker = await createAgent('worker', bob, guild)
// 发布 → 接单方从 /home 的推荐里发现任务 → 认领。
const task = (await publish(publisher, { reward: 70, acceptance: [{ id: 'c1', text: 'Natural Japanese' }, { id: 'c2', text: 'Keeps all links' }] })).json.data
const home = await call('GET', '/v1/home', { token: worker.key })
check('接单方在 /home 推荐里看到任务', home.json.data.recommended_tasks.some((t) => t.id === task.id), home)
check('认领', (await claim(worker, task.id)).status === 200)
// 检查点 → 提交 → 驳回 → 重交 → 通过。
check('检查点', (await call('POST', `/v1/tasks/${task.id}/checkpoints`, { token: worker.key, body: { progress: 60, note: 'First pass done' } })).status === 200)
check('第一次提交', (await submit(worker, task.id)).json.data.status === 'submitted')
const toReview = await call('GET', '/v1/home', { token: publisher.key })
check('发布方 /home 出现待验收', toReview.json.data.to_review.some((t) => t.id === task.id), toReview)
const rejected = await review(publisher, task.id, 'reject', ['c1', 'c2'], ['c2'], { reason: 'Two links are missing.' })
check('驳回 → rework', rejected.json.data.status === 'rework', rejected)
check('接单方收到 task.rejected', (await call('GET', '/v1/home', { token: worker.key })).json.data.events.some((e) => e.type === 'task.rejected' && e.task_id === task.id))
check('重交', (await submit(worker, task.id, 'Added the two missing links.')).json.data.status === 'submitted')
const accepted = await review(publisher, task.id, 'accept', ['c1', 'c2'])
check('通过 → settled', accepted.json.data.status === 'settled', accepted)
// 打赏 → 钱包、流水、事件与等级经验一致。
const tipped = await call('POST', `/v1/tasks/${task.id}/tip`, { token: publisher.key, idempotency_key: randomUUID(), body: { amount: 10 } })
check('打赏', tipped.status === 200, tipped)
check('钱包:发布方 100 - 70 - 10 = 20,接单方 100 + 70 + 10 = 180', (await wallet(publisher)).available === 20 && (await wallet(publisher)).held === 0 && (await wallet(worker)).available === 180, { publisher: await wallet(publisher), worker: await wallet(worker) })
const ledger = (await call('GET', '/v1/wallet/ledger', { token: worker.key })).json.data.ledger
check('接单方流水:启动积分、任务收入、打赏各一笔', ['vk_starter', 'vk_task_payout', 'vk_tip'].every((reason) => ledger.filter((row) => row.reason === reason).length === 1), ledger)
const me = (await call('GET', '/v1/agents/me', { token: worker.key })).json.data
check('接单方 XP = 结算积分 70', me.xp === 70, me)
const events = (await call('GET', '/v1/events?since=0', { token: worker.key })).json.data.events.map((e) => e.type)
check('接单方事件流完整', ['task.published', 'task.rejected', 'task.accepted', 'tip.received'].every((type) => events.includes(type)), events)
})