import { describe, expect, it } from "vitest"; import { evaluateCartAttributes, evaluateCheckout } from "../../extensions/validation-slot/src/evaluate.js"; const COMPLETE = { dd_method: "PICKUP", dd_date: "2026-08-25", dd_start_min: "540", dd_end_min: "600", dd_location_id: "loc_123", }; describe("evaluateCartAttributes", () => { it("is valid when every required attribute is present", () => { expect(evaluateCartAttributes(COMPLETE)).toEqual({ valid: true }); }); it("rejects a cart with no scheduling attributes at all", () => { const result = evaluateCartAttributes({}); expect(result).toMatchObject({ valid: false, reason: "no_slot_selected" }); }); it("rejects a cart missing just one required attribute", () => { const { dd_start_min, ...rest } = COMPLETE; const result = evaluateCartAttributes(rest); expect(result).toMatchObject({ valid: false, reason: "incomplete_slot_selection", missing: ["dd_start_min"] }); }); it("treats an empty-string attribute the same as missing", () => { const result = evaluateCartAttributes({ ...COMPLETE, dd_date: "" }); expect(result.valid).toBe(false); }); it("treats null/undefined attribute values as missing", () => { const result = evaluateCartAttributes({ ...COMPLETE, dd_location_id: null, dd_method: undefined }); expect(result.valid).toBe(false); if (result.valid) throw new Error("unreachable"); expect(result.reason).toBe("incomplete_slot_selection"); expect([...(result.missing ?? [])].sort()).toEqual(["dd_location_id", "dd_method"]); }); }); // A snapshot that says loc_123 PICKUP on 2026-08-25 has a 09:00 slot with 2 left. const SNAPSHOT = { enforcement: { mode: "all" as const }, schedulableProductIds: [] as string[], horizonDate: "2026-09-30", slots: { "loc_123|PICKUP|2026-08-25|540": 2 }, closedDates: {} as Record, }; describe("evaluateCheckout — enforcement scope", () => { it("never blocks when the shop set enforcement to off, even with nothing selected", () => { const result = evaluateCheckout({ attributes: {}, snapshot: { ...SNAPSHOT, enforcement: { mode: "off" } } }); expect(result).toEqual({ valid: true }); }); it("blocks a slotless order when mode is 'all'", () => { const result = evaluateCheckout({ attributes: {}, snapshot: SNAPSHOT }); expect(result).toMatchObject({ valid: false, reason: "no_slot_selected" }); }); it("skips enforcement for a 'tagged' shop when no cart product is flagged", () => { const snapshot = { ...SNAPSHOT, enforcement: { mode: "tagged" as const }, schedulableProductIds: ["gid://shopify/Product/1"] }; const result = evaluateCheckout({ attributes: {}, snapshot, cartProductIds: ["gid://shopify/Product/999"] }); expect(result).toEqual({ valid: true }); }); it("enforces for a 'tagged' shop when a cart product is flagged", () => { const snapshot = { ...SNAPSHOT, enforcement: { mode: "tagged" as const }, schedulableProductIds: ["gid://shopify/Product/1"] }; const result = evaluateCheckout({ attributes: {}, snapshot, cartProductIds: ["gid://shopify/Product/1"] }); expect(result).toMatchObject({ valid: false, reason: "no_slot_selected" }); }); }); describe("evaluateCheckout — live slot re-validation", () => { it("passes a complete selection that still has capacity", () => { expect(evaluateCheckout({ attributes: COMPLETE, snapshot: SNAPSHOT })).toEqual({ valid: true }); }); it("blocks when the picked slot has filled up since selection", () => { const snapshot = { ...SNAPSHOT, slots: { "loc_123|PICKUP|2026-08-25|540": 0 } }; expect(evaluateCheckout({ attributes: COMPLETE, snapshot })).toMatchObject({ valid: false, reason: "slot_full" }); }); it("blocks when the picked date has been blacked out since selection", () => { const snapshot = { ...SNAPSHOT, closedDates: { "loc_123|PICKUP|2026-08-25": true as const } }; expect(evaluateCheckout({ attributes: COMPLETE, snapshot })).toMatchObject({ valid: false, reason: "slot_unavailable" }); }); it("blocks when the picked slot no longer exists in the schedule", () => { const snapshot = { ...SNAPSHOT, slots: { "loc_123|PICKUP|2026-08-25|600": 3 } }; expect(evaluateCheckout({ attributes: COMPLETE, snapshot })).toMatchObject({ valid: false, reason: "slot_unavailable" }); }); it("stays permissive past the snapshot horizon", () => { const result = evaluateCheckout({ attributes: { ...COMPLETE, dd_date: "2027-01-01" }, snapshot: SNAPSHOT }); expect(result).toEqual({ valid: true }); }); it("falls back to presence-only when there is no snapshot at all", () => { expect(evaluateCheckout({ attributes: COMPLETE, snapshot: null })).toEqual({ valid: true }); expect(evaluateCheckout({ attributes: {}, snapshot: null })).toMatchObject({ valid: false, reason: "no_slot_selected" }); }); it("falls back to presence-only when the snapshot carries no slot data yet (store mid-setup)", () => { const bare = { enforcement: { mode: "all" as const }, slots: {}, closedDates: {}, horizonDate: "2026-09-30" }; expect(evaluateCheckout({ attributes: COMPLETE, snapshot: bare })).toEqual({ valid: true }); }); });