test/shared/email-renderer/package-grouping.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 { groups } from "#db/groups.ts";
import { createTestGroup } from "#test-utils/db-helpers/groups.ts";
import { createTestListing } from "#test-utils/db-helpers/listings.ts";
import { makeTestEntry as makeEntry } from "#test-utils/factories.ts";
import { buildTestData, describeEmailRenderer } from "./test-helpers.ts";
describeEmailRenderer(() => {
describe("package grouping", () => {
const buildPackageEntries = async (hide: boolean) => {
const group = await createTestGroup({
isPackage: true,
name: "Camp Kit",
});
if (hide) {
await groups.table.update(group.id, { hidePackageListings: true });
}
const tent = await createTestListing({
groupId: group.id,
name: "Tent",
unitPrice: 0,
});
const chair = await createTestListing({
groupId: group.id,
name: "Chair",
unitPrice: 500,
});
return [
makeEntry(
{ id: tent.id, name: "Tent", unit_price: 0 },
{ package_group_id: group.id, price_paid: "2000", quantity: 2 },
),
makeEntry(
{ id: chair.id, name: "Chair", unit_price: 500 },
{ package_group_id: group.id, price_paid: "3000", quantity: 6 },
),
];
};
test("a non-hidden package heads the email with its name and lists members", async () => {
const data = await buildTestData(await buildPackageEntries(false));
expect(data.listing_names).toBe("Camp Kit");
expect(data.entries.map((entry) => entry.listing.name)).toEqual([
"Tent",
"Chair",
]);
});
test("a hidden package collapses to one row for the buyer's confirmation", async () => {
const data = await buildTestData(await buildPackageEntries(true), {
hidePackageMembers: true,
});
expect(data.listing_names).toBe("Camp Kit");
expect(data.entries.length).toBe(1);
expect(data.entries[0]!.listing.name).toBe("Camp Kit");
expect(data.entries[0]!.attendee.quantity).toBe(8);
expect(data.entries[0]!.attendee.price_paid).toBe("5000");
expect(data.entries[0]!.listing.is_paid).toBe(true);
expect(data.entries[0]!.attendee.date_range_label).toBe("");
expect(data.entries[0]!.listing.slug).toBe("");
});
test("a collapsed hidden package of free-base members is paid from prices", async () => {
const group = await createTestGroup({
isPackage: true,
name: "Free Kit",
});
await groups.table.update(group.id, { hidePackageListings: true });
const memberA = await createTestListing({
groupId: group.id,
name: "A",
unitPrice: 0,
});
const memberB = await createTestListing({
groupId: group.id,
name: "B",
unitPrice: 0,
});
const data = await buildTestData(
[
makeEntry(
{ id: memberA.id, name: "A", unit_price: 0 },
{ package_group_id: group.id, price_paid: "1000", quantity: 1 },
),
makeEntry(
{ id: memberB.id, name: "B", unit_price: 0 },
{ package_group_id: group.id, price_paid: "0", quantity: 1 },
),
],
{ hidePackageMembers: true },
);
expect(data.entries.length).toBe(1);
expect(data.entries[0]!.listing.is_paid).toBe(true);
});
test("a dated hidden package collapses keeping the widest member's range", async () => {
const group = await createTestGroup({
isPackage: true,
name: "Dated Kit",
});
await groups.table.update(group.id, { hidePackageListings: true });
const spans: [name: string, endDate: string | null][] = [
["Day Only", null],
["Narrow A", "2026-08-02"],
["Wide", "2026-08-04"],
["Narrow B", "2026-08-02"],
];
const entries = [];
for (const [name, endDate] of spans) {
const listing = await createTestListing({
groupId: group.id,
name,
unitPrice: 500,
});
entries.push(
makeEntry(
{ id: listing.id, name, unit_price: 500 },
{
date: "2026-08-01",
end_date: endDate,
package_group_id: group.id,
price_paid: "500",
quantity: 1,
},
),
);
}
const data = await buildTestData(entries, { hidePackageMembers: true });
expect(data.entries.length).toBe(1);
expect(data.entries[0]!.attendee.date).toBe("2026-08-01");
expect(data.entries[0]!.attendee.date_range_label).toBe(
"1–3 August 2026",
);
});
test("a hidden package still shows members in the admin notification", async () => {
const data = await buildTestData(await buildPackageEntries(true));
expect(data.entries.map((entry) => entry.listing.name)).toEqual([
"Tent",
"Chair",
]);
});
test("a mixed order conceals its hidden bundle beside plain rows", async () => {
const entries = await buildPackageEntries(true);
const lantern = await createTestListing({
name: "Lantern",
unitPrice: 300,
});
entries.push(
makeEntry(
{ id: lantern.id, name: "Lantern", unit_price: 300 },
{ price_paid: "300", quantity: 1 },
),
);
const data = await buildTestData(entries, { hidePackageMembers: true });
expect(data.listing_names).toBe("Camp Kit and Lantern");
expect(data.entries.map((entry) => entry.listing.name)).toEqual([
"Camp Kit",
"Lantern",
]);
expect(data.entries[0]!.attendee.quantity).toBe(8);
expect(data.entries[1]!.attendee.quantity).toBe(1);
});
test("one row of a hidden bundle still collapses behind the bundle's name", async () => {
// Booking one thing out of a hidden bundle is still a bundle booking, so
// the row it collapses to carries the bundle's name and the buyer's own
// contact — the whole point of hiding the members.
const group = await createTestGroup({
isPackage: true,
name: "Single Kit",
});
await groups.table.update(group.id, { hidePackageListings: true });
const only = await createTestListing({
groupId: group.id,
name: "Only Member",
unitPrice: 500,
});
const entry = makeEntry(
{ id: only.id, name: "Only Member", unit_price: 500 },
{ package_group_id: group.id, price_paid: "1500", quantity: 3 },
);
const data = await buildTestData([entry], { hidePackageMembers: true });
expect(data.entries.length).toBe(1);
expect(data.entries[0]!.listing.name).toBe("Single Kit");
expect(data.entries[0]!.attendee.quantity).toBe(3);
expect(data.entries[0]!.attendee.price_paid).toBe("1500");
// The buyer's own contact comes from the row that was booked, so a
// collapse that reached past it for a second row it does not have would
// fail here rather than send an email addressed to nobody.
expect(data.entries[0]!.attendee.name).toBe(entry.attendee.name);
expect(data.entries[0]!.attendee.email).toBe(entry.attendee.email);
});
test("a standalone booking of a hidden one-member package's listing is NOT collapsed", async () => {
const group = await createTestGroup({
isPackage: true,
name: "Solo Kit",
});
await groups.table.update(group.id, { hidePackageListings: true });
const widget = await createTestListing({
groupId: group.id,
name: "Widget",
unitPrice: 500,
});
const data = await buildTestData(
[
makeEntry(
{ id: widget.id, name: "Widget", unit_price: 500 },
{ price_paid: "1500", quantity: 3 },
),
],
{ hidePackageMembers: true },
);
expect(data.listing_names).toBe("Widget");
expect(data.entries.length).toBe(1);
expect(data.entries[0]!.listing.name).toBe("Widget");
});
});
});