// author: simon-pierre boucher import { describe, expect, it } from "vitest"; import { normalizeUrl } from "./url.js"; function norm(raw: string, base?: string): string { const r = normalizeUrl(raw, base); if (!r.ok) throw new Error(`expected ok, got ${r.error.code}`); return r.value; } describe("normalizeUrl", () => { it("lowercases the host but not the path", () => { expect(norm("https://EXAMPLE.com/Path")).toBe("https://example.com/Path"); }); it("strips default ports", () => { expect(norm("http://example.com:80/a")).toBe("http://example.com/a"); expect(norm("https://example.com:443/a")).toBe("https://example.com/a"); }); it("keeps non-default ports", () => { expect(norm("https://example.com:8443/a")).toBe("https://example.com:8443/a"); }); it("removes tracking params but keeps real ones", () => { expect(norm("https://e.com/?utm_source=x&q=1&fbclid=z&_ga=2")).toBe("https://e.com/?q=1"); }); it("sorts query params deterministically", () => { expect(norm("https://e.com/?b=2&a=1&a=0")).toBe("https://e.com/?a=0&a=1&b=2"); }); it("drops the fragment unless hashbang", () => { expect(norm("https://e.com/p#section")).toBe("https://e.com/p"); expect(norm("https://e.com/p#!/route")).toBe("https://e.com/p#!/route"); }); it("removes trailing slash except at root", () => { expect(norm("https://e.com/foo/")).toBe("https://e.com/foo"); expect(norm("https://e.com/")).toBe("https://e.com/"); }); it("resolves dot segments", () => { expect(norm("https://e.com/a/b/../c")).toBe("https://e.com/a/c"); }); it("punycodes international hosts", () => { expect(norm("https://münchen.de/")).toBe("https://xn--mnchen-3ya.de/"); }); it("resolves relative URLs against a base", () => { expect(norm("../x", "https://e.com/a/b")).toBe("https://e.com/x"); }); it("rejects non-http schemes", () => { const r = normalizeUrl("ftp://e.com/x"); expect(r.ok).toBe(false); if (!r.ok) expect(r.error.code).toBe("ERR_INVALID_URL"); }); it("rejects malformed input", () => { const r = normalizeUrl("not a url"); expect(r.ok).toBe(false); }); it("produces identical output for equivalent URLs", () => { expect(norm("https://E.com:443/a/../b/?utm_x=1&z=9#frag")).toBe(norm("https://e.com/b?z=9")); }); });