Vollstaendige Next.js/Prisma-E-Commerce-Anwendung fuer eine Imkerei: Shop, Warenkorb, Stripe-Checkout, Kundenkonto mit 2FA, Admin-Bereich (Produkte, Ernten, Chargen, Bestellungen, Gutscheine, admin-editierbare Website-Inhalte), i18n (DE/EN), Rate-Limiting/CSP/Audit-Log-Haertung, PostgreSQL- und MySQL-Unterstuetzung ueber austauschbare Prisma- Treiber-Adapter, Unit-/Komponenten-/E2E-Tests.
72 lines
2.5 KiB
TypeScript
72 lines
2.5 KiB
TypeScript
import { describe, test, expect } from "vitest";
|
|
import { resolveShippingCostCents, getNextShippingTier, FALLBACK_SHIPPING_CENTS } from "./shipping-calc";
|
|
|
|
const tiers = [
|
|
{ minQuantity: 0, maxQuantity: 3, priceCents: 700 },
|
|
{ minQuantity: 4, maxQuantity: 9, priceCents: 850 },
|
|
{ minQuantity: 10, maxQuantity: null, priceCents: 1100 },
|
|
];
|
|
|
|
describe("resolveShippingCostCents", () => {
|
|
test("returns 0 when the cart is empty", () => {
|
|
expect(resolveShippingCostCents(tiers, 0)).toBe(0);
|
|
});
|
|
|
|
test("falls back to a fixed price when no tiers are configured", () => {
|
|
expect(resolveShippingCostCents([], 5)).toBe(FALLBACK_SHIPPING_CENTS);
|
|
});
|
|
|
|
test("picks the lowest tier for a small quantity", () => {
|
|
expect(resolveShippingCostCents(tiers, 2)).toBe(700);
|
|
});
|
|
|
|
test("picks the middle tier at its lower boundary", () => {
|
|
expect(resolveShippingCostCents(tiers, 4)).toBe(850);
|
|
});
|
|
|
|
test("picks the middle tier at its upper boundary", () => {
|
|
expect(resolveShippingCostCents(tiers, 9)).toBe(850);
|
|
});
|
|
|
|
test("applies the open-ended top tier for large quantities", () => {
|
|
expect(resolveShippingCostCents(tiers, 500)).toBe(1100);
|
|
});
|
|
|
|
test("uses the topmost tier when the quantity exceeds every defined tier", () => {
|
|
const closedTiers = [{ minQuantity: 0, maxQuantity: 3, priceCents: 700 }];
|
|
expect(resolveShippingCostCents(closedTiers, 50)).toBe(700);
|
|
});
|
|
|
|
test("is unaffected by tier input order", () => {
|
|
const shuffled = [...tiers].reverse();
|
|
expect(resolveShippingCostCents(shuffled, 4)).toBe(850);
|
|
});
|
|
});
|
|
|
|
describe("getNextShippingTier", () => {
|
|
test("returns null for an empty cart", () => {
|
|
expect(getNextShippingTier(tiers, 0)).toBeNull();
|
|
});
|
|
|
|
test("returns null when no tiers are configured", () => {
|
|
expect(getNextShippingTier([], 2)).toBeNull();
|
|
});
|
|
|
|
test("returns null when already in the topmost open-ended tier", () => {
|
|
expect(getNextShippingTier(tiers, 15)).toBeNull();
|
|
});
|
|
|
|
test("reports units and price of the next tier", () => {
|
|
expect(getNextShippingTier(tiers, 2)).toEqual({ unitsUntilNext: 2, priceCents: 850 });
|
|
});
|
|
|
|
test("reports 1 unit remaining right below a boundary", () => {
|
|
expect(getNextShippingTier(tiers, 3)).toEqual({ unitsUntilNext: 1, priceCents: 850 });
|
|
});
|
|
|
|
test("is unaffected by tier input order", () => {
|
|
const shuffled = [...tiers].reverse();
|
|
expect(getNextShippingTier(shuffled, 9)).toEqual({ unitsUntilNext: 1, priceCents: 1100 });
|
|
});
|
|
});
|