Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/utils/db/tenantSubscriptions.db.server.test.ts
T

61 lines
2.6 KiB
TypeScript

// @vitest-environment node
import { describe, expect, it, vi } from "vitest";
// Stripe-driven subscription mutations must purge the cache cross-replica,
// not just in-process — assert these wrappers route through the publishing
// helper `clearTenantSubscriptionCache` (which fans out on pub/sub).
//
// The mock fn is parked on `globalThis` so the hoisted `vi.mock` factory can
// reach it without a top-level reference (vitest 0.29 has no `vi.hoisted`).
type CacheMocks = { clearTenantSubscriptionCache: ReturnType<typeof vi.fn> };
function getMocks(): CacheMocks {
const store = globalThis as typeof globalThis & { __tenantSubsDbCacheMocks__?: CacheMocks };
store.__tenantSubsDbCacheMocks__ ??= { clearTenantSubscriptionCache: vi.fn() };
return store.__tenantSubsDbCacheMocks__;
}
vi.mock("@toolctrl/db/subscriptions.server", () => ({
createTenantSubscription: vi.fn(),
getTenantSubscription: vi.fn(),
getTenantSubscriptions: vi.fn(),
updateTenantSubscriptionCustomerId: vi.fn(),
}));
vi.mock("~/utils/services/.server/subscriptionService", () => ({
clearTenantSubscriptionCache: getMocks().clearTenantSubscriptionCache,
}));
import { createTenantSubscription, updateTenantSubscriptionCustomerId } from "./tenantSubscriptions.db.server";
import {
createTenantSubscription as persistTenantSubscription,
updateTenantSubscriptionCustomerId as persistTenantSubscriptionCustomerId,
} from "@toolctrl/db/subscriptions.server";
const mocks = getMocks();
describe("tenantSubscriptions db wrapper — cross-replica cache invalidation", () => {
it("createTenantSubscription publishes a cross-replica invalidation for the tenant", async () => {
mocks.clearTenantSubscriptionCache.mockClear();
vi.mocked(persistTenantSubscription).mockResolvedValueOnce({
tenantId: "tenant-a",
} as Awaited<ReturnType<typeof persistTenantSubscription>>);
await createTenantSubscription("tenant-a", "cus_x");
expect(mocks.clearTenantSubscriptionCache).toHaveBeenCalledTimes(1);
expect(mocks.clearTenantSubscriptionCache).toHaveBeenCalledWith("tenant-a");
});
it("updateTenantSubscriptionCustomerId publishes a cross-replica invalidation for the tenant", async () => {
mocks.clearTenantSubscriptionCache.mockClear();
vi.mocked(persistTenantSubscriptionCustomerId).mockResolvedValueOnce(
{} as Awaited<ReturnType<typeof persistTenantSubscriptionCustomerId>>,
);
await updateTenantSubscriptionCustomerId("tenant-b", { stripeCustomerId: "cus_y" });
expect(mocks.clearTenantSubscriptionCache).toHaveBeenCalledTimes(1);
expect(mocks.clearTenantSubscriptionCache).toHaveBeenCalledWith("tenant-b");
});
});