Files
TallyNote/tests/core.test.ts
T
Qiufeng 9719429f4a
TallyNote release / linux-x64 (push) Failing after 2m41s
feat: add TallyNote local reimbursement ledger
2026-08-29 01:02:29 +08:00

45 lines
2.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { amountToCents, centsToAmount, exportRequestSchema } from "../shared/contracts.js";
import { zonedMonthBounds } from "../server/app.js";
import { safeExcelText } from "../server/exporter.js";
import { safeStoragePath, sanitizeOriginalName } from "../server/files.js";
describe("金额", () => {
it("按分精确转换并格式化", () => {
expect(amountToCents("12.3")).toBe(1230);
expect(amountToCents("0.01")).toBe(1);
expect(centsToAmount(1234)).toBe("12.34");
expect(() => amountToCents("12.345")).toThrow();
expect(() => amountToCents("0")).toThrow();
});
});
describe("时区月份", () => {
it("按 Asia/Shanghai 返回 UTC 月份边界", () => {
const [start, end] = zonedMonthBounds("2026-08", "Asia/Shanghai");
expect(new Date(start).toISOString()).toBe("2026-07-31T16:00:00.000Z");
expect(new Date(end).toISOString()).toBe("2026-08-31T16:00:00.000Z");
});
});
describe("导出选项", () => {
it("默认不包含 manifest.json,并支持显式开启", () => {
expect(exportRequestSchema.parse({ ids: ["00000000-0000-4000-8000-000000000001"] }).includeManifest).toBe(false);
expect(exportRequestSchema.parse({ month: "2026-08", status: "unreimbursed" }).includeManifest).toBe(false);
expect(exportRequestSchema.parse({ ids: ["00000000-0000-4000-8000-000000000001"], includeManifest: true }).includeManifest).toBe(true);
});
});
describe("文件和导出安全", () => {
it("不让用户文件名参与路径", () => {
expect(sanitizeOriginalName("../../秘密\u0000.png")).toBe("秘密.png");
expect(safeStoragePath("/tmp/tallynote-files", "ab/example.png")).toBe("/tmp/tallynote-files/ab/example.png");
expect(() => safeStoragePath("/tmp/tallynote-files", "../outside")).toThrow();
});
it("阻止 Excel 公式注入", () => {
expect(safeExcelText("=HYPERLINK(\"https://example.com\")")).toBe("'=HYPERLINK(\"https://example.com\")");
expect(safeExcelText("普通备注")).toBe("普通备注");
});
});