Files
NianAIGC/tests/organization-balance.test.ts
T
2026-10-02 19:56:32 +08:00

53 lines
2.8 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
import { fetchOrganizationBalance } from "@/lib/client/organization-balance";
const payload = (balanceFen = 12345) => ({
organization: { id: "org-current", name: "当前组织" },
wallet: { organizationId: "org-current", balanceFen, updatedAt: "2026-10-01T00:00:00Z" }
});
afterEach(() => vi.unstubAllGlobals());
describe("creation organization balance", () => {
it.each([12345, 0, -100])("preserves the available balance %i without substituting a fallback", async (amount) => {
const fetchMock = vi.fn().mockResolvedValue(Response.json(payload(amount)));
vi.stubGlobal("fetch", fetchMock);
const controller = new AbortController();
expect((await fetchOrganizationBalance("org-current", controller.signal)).wallet.balanceFen).toBe(amount);
expect(fetchMock).toHaveBeenCalledWith("/api/billing/balance", { cache: "no-store", signal: controller.signal });
});
it.each([
{ ...payload(), wallet: { ...payload().wallet, organizationId: "org-other" } },
{ ...payload(), wallet: { ...payload().wallet, balanceFen: "12345" } },
{ ...payload(), wallet: { ...payload().wallet, balanceFen: 1.5 } },
{ organization: payload().organization },
null
])("rejects malformed or other-organization responses instead of showing a balance", async (value) => {
vi.stubGlobal("fetch", vi.fn().mockResolvedValue(Response.json(value)));
await expect(fetchOrganizationBalance("org-current")).rejects.toThrow("余额信息不完整");
});
it("explains when the server has refreshed the user into a different organization", async () => {
vi.stubGlobal("fetch", vi.fn().mockResolvedValue(Response.json({
...payload(), organization: { id: "org-other", name: "新组织" }
})));
await expect(fetchOrganizationBalance("org-current")).rejects.toThrow("账号所属组织已变更,请刷新页面");
});
it.each([401, 403, 422])("explains expired or changed access for HTTP %i", async (status) => {
vi.stubGlobal("fetch", vi.fn().mockResolvedValue(Response.json({}, { status })));
await expect(fetchOrganizationBalance("org-current")).rejects.toThrow("登录状态或组织信息已变更,请刷新页面");
});
it("does not expose internal errors or turn failures into zero balance", async () => {
vi.stubGlobal("fetch", vi.fn().mockResolvedValue(Response.json({ error: "internal database details" }, { status: 500 })));
await expect(fetchOrganizationBalance("org-current")).rejects.toThrow("余额暂时无法读取,请重试。");
});
it("handles a non-JSON proxy response as an error", async () => {
vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response("gateway unavailable", { status: 502 })));
await expect(fetchOrganizationBalance("org-current")).rejects.toThrow("余额暂时无法读取,请重试。");
});
});