文件
hyb-oa/server/tests/unit/scripts/payment-batch-flag-snapshot.test.js
T
wangsli 37b4ef2d10
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s
恢复付款入口与常开基线(08-01-reimbursement-notification-progress-clarity)
2026-08-01 23:12:23 +08:00

149 行
5.1 KiB
JavaScript

const { execFile } = require("node:child_process");
const { mkdtemp, readFile, rm } = require("node:fs/promises");
const http = require("node:http");
const os = require("node:os");
const path = require("node:path");
const { promisify } = require("node:util");
const execFileAsync = promisify(execFile);
const ROOT_DIR = path.resolve(__dirname, "../../../..");
const SNAPSHOT_SCRIPT = path.join(ROOT_DIR, "scripts/qa/payment-batch-flag-snapshot.mjs");
async function readJsonBody(request) {
const chunks = [];
for await (const chunk of request) chunks.push(chunk);
return JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
}
async function withFlagApi(initialFlag, callback) {
let flag = { ...initialFlag, departmentIds: [...initialFlag.departmentIds] };
const server = http.createServer(async (request, response) => {
response.setHeader("content-type", "application/json");
if (request.method === "POST" && request.url === "/api/auth/login") {
response.end(JSON.stringify({ data: { accessToken: "synthetic-access-token" } }));
return;
}
if (request.method === "GET" && request.url === "/api/system/feature-flags") {
response.end(JSON.stringify({ data: { items: [flag] } }));
return;
}
if (request.method === "PUT" && request.url === "/api/system/feature-flags/payment_batch_v1") {
const body = await readJsonBody(request);
if (body.expectedVersion !== flag.version) {
response.statusCode = 409;
response.end(JSON.stringify({ error: { code: "CONFLICT" } }));
return;
}
flag = {
...flag,
overrideMode: body.overrideMode,
rolloutType: body.rolloutType,
departmentIds: [...body.departmentIds],
note: body.note,
version: flag.version + 1,
effectiveEnabled: body.overrideMode === "force_on",
effectiveReason: `mock_${body.overrideMode}`,
};
response.end(JSON.stringify({ data: { item: flag } }));
return;
}
response.statusCode = 404;
response.end(JSON.stringify({ error: { code: "NOT_FOUND" } }));
});
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
const address = server.address();
const baseUrl = `http://127.0.0.1:${address.port}`;
try {
await callback({
baseUrl,
getFlag: () => flag,
setFlag: (next) => {
flag = { ...next, departmentIds: [...next.departmentIds] };
},
});
} finally {
await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
}
}
function runSnapshotScript(action, baseUrl, snapshotFile) {
return execFileAsync(process.execPath, [SNAPSHOT_SCRIPT, action, "--snapshot-file", snapshotFile], {
env: {
...process.env,
P2_FIN_LIVE_APPROVED: "1",
LIVE_SMOKE_BASE_URL: baseUrl,
LIVE_SMOKE_ADMIN_IDENTIFIER: "synthetic-admin",
LIVE_SMOKE_ADMIN_PASSWORD: "synthetic-password",
},
});
}
describe.each([
{
label: "force_off allowlist",
initial: {
flagKey: "payment_batch_v1",
overrideMode: "force_off",
rolloutType: "department_allowlist",
departmentIds: ["00000000-0000-4000-8000-000000000001"],
note: "original off note",
version: 3,
effectiveEnabled: false,
effectiveReason: "flag_force_off",
},
},
{
label: "force_on global",
initial: {
flagKey: "payment_batch_v1",
overrideMode: "force_on",
rolloutType: "global",
departmentIds: [],
note: "original on note",
version: 8,
effectiveEnabled: true,
effectiveReason: "flag_force_on_global",
},
},
])("payment batch flag snapshot: $label", ({ initial }) => {
it("restores the caller configuration instead of forcing a fixed mode", async () => {
const tempDir = await mkdtemp(path.join(os.tmpdir(), "hyb-oa-payment-flag-"));
const snapshotFile = path.join(tempDir, "snapshot.json");
try {
await withFlagApi(initial, async ({ baseUrl, getFlag, setFlag }) => {
await runSnapshotScript("capture", baseUrl, snapshotFile);
const saved = JSON.parse(await readFile(snapshotFile, "utf8"));
expect(saved).toMatchObject({
overrideMode: initial.overrideMode,
rolloutType: initial.rolloutType,
departmentIds: initial.departmentIds,
note: initial.note,
effectiveEnabled: initial.effectiveEnabled,
});
setFlag({
...getFlag(),
overrideMode: initial.overrideMode === "force_on" ? "force_off" : "force_on",
rolloutType: "global",
departmentIds: [],
note: "temporary window state",
version: getFlag().version + 1,
effectiveEnabled: initial.overrideMode !== "force_on",
effectiveReason: "temporary",
});
await runSnapshotScript("restore", baseUrl, snapshotFile);
expect(getFlag()).toMatchObject({
overrideMode: initial.overrideMode,
rolloutType: initial.rolloutType,
departmentIds: initial.departmentIds,
note: initial.note,
});
});
} finally {
await rm(tempDir, { recursive: true, force: true });
}
});
});