feat: bootstrap commercial AI drama platform
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { dbRun } from "../server/db.mjs";
|
||||
|
||||
const api = process.env.AI_DRAMA_API_BASE || "http://127.0.0.1:8787";
|
||||
const scope = {
|
||||
"x-organization-id": "org-studio-lab",
|
||||
"x-workspace-id": "ws-local-aidrama",
|
||||
"x-project-id": "thunder-mouth"
|
||||
};
|
||||
|
||||
async function request(path, options = {}) {
|
||||
const response = await fetch(`${api}${path}`, {
|
||||
...options,
|
||||
headers: { "content-type": "application/json", ...(options.headers || {}) }
|
||||
});
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
return { response, payload };
|
||||
}
|
||||
|
||||
function headers(token) {
|
||||
return { authorization: `Bearer ${token}`, ...scope };
|
||||
}
|
||||
|
||||
async function login(email) {
|
||||
const result = await request("/api/auth/login", { method: "POST", body: JSON.stringify({ email, password: "Demo@123456" }) });
|
||||
assert.equal(result.response.ok, true, `${email} login failed`);
|
||||
return result.payload.session.token;
|
||||
}
|
||||
|
||||
const taskTitle = `smoke-task-${Date.now()}`;
|
||||
let ownerToken = "";
|
||||
let reviewerToken = "";
|
||||
let taskId = "";
|
||||
try {
|
||||
const anonymous = await request("/api/tasks");
|
||||
assert.equal(anonymous.response.status, 401, "anonymous task access must be rejected");
|
||||
|
||||
ownerToken = await login("producer@local.test");
|
||||
reviewerToken = await login("review@local.test");
|
||||
|
||||
const created = await request("/api/tasks", {
|
||||
method: "POST",
|
||||
headers: headers(ownerToken),
|
||||
body: JSON.stringify({
|
||||
title: taskTitle,
|
||||
description: "验证项目任务的负责人、状态、截止时间和审计链路",
|
||||
kind: "review",
|
||||
priority: "high",
|
||||
assigneeUserId: "u-review",
|
||||
targetTab: "qa",
|
||||
dueAt: "2026-08-30T23:59:59.000Z"
|
||||
})
|
||||
});
|
||||
assert.equal(created.response.status, 201, `task creation failed: ${JSON.stringify(created.payload)}`);
|
||||
assert.equal(created.payload.task.title, taskTitle, "created task title mismatch");
|
||||
assert.equal(created.payload.task.assignee.id, "u-review", "task assignee not persisted");
|
||||
assert.equal(created.payload.task.priority, "high", "task priority not persisted");
|
||||
taskId = created.payload.task.id;
|
||||
|
||||
const ownerList = await request("/api/tasks?status=all", { headers: headers(ownerToken) });
|
||||
assert.equal(ownerList.response.ok, true, "owner task list failed");
|
||||
assert.ok(ownerList.payload.tasks.some((task) => task.id === taskId), "owner should see created task");
|
||||
assert.ok(ownerList.payload.summary.total >= 1, "task summary must include created task");
|
||||
|
||||
const reviewerList = await request("/api/tasks?assignedTo=me", { headers: headers(reviewerToken) });
|
||||
assert.equal(reviewerList.response.ok, true, "reviewer assigned task list failed");
|
||||
assert.ok(reviewerList.payload.tasks.some((task) => task.id === taskId), "assignee should see own task");
|
||||
const reviewerNotifications = await request("/api/notifications?limit=200", { headers: headers(reviewerToken) });
|
||||
assert.equal(reviewerNotifications.response.ok, true, "reviewer notification list failed");
|
||||
assert.ok(reviewerNotifications.payload.notifications.some((notification) => notification.eventKey === "task.assigned" && notification.targetId === taskId), "task assignment must create an in-app notification");
|
||||
|
||||
const reviewerUpdate = await request(`/api/tasks/${encodeURIComponent(taskId)}`, {
|
||||
method: "PATCH",
|
||||
headers: headers(reviewerToken),
|
||||
body: JSON.stringify({ status: "in_progress" })
|
||||
});
|
||||
assert.equal(reviewerUpdate.response.ok, true, "assignee status update failed");
|
||||
assert.equal(reviewerUpdate.payload.task.status, "in_progress", "assignee status was not saved");
|
||||
|
||||
const reviewerEscalation = await request(`/api/tasks/${encodeURIComponent(taskId)}`, {
|
||||
method: "PATCH",
|
||||
headers: headers(reviewerToken),
|
||||
body: JSON.stringify({ title: "越权修改标题" })
|
||||
});
|
||||
assert.equal(reviewerEscalation.response.status, 403, "assignee must not edit task metadata");
|
||||
|
||||
const ownerUpdate = await request(`/api/tasks/${encodeURIComponent(taskId)}`, {
|
||||
method: "PATCH",
|
||||
headers: headers(ownerToken),
|
||||
body: JSON.stringify({ status: "done", priority: "medium" })
|
||||
});
|
||||
assert.equal(ownerUpdate.response.ok, true, "manager task update failed");
|
||||
assert.equal(ownerUpdate.payload.task.status, "done", "manager status update was not saved");
|
||||
assert.ok(ownerUpdate.payload.task.completedAt, "completed task must have completedAt");
|
||||
|
||||
const northstar = await request("/api/tasks", {
|
||||
headers: { authorization: `Bearer ${ownerToken}`, "x-organization-id": "org-northstar", "x-workspace-id": "ws-northstar-main", "x-project-id": "northstar-pilot" }
|
||||
});
|
||||
assert.equal(northstar.response.ok, true, "northstar task scope request failed");
|
||||
assert.ok(northstar.payload.tasks.every((task) => task.id !== taskId), "cross-organization task must not leak");
|
||||
console.log(`tasks smoke passed: ${taskId}`);
|
||||
} finally {
|
||||
if (taskId) dbRun("DELETE FROM project_tasks WHERE id = ?", [taskId]);
|
||||
if (taskId) {
|
||||
dbRun("DELETE FROM user_notifications WHERE target_id = ?", [taskId]);
|
||||
dbRun("DELETE FROM audit_logs WHERE target_type = 'project_task' AND target_id = ?", [taskId]);
|
||||
}
|
||||
if (ownerToken) await request("/api/auth/logout", { method: "POST", headers: { authorization: `Bearer ${ownerToken}` } }).catch(() => {});
|
||||
if (reviewerToken) await request("/api/auth/logout", { method: "POST", headers: { authorization: `Bearer ${reviewerToken}` } }).catch(() => {});
|
||||
}
|
||||
Reference in New Issue
Block a user