61 lines
2.6 KiB
TypeScript
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");
|
|
});
|
|
});
|