文件
hyb-oa/server/tests/unit/scripts/seed-config.defaults.test.js
T

205 行
7.3 KiB
JavaScript

const {
DEFAULT_APPROVAL_RULES,
DEFAULT_FEATURE_FLAGS,
ENABLED_EXPENSE_TYPES,
seedApprovalRules,
seedExpenseTypes,
seedFeatureFlags,
} = require("../../../src/scripts/seed-config");
describe("default travel expense types", () => {
it("keeps intercity bus tickets separate from the two travel allowances", () => {
expect(ENABLED_EXPENSE_TYPES).toEqual(
expect.arrayContaining([
expect.objectContaining({ code: "travel_bus", name: "大巴车票", category: "travel" }),
expect.objectContaining({ code: "travel_meal", name: "伙食补助费", category: "travel" }),
expect.objectContaining({
code: "travel_local_transport_allowance",
name: "市内交通补助费",
category: "travel",
}),
]),
);
const travelCodes = ENABLED_EXPENSE_TYPES.filter((item) =>
["travel_bus", "travel_meal", "travel_local_transport_allowance"].includes(item.code),
);
expect(travelCodes).toHaveLength(3);
});
it("upserts the distinct travel types by stable code", async () => {
const upsert = vi.fn().mockResolvedValue({});
await seedExpenseTypes({ expenseType: { upsert } });
for (const [code, name] of [
["travel_bus", "大巴车票"],
["travel_meal", "伙食补助费"],
["travel_local_transport_allowance", "市内交通补助费"],
]) {
expect(upsert).toHaveBeenCalledWith(
expect.objectContaining({
where: { code },
update: expect.objectContaining({ name, enabled: true }),
create: expect.objectContaining({ code, name, enabled: true }),
}),
);
}
});
});
describe("reimbursement expense policy defaults", () => {
it("keeps only the two allowances invoice-free and replaces ambiguous selectable types", () => {
expect(ENABLED_EXPENSE_TYPES).toEqual(expect.arrayContaining([
expect.objectContaining({ code: "business_client_meal", name: "业务招待费" }),
expect.objectContaining({ code: "business_meeting", name: "会议费" }),
expect.objectContaining({ code: "business_training_fee", name: "培训费" }),
expect.objectContaining({ code: "assets_office_electronics", name: "办公电子设备" }),
expect.objectContaining({ code: "travel_meal", requiresInvoice: false }),
expect.objectContaining({ code: "travel_local_transport_allowance", requiresInvoice: false }),
]));
expect(ENABLED_EXPENSE_TYPES.some((item) => item.code === "business_training")).toBe(false);
expect(ENABLED_EXPENSE_TYPES.some((item) => item.code === "assets_it_hardware")).toBe(false);
});
it("provides employee-readable guidance for every selectable expense type", () => {
for (const expenseType of ENABLED_EXPENSE_TYPES) {
expect(expenseType.description, expenseType.code).toEqual(expect.any(String));
expect(expenseType.description.trim().length, expenseType.code).toBeGreaterThan(0);
}
});
it("uses asset-registration guidance without inventing a prior-approval policy", () => {
const assetTypes = ENABLED_EXPENSE_TYPES.filter((item) => item.category === "assets");
expect(assetTypes.map((item) => item.code)).toEqual([
"assets_equipment",
"assets_furniture",
"assets_office_electronics",
]);
for (const expenseType of assetTypes) {
expect(expenseType.description).toContain("物品名称");
expect(expenseType.description).toContain("实际使用人或责任人");
expect(expenseType.description).toContain("存放位置");
expect(expenseType.description).not.toMatch(/事前批准|批准人|批准时间|批准依据/);
}
expect(assetTypes.find((item) => item.code === "assets_office_electronics")?.description)
.toContain("不等同于会计固定资产确认标准");
});
it("seeds the invoice guard disabled by default", () => {
expect(DEFAULT_FEATURE_FLAGS).toContainEqual({
flag_key: "reimbursement_invoice_guard_v1",
override_mode: "force_off",
rollout_type: "global",
department_ids: [],
note: "bootstrap default: force_off",
});
});
it("preserves finance-maintained account mappings during repeated init", async () => {
const upsert = vi.fn().mockResolvedValue({});
await seedExpenseTypes({ expenseType: { upsert } });
for (const call of upsert.mock.calls) {
expect(call[0].update).not.toHaveProperty("account_code_default");
expect(call[0].create).toEqual(expect.objectContaining({ account_code_default: null }));
}
});
});
describe("small-team default reimbursement approval rules", () => {
it("uses finance for every owner fallback and finance review node", () => {
expect(DEFAULT_APPROVAL_RULES).toEqual([
expect.objectContaining({
name: "小额",
level1_role: "manager",
level2_role: "finance",
level3_role: null,
owner_self_fallback_role: "finance",
}),
expect.objectContaining({
name: "中额",
level1_role: "manager",
level2_role: "finance",
level3_role: null,
owner_self_fallback_role: "finance",
}),
expect.objectContaining({
name: "大额",
level1_role: "manager",
level2_role: "ceo",
level3_role: "finance",
owner_self_fallback_role: "finance",
}),
]);
});
it("preserves existing production approval rules instead of replacing them", async () => {
const approvalRule = {
count: vi.fn().mockResolvedValue(3),
createMany: vi.fn(),
deleteMany: vi.fn(),
};
await expect(seedApprovalRules({ approvalRule })).resolves.toEqual({
created: 0,
preserved: 3,
});
expect(approvalRule.createMany).not.toHaveBeenCalled();
expect(approvalRule.deleteMany).not.toHaveBeenCalled();
});
it("creates the three defaults only for an empty approval-rule table", async () => {
const approvalRule = {
count: vi.fn().mockResolvedValue(0),
createMany: vi.fn().mockResolvedValue({ count: 3 }),
};
await expect(seedApprovalRules({ approvalRule })).resolves.toEqual({
created: 3,
preserved: 0,
});
expect(approvalRule.createMany).toHaveBeenCalledWith({
data: DEFAULT_APPROVAL_RULES.map((item) => ({
...item,
enabled: true,
created_by: null,
updated_by: null,
})),
});
});
});
describe("trialrun payment batch baseline", () => {
it("creates payment_batch_v1 as globally enabled", () => {
expect(DEFAULT_FEATURE_FLAGS).toContainEqual({
flag_key: "payment_batch_v1",
override_mode: "force_on",
rollout_type: "global",
department_ids: [],
note: "bootstrap default: force_on",
});
});
it("preserves an existing payment flag instead of overwriting it", async () => {
const create = vi.fn(async ({ data }) => {
if (data.flag_key === "payment_batch_v1") {
throw Object.assign(new Error("unique conflict"), { code: "P2002" });
}
return data;
});
const prisma = { featureFlag: { create } };
await expect(seedFeatureFlags(prisma)).resolves.toBeUndefined();
expect(create).toHaveBeenCalledWith({
data: expect.objectContaining({
flag_key: "payment_batch_v1",
override_mode: "force_on",
}),
});
expect(prisma.featureFlag.update).toBeUndefined();
expect(prisma.featureFlag.upsert).toBeUndefined();
});
});