Ctrl K
ComunidadGuías…

test/shared/external-order.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { assert, assertStringIncludes } from "@std/assert";
import { expect } from "@std/expect";
import { describe, it as test } from "@std/testing/bdd";
import {
  buildCatalog,
  resolveAllowOrigin,
  serializeCatalog,
} from "#shared/external-order.ts";
import { testListing } from "#test-utils/factories.ts";

const base = {
  currency: "GBP",
  debug: false,
  decimalPlaces: 2,
  generatedAt: "2026-06-28T20:00:00Z",
  origin: "https://tickets.test",
};

describe("external-order", () => {
  describe("resolveAllowOrigin", () => {
    test("empty allow-list returns wildcard for any origin", () => {
      expect(resolveAllowOrigin("https://anywhere.test", [])).toBe("*");
    });

    test("echoes an exactly-listed origin", () => {
      expect(resolveAllowOrigin("https://example.com", ["example.com"])).toBe(
        "https://example.com",
      );
    });

    test("matches the origin host case-insensitively", () => {
      expect(resolveAllowOrigin("https://EXAMPLE.com", ["example.com"])).toBe(
        "https://EXAMPLE.com",
      );
    });

    test("ignores the origin port", () => {
      expect(
        resolveAllowOrigin("https://example.com:8443", ["example.com"]),
      ).toBe("https://example.com:8443");
    });

    test("matches a wildcard subdomain", () => {
      expect(
        resolveAllowOrigin("https://www.example.com", ["*.example.com"]),
      ).toBe("https://www.example.com");
    });

    test("wildcard does not match the bare apex", () => {
      expect(
        resolveAllowOrigin("https://example.com", ["*.example.com"]),
      ).toBeNull();
    });

    test("rejects an unlisted origin", () => {
      expect(
        resolveAllowOrigin("https://evil.com", ["example.com"]),
      ).toBeNull();
    });

    test("wildcard requires a dot boundary, not just the suffix text", () => {
      // `bbexample.com` ends with `example.com` but not with the `.example.com`
      // the wildcard demands — the host-length check alone would wrongly allow
      // it, so the boundary `&&` must hold.
      expect(
        resolveAllowOrigin("https://bbexample.com", ["*.example.com"]),
      ).toBeNull();
    });

    test("rejects a missing origin against a non-empty list", () => {
      expect(resolveAllowOrigin(null, ["example.com"])).toBeNull();
    });

    test("rejects an empty-string origin against a non-empty list", () => {
      // An empty `Origin` header is falsy but still a string; it must be denied
      // (null), not echoed back as the allowed origin.
      expect(resolveAllowOrigin("", ["example.com"])).toBeNull();
    });

    test("rejects a malformed origin", () => {
      expect(resolveAllowOrigin("not a url", ["example.com"])).toBeNull();
    });
  });

  describe("buildCatalog", () => {
    test("keys active non-hidden entries by slug, excludes hidden + inactive", () => {
      const catalog = buildCatalog({
        ...base,
        listings: [
          testListing({ id: 1, name: "Open", slug: "open", unit_price: 1500 }),
          testListing({ hidden: true, id: 2, name: "Secret", slug: "secret" }),
          testListing({ active: false, id: 3, name: "Closed", slug: "closed" }),
        ],
      });
      expect(Object.keys(catalog.listings)).toEqual(["open"]);
      expect(catalog.listings.open).toEqual({
        id: 1,
        name: "Open",
        slug: "open",
        unitPrice: 1500,
        variablePrice: false,
      });
      expect(catalog.origin).toBe("https://tickets.test");
      expect(catalog.currency).toBe("GBP");
      expect(catalog.decimalPlaces).toBe(2);
      expect(catalog.generatedAt).toBe("2026-06-28T20:00:00Z");
      expect(catalog.debug).toBe(false);
    });

    test("carries the debug flag through to the catalog", () => {
      const catalog = buildCatalog({ ...base, debug: true, listings: [] });
      expect(catalog.debug).toBe(true);
    });

    test("flags variablePrice for daily, customisable-days, and PWYW", () => {
      const catalog = buildCatalog({
        ...base,
        listings: [
          testListing({ id: 1, listing_type: "daily", slug: "daily" }),
          testListing({ customisable_days: true, id: 2, slug: "days" }),
          testListing({ can_pay_more: true, id: 3, slug: "pwyw" }),
          testListing({ id: 4, slug: "fixed" }),
        ],
      });
      expect(
        (catalog.listings.daily as { variablePrice: boolean }).variablePrice,
      ).toBe(true);
      expect(
        (catalog.listings.days as { variablePrice: boolean }).variablePrice,
      ).toBe(true);
      expect(
        (catalog.listings.pwyw as { variablePrice: boolean }).variablePrice,
      ).toBe(true);
      expect(
        (catalog.listings.fixed as { variablePrice: boolean }).variablePrice,
      ).toBe(false);
    });

    test("keys package bundles by slug, separate from listings", () => {
      const catalog = buildCatalog({
        ...base,
        listings: [testListing({ id: 1, name: "Solo", slug: "solo" })],
        packages: [
          { name: "Camp Bundle", slug: "camp" },
          { name: "Beach Bundle", slug: "beach" },
        ],
      });
      expect(Object.keys(catalog.listings)).toEqual(["solo"]);
      expect(catalog.packages).toEqual({
        beach: { name: "Beach Bundle", slug: "beach" },
        camp: { name: "Camp Bundle", slug: "camp" },
      });
    });

    test("defaults packages to an empty object when none are given", () => {
      const catalog = buildCatalog({ ...base, listings: [] });
      expect(catalog.packages).toEqual({});
    });
  });

  describe("serializeCatalog", () => {
    test("produces a CATALOG const that round-trips", () => {
      const catalog = buildCatalog({ ...base, listings: [] });
      const out = serializeCatalog(catalog);
      expect(out).toMatch(/^const CATALOG = \{/);
      const json = out.slice("const CATALOG = ".length, -1);
      expect(JSON.parse(json)).toEqual(catalog);
    });

    test("escapes < so a name cannot form a closing script tag", () => {
      const catalog = buildCatalog({
        ...base,
        listings: [
          testListing({ id: 1, name: "</script><img src=x>", slug: "x" }),
        ],
      });
      const out = serializeCatalog(catalog);
      assert(!out.includes("</script>"));
      assertStringIncludes(out, "\\u003c");
    });
  });
});