Files
cfw-autumn/server/tests/integration/billing/utils/sync/expectSubscriptionMatch.ts
2026-05-05 18:06:39 +08:00

90 lines
2.3 KiB
TypeScript

import { expect } from "bun:test";
import type {
PlanBase,
SubscriptionMatch,
} from "@/internal/billing/v2/actions/sync/detect/types";
export type ExpectedMatchedPlan = {
plan_id?: string;
base_kind?: PlanBase["kind"];
};
export type ExpectedPhaseMatch = {
plans: ExpectedMatchedPlan[];
is_current?: boolean;
/** When true, asserts no Stripe items in this phase are unmatched. */
noUnmatchedItems?: boolean;
};
export type ExpectedCurrentPhase = {
plans: ExpectedMatchedPlan[];
/** When set, asserts no Stripe items in the current phase are unmatched. */
noUnmatchedItems?: boolean;
};
const expectPhaseMatchCorrect = ({
phase,
expected,
}: {
phase: SubscriptionMatch["phaseMatches"][number];
expected: ExpectedPhaseMatch;
}) => {
if (expected.is_current !== undefined) {
expect(phase.is_current).toBe(expected.is_current);
}
expect(phase.plans).toHaveLength(expected.plans.length);
expected.plans.forEach((expectedPlan, planIndex) => {
const plan = phase.plans[planIndex];
if (expectedPlan.plan_id !== undefined) {
expect(plan.product.id).toBe(expectedPlan.plan_id);
}
if (expectedPlan.base_kind !== undefined) {
expect(plan.base.kind).toBe(expectedPlan.base_kind);
}
});
if (expected.noUnmatchedItems) {
const unmatched = phase.item_diffs.filter((d) => d.match.kind === "none");
expect(unmatched).toEqual([]);
}
};
/**
* Match-side counterpart to `expectSyncParamsCorrect` — asserts on the
* detection result (`SubscriptionMatch`).
*
* Pass `currentPhase` to assert against the current phase only. Pass
* `phaseMatches` to assert against every phase by index (the order matches
* `match.phaseMatches`).
*/
export const expectSubscriptionMatchCorrect = ({
match,
currentPhase,
phaseMatches,
}: {
match: SubscriptionMatch;
currentPhase?: ExpectedCurrentPhase;
phaseMatches?: ExpectedPhaseMatch[];
}) => {
if (currentPhase) {
const phase = match.phaseMatches.find((p) => p.is_current);
expect(phase).toBeDefined();
expectPhaseMatchCorrect({
phase: phase!,
expected: {
plans: currentPhase.plans,
noUnmatchedItems: currentPhase.noUnmatchedItems,
},
});
}
if (phaseMatches) {
expect(match.phaseMatches).toHaveLength(phaseMatches.length);
phaseMatches.forEach((expected, i) => {
expectPhaseMatchCorrect({ phase: match.phaseMatches[i], expected });
});
}
};