Files
koc-loop/tests/task-pairing.test.mjs
ABAPPLO e2a93e22cf feat: 任务模型物理合并,发布+回收并为单任务双阶段
- tasks 新增 recovery_enabled/recovery_due_at/recovery_instructions/recovery_example_images,回收挂自己名下(先发布后交截图),不再置 complete
- 存量 screenshot_collect 迁移并入父任务后删除(mysql/0020 含 DELETE,生产执行前务必备份)
- 新 action task_enable_recovery:ghost 面板一键开通回收,截止默认=发布截止
- 企微催办双阶段(待发布/截图待提交);超期自动释放仅发布阶段
- admin 删 groupTaskMasters 聚合改单卡双面板;portal 详情页回收截图区块+批次回收进度
- 测试 309 全绿 + Playwright E2E 20/20
2026-09-24 15:52:45 +08:00

96 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import test from "node:test";
import { readFileSync } from "node:fs";
const adminApp = readFileSync(
new URL("../app/admin-app.tsx", import.meta.url),
"utf8",
);
const adminCss = readFileSync(
new URL("../app/globals.css", import.meta.url),
"utf8",
);
const actionRoute = readFileSync(
new URL("../app/api/action/route.ts", import.meta.url),
"utf8",
);
const taskService = readFileSync(
new URL("../lib/task-service.ts", import.meta.url),
"utf8",
);
const projectService = readFileSync(
new URL("../lib/project-service.ts", import.meta.url),
"utf8",
);
const migration = readFileSync(
new URL("../mysql/0020_task_recovery_merge.sql", import.meta.url),
"utf8",
);
test("单任务模型:配对聚合与截图任务分支已删除", () => {
assert.doesNotMatch(adminApp, /groupTaskMasters/);
assert.doesNotMatch(adminApp, /PairableTask/);
assert.doesNotMatch(adminApp, /companion/);
assert.doesNotMatch(adminApp, /screenshot_collect/);
assert.doesNotMatch(adminApp, /withScreenshotTask/);
assert.doesNotMatch(adminApp, /仅回收/);
assert.doesNotMatch(adminApp, /回收群/);
assert.doesNotMatch(taskService, /createScreenshotTask/);
assert.doesNotMatch(actionRoute, /create_screenshot_task/);
assert.doesNotMatch(adminCss, /\.task-row-companion/);
});
test("TaskRowCard 双面板:发布面板 + 回收实面板/ghost 开通面板", () => {
assert.match(adminApp, /master-panel publish/);
assert.match(adminApp, /master-panel recovery/);
assert.match(adminApp, /master-panel ghost/);
assert.match(adminApp, /未开通回收/);
assert.match(adminApp, /开通回收 ›/);
assert.match(adminApp, /已收取/);
assert.match(adminApp, /recovery_submitted/);
assert.match(adminApp, /回收已开通/);
assert.match(adminCss, /\.master-panel\.ghost/);
});
test("创建/编辑表单携带回收设置", () => {
assert.match(adminApp, /开启截图回收(第二阶段)/);
assert.match(adminApp, /recoveryEnabled/);
assert.match(adminApp, /recoveryDueAt/);
assert.match(adminApp, /recoveryInstructions/);
assert.match(adminApp, /recoveryExampleImageKey/);
assert.match(adminApp, /发布截止日期/);
});
test("create_task / task_update / task_enable_recovery 三个 action 都落 recovery 字段", () => {
const createBlock = actionRoute.slice(
actionRoute.indexOf('body.action === "create_task"'),
actionRoute.indexOf('body.action === "task_update"'),
);
assert.match(createBlock, /recoveryEnabled/);
assert.match(createBlock, /recoveryExampleImageKey/);
const enableBlock = actionRoute.slice(
actionRoute.indexOf('body.action === "task_enable_recovery"'),
);
assert.match(enableBlock, /enableTaskRecovery/);
assert.match(enableBlock, /recoveryDueAt/);
assert.match(taskService, /export async function enableTaskRecovery/);
assert.match(taskService, /recovery_enabled, recovery_due_at, recovery_instructions, recovery_example_images/);
});
test("项目详情查询带回 recovery 字段(不再依赖 related_task_id)", () => {
assert.match(projectService, /recovery_enabled, recovery_due_at/);
assert.match(projectService, /recovery_submitted/);
assert.doesNotMatch(projectService, /related_task_id/);
});
test("存量迁移 SQL:配对并入、独立转正、删除老截图任务", () => {
assert.match(migration, /ALTER TABLE tasks ADD COLUMN recovery_enabled/);
assert.match(migration, /ADD COLUMN recovery_due_at/);
assert.match(migration, /ADD COLUMN recovery_instructions/);
assert.match(migration, /ADD COLUMN recovery_example_images/);
assert.match(migration, /child\.related_task_id = parent\.id/);
assert.match(migration, /target\.result_screenshot_key = legacy\.result_screenshot_key/);
assert.match(migration, /DELETE FROM tasks WHERE task_type = 'screenshot_collect' AND related_task_id != ''/);
assert.match(migration, /standalone\.task_type = 'content_publish'/);
});