test/shared/capacity-rules.test.ts
Rama main · réplica de lectura del repositorio original.
import { expect } from "@std/expect";
import { describe, it as test } from "@std/testing/bdd";
import {
allCapacityFacets,
applicableCapacityRules,
assertCapacityRulesCoherent,
CAPACITY_RULES,
type CapacityFacet,
type CapacityRule,
type CapacityRuleKey,
capacityDateFor,
capacityRuleTypeSql,
countsPerDate,
hasDateLessCap,
listingTypesWithRule,
} from "#shared/capacity-rules.ts";
/** The checks that apply to every listing, whatever its facets. */
const UNIVERSAL = [
"groupPoolCap",
"parentChildUnits",
"adminOverbookBypass",
] as const;
describe("capacity rules", () => {
describe("applicableCapacityRules", () => {
test("a standard listing counts its own cap as one running total", () => {
for (const customisable_days of [false, true]) {
expect(
applicableCapacityRules({
customisable_days,
listing_type: "standard",
}),
).toEqual(new Set(["dateLessCap", ...UNIVERSAL]));
}
});
test("a daily listing counts its own cap per occupied date", () => {
for (const customisable_days of [false, true]) {
expect(
applicableCapacityRules({ customisable_days, listing_type: "daily" }),
).toEqual(new Set(["perDateCap", ...UNIVERSAL]));
}
});
});
describe("hasDateLessCap", () => {
test("true exactly for the facets carrying the dateLessCap rule", () => {
for (const facet of allCapacityFacets()) {
expect(hasDateLessCap(facet)).toBe(facet.listing_type === "standard");
}
});
});
describe("countsPerDate", () => {
test("true only for listing types with the perDateCap rule", () => {
expect(countsPerDate("daily")).toBe(true);
expect(countsPerDate("standard")).toBe(false);
});
});
describe("capacityDateFor", () => {
test("a per-date listing keeps the booking's date", () => {
expect(capacityDateFor("daily", "2026-05-01")).toBe("2026-05-01");
});
test("a per-date listing with no date checks date-lessly", () => {
expect(capacityDateFor("daily", null)).toBe(null);
expect(capacityDateFor("daily", undefined)).toBe(null);
});
test("only a missing date falls back — a present string passes through untouched", () => {
// Date validation lives upstream; this helper must not second-guess it.
expect(capacityDateFor("daily", "")).toBe("");
});
test("a running-total listing always drops the date", () => {
expect(capacityDateFor("standard", "2026-05-01")).toBe(null);
expect(capacityDateFor("standard", undefined)).toBe(null);
});
});
describe("listingTypesWithRule", () => {
test("maps each own-cap rule to its listing types", () => {
expect(listingTypesWithRule("perDateCap")).toEqual(["daily"]);
expect(listingTypesWithRule("dateLessCap")).toEqual(["standard"]);
});
test("a universal rule maps to every listing type", () => {
expect(listingTypesWithRule("groupPoolCap")).toEqual([
"standard",
"daily",
]);
});
test("rejects a rule whose applicability depends on customisable days", () => {
const rules: CapacityRule[] = [
{ appliesTo: (facet) => facet.customisable_days, key: "perDateCap" },
];
expect(() => listingTypesWithRule("perDateCap", rules)).toThrow(
"cannot be keyed by listing type alone",
);
});
});
describe("capacityRuleTypeSql", () => {
test("emits the type predicate the SQL guard interpolates", () => {
expect(capacityRuleTypeSql("perDateCap", "listing.listing_type")).toBe(
"listing.listing_type IN ('daily')",
);
expect(
capacityRuleTypeSql("dateLessCap", "memberListing.listing_type"),
).toBe("memberListing.listing_type IN ('standard')");
expect(capacityRuleTypeSql("groupPoolCap", "t")).toBe(
"t IN ('standard', 'daily')",
);
});
});
describe("assertCapacityRulesCoherent", () => {
/** The production table with some rules' applicability swapped out. */
const tableWith = (
over: Partial<Record<CapacityRuleKey, (facet: CapacityFacet) => boolean>>,
): CapacityRule[] =>
CAPACITY_RULES.map((rule) => {
const appliesTo = over[rule.key];
return appliesTo ? { appliesTo, key: rule.key } : rule;
});
test("accepts the production table unchanged", () => {
expect(assertCapacityRulesCoherent(CAPACITY_RULES)).toBe(CAPACITY_RULES);
});
test("rejects a table missing one of the known checks", () => {
const missing = CAPACITY_RULES.filter(
(rule) => rule.key !== "perDateCap",
);
expect(() => assertCapacityRulesCoherent(missing)).toThrow(
'Capacity rule "perDateCap" must be declared exactly once, found 0',
);
});
test("rejects a table declaring the same check twice", () => {
const doubled = [
...CAPACITY_RULES,
{ appliesTo: () => true, key: "groupPoolCap" } as CapacityRule,
];
expect(() => assertCapacityRulesCoherent(doubled)).toThrow(
'Capacity rule "groupPoolCap" must be declared exactly once, found 2',
);
});
test("rejects a table where a listing would be counted twice", () => {
const both = tableWith({ perDateCap: () => true });
expect(() => assertCapacityRulesCoherent(both)).toThrow(
"exactly one own-cap counting rule, found 2",
);
});
test("rejects a table where a listing would never be counted", () => {
const neither = tableWith({ dateLessCap: () => false });
expect(() => assertCapacityRulesCoherent(neither)).toThrow(
"exactly one own-cap counting rule, found 0",
);
});
test("rejects a rule no listing can ever match", () => {
const withDeadRule = tableWith({ groupPoolCap: () => false });
expect(() => assertCapacityRulesCoherent(withDeadRule)).toThrow(
'Capacity rule "groupPoolCap" applies to no listing',
);
});
});
describe("allCapacityFacets", () => {
test("covers every listing type × customisable days combination", () => {
expect(allCapacityFacets()).toEqual([
{ customisable_days: false, listing_type: "standard" },
{ customisable_days: true, listing_type: "standard" },
{ customisable_days: false, listing_type: "daily" },
{ customisable_days: true, listing_type: "daily" },
]);
});
});
});