Files
flow-center-front/tests/line-offline.test.ts
T
chenxing f2841e2740
build / build (push) Successful in 1m33s
release: FL 2.0 前端候选(流程线停发/发起页指派预览/测试夹具)
配套 service 候选 500a9a2:
- flow.ts 增加 admin/def/offlineLine、enableLine(T03 线级停发/恢复)
- Defs.vue 接线级停发开关与状态展示;lineOffline.ts 收敛判定与文案
- AssignPreview.vue + assignEmbed.ts 发起时指派预览(T02 契约)
- def-editor 表单坐标绑定微调
- 新增 vitest 组件测试与 line-offline 契约测试(npm test 可跑)
2026-10-27 12:07:40 +08:00

148 lines
5.1 KiB
TypeScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { lineActionErrorDetail, runLineAction } from "../src/utils/lineOffline";
/** 线级启停纯逻辑单测:不发真实请求,边界=请求/刷新编排,不代表后端或真实 UI 已验证 */
test("停发成功:按 flowGuid 调一次接口,按返回行数刷新", async () => {
const calls: string[] = [];
let reloads = 0;
const out = await runLineAction({
flowGuid: " g1 ",
lineOffline: 0,
action: "offline",
request: async (guid) => { calls.push(guid); return 3; },
reload: async () => { reloads++; },
});
assert.deepEqual(calls, ["g1"]);
assert.equal(out.kind, "updated");
assert.equal(out.affected, 3);
assert.equal(out.reloadFailed, false);
assert.equal(reloads, 1);
});
test("恢复成功:已停发线才发恢复请求", async () => {
let requested = "";
let reloads = 0;
const out = await runLineAction({
flowGuid: "g2",
lineOffline: 1,
action: "enable",
request: async (guid) => { requested = guid; return 2; },
reload: async () => { reloads++; },
});
assert.equal(requested, "g2");
assert.equal(out.kind, "updated");
assert.equal(out.affected, 2);
assert.equal(reloads, 1);
});
test("重复停发被前端状态守卫拦下:不发请求、不刷新", async () => {
let requests = 0;
let reloads = 0;
const out = await runLineAction({
flowGuid: "g3",
lineOffline: 1,
action: "offline",
request: async () => { requests++; return 1; },
reload: async () => { reloads++; },
});
assert.equal(out.kind, "skipped");
assert.equal(out.reason, "already-offline");
assert.equal(requests, 0);
assert.equal(reloads, 0);
});
test("恢复一条未停发的线被拦下:不发请求、不刷新", async () => {
let requests = 0;
const out = await runLineAction({
flowGuid: "g4",
lineOffline: 0,
action: "enable",
request: async () => { requests++; return 1; },
reload: async () => {},
});
assert.equal(out.kind, "skipped");
assert.equal(out.reason, "not-offline");
assert.equal(requests, 0);
});
test("空 flowGuid 不发请求(历史脏行防误操作整线)", async () => {
let requests = 0;
const out = await runLineAction({
flowGuid: "",
lineOffline: 0,
action: "offline",
request: async () => { requests++; return 1; },
reload: async () => {},
});
assert.equal(out.kind, "skipped");
assert.equal(out.reason, "no-guid");
assert.equal(requests, 0);
});
test("接口返回 0 行:报 empty 但仍刷新列表以同步真实状态", async () => {
let reloads = 0;
const out = await runLineAction({
flowGuid: "g5",
lineOffline: 0,
action: "offline",
request: async () => 0,
reload: async () => { reloads++; },
});
assert.equal(out.kind, "empty");
assert.equal(out.affected, 0);
assert.equal(reloads, 1);
});
test("接口失败向上抛出,且不触发刷新", async () => {
let reloads = 0;
await assert.rejects(() => runLineAction({
flowGuid: "g6",
lineOffline: 0,
action: "offline",
request: async () => { throw new Error("无流程管理权限"); },
reload: async () => { reloads++; },
}), /无流程管理权限/);
assert.equal(reloads, 0);
});
test("操作成功但刷新失败:保留成功结果并标记 reloadFailed", async () => {
const out = await runLineAction({
flowGuid: "g7",
lineOffline: 1,
action: "enable",
request: async () => 1,
reload: async () => { throw new Error("网络异常"); },
});
assert.equal(out.kind, "updated");
assert.equal(out.affected, 1);
assert.equal(out.reloadFailed, true);
});
test("错误文案:权限/网络异常与后端业务错误分开提示", () => {
assert.match(lineActionErrorDetail("网络错误"), /权限/);
assert.match(lineActionErrorDetail("Failed to fetch"), /网络异常/);
assert.match(lineActionErrorDetail(""), /网络异常/);
assert.equal(lineActionErrorDetail("流程线不存在:g1"), "流程线不存在:g1");
});
test("静态接线:Defs.vue 使用线级接口,不混入 listAll 或重复查询", () => {
const defs = readFileSync(resolve(process.cwd(), "src/views/flow/admin/Defs.vue"), "utf8");
assert.match(defs, /defOfflineLine/);
assert.match(defs, /defEnableLine/);
assert.match(defs, /lineOffline/);
assert.match(defs, /停发流程线/);
assert.match(defs, /恢复流程线/);
assert.match(defs, /versionActions/);
assert.doesNotMatch(defs, /listAll/);
});
test("静态接线:API 客户端使用既有 admin 端点与 flowGuid 请求体", () => {
const api = readFileSync(resolve(process.cwd(), "src/api/module/flow.ts"), "utf8");
assert.match(api, /`\$\{ROOT\}\/admin\/def\/offlineLine`, \{ flowGuid \}/);
assert.match(api, /`\$\{ROOT\}\/admin\/def\/enableLine`, \{ flowGuid \}/);
});