MatchMaster/server/laf-cloud/tests/ab-config-admin.test.mjs
2026-08-21 18:09:01 +08:00

174 lines
5.0 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { registerHooks } from "node:module";
const functionUrl = new URL("../functions/abConfigAdmin.ts", import.meta.url);
const state = {
configs: [],
nextId: 1,
};
function clone(value) {
return value == null ? value : JSON.parse(JSON.stringify(value));
}
function matches(document, query) {
return Object.keys(query).every(key => document[key] === query[key]);
}
function collection(name) {
assert.equal(name, "ab_config");
return {
async get() {
return { data: clone(state.configs) };
},
where(query) {
return {
async getOne() {
return { data: clone(state.configs.find(item => matches(item, query)) || null) };
},
async update(payload) {
const matched = state.configs.filter(item => matches(item, query));
matched.forEach(item => Object.assign(item, clone(payload)));
return { updated: matched.length };
},
async remove() {
const oldLength = state.configs.length;
state.configs = state.configs.filter(item => !matches(item, query));
return { deleted: oldLength - state.configs.length };
},
};
},
async add(payload) {
const document = { _id: `config-${state.nextId++}`, ...clone(payload) };
state.configs.push(document);
return { id: document._id };
},
};
}
globalThis.__abConfigAdminCloudMock = {
database() {
return { collection };
},
};
registerHooks({
resolve(specifier, context, nextResolve) {
if (specifier === "@lafjs/cloud") {
return {
url: "data:text/javascript,export default globalThis.__abConfigAdminCloudMock",
shortCircuit: true,
};
}
return nextResolve(specifier, context);
},
});
const { default: abConfigAdmin } = await import(functionUrl);
function reset() {
state.configs = [];
state.nextId = 1;
}
function config(extra = {}) {
return {
experimentId: "exp_layer_1_001",
layer: "1",
name: "Layer 1",
enabled: true,
resetAssignments: false,
variants: [{ group: "A", ratio: 50 }, { group: "B", ratio: 50 }],
...extra,
};
}
async function save(items) {
return await abConfigAdmin({
body: {
action: "save",
adminToken: "abtest-admin-token",
config: items,
},
});
}
test("resetVersion changes only on an enabled false-to-true transition", async () => {
reset();
await save([config()]);
assert.equal(state.configs[0].resetVersion, 0);
await save([config({ resetAssignments: true })]);
const firstVersion = state.configs[0].resetVersion;
assert.ok(firstVersion > 0);
await save([config({
experimentId: "exp_layer_1_002",
resetAssignments: true,
variants: [{ group: "A", ratio: 80 }, { group: "B", ratio: 20 }],
})]);
assert.equal(state.configs.length, 1);
assert.equal(state.configs[0].experimentId, "exp_layer_1_002");
assert.equal(state.configs[0].resetVersion, firstVersion);
await save([config({ experimentId: "exp_layer_1_002", resetAssignments: false })]);
assert.equal(state.configs[0].resetVersion, firstVersion);
await save([config({ experimentId: "exp_layer_1_002", resetAssignments: true })]);
assert.ok(state.configs[0].resetVersion > firstVersion);
});
test("a disabled layer does not create a reset version", async () => {
reset();
await save([config({ enabled: false })]);
await save([config({ enabled: false, resetAssignments: true })]);
assert.equal(state.configs[0].resetVersion, 0);
await save([config({ enabled: true, resetAssignments: true })]);
assert.equal(state.configs[0].resetVersion, 0);
await save([config({ enabled: true, resetAssignments: false })]);
await save([config({ enabled: true, resetAssignments: true })]);
assert.ok(state.configs[0].resetVersion > 0);
await save([config({ enabled: false, resetAssignments: true })]);
assert.equal(state.configs[0].resetVersion, 0);
await save([config({ enabled: true, resetAssignments: true })]);
assert.equal(state.configs[0].resetVersion, 0);
});
test("an existing enabled reset without a version is initialized on publish", async () => {
reset();
state.configs.push({ _id: "legacy", ...config({ resetAssignments: true }) });
const result = await save([config({ resetAssignments: true })]);
assert.equal(result.code, 1);
assert.ok(state.configs[0].resetVersion > 0);
});
test("Default is a case-insensitive reserved group name", async () => {
reset();
const result = await save([config({
variants: [{ group: "DEFAULT", ratio: 50 }, { group: "B", ratio: 50 }],
})]);
assert.equal(result.code, 0);
assert.match(result.msg, /Default.*reserved/i);
assert.equal(state.configs.length, 0);
});
test("the admin page explains edge-triggered reset behavior", async () => {
const ui = await readFile(new URL("../../xxwzUI.html", import.meta.url), "utf8");
assert.match(ui, /关闭→开启并发布/);
assert.match(ui, /关闭后未登录用户不补做/);
assert.match(ui, /Default.*系统保留/);
});