53 lines
2.8 KiB
TypeScript
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("余额暂时无法读取,请重试。");
|
|
});
|
|
});
|