import type { UTMProperties } from "../types/utm"; import { buildPreservedQueryHref, combineExistingAndNewUTMs, getCampaignProperties, getOrganicTrafficUtmParameters, getUtmParametersFromURL, } from "./utm"; describe("utm utilities", () => { // ── getUtmParametersFromURL ────────────────────────── describe("getUtmParametersFromURL", () => { const origLocation = window.location; afterEach(() => { Object.defineProperty(window, "location", { value: origLocation, writable: true, }); }); it("returns null when window is undefined", () => { const origWindow = globalThis.window; // @ts-expect-error - intentionally deleting window delete globalThis.window; expect(getUtmParametersFromURL()).toBeNull(); globalThis.window = origWindow; }); it("returns null when no UTM params in URL", () => { Object.defineProperty(window, "location", { value: { search: "?foo=bar&baz=qux" }, writable: true, }); expect(getUtmParametersFromURL()).toBeNull(); }); it("extracts all UTM params from URL", () => { Object.defineProperty(window, "location", { value: { search: "?utm_source=google&utm_medium=cpc&utm_campaign=spring&utm_term=shoes&utm_content=ad1&utm_campaign_id=c123&utm_adgroup_id=ag456&gclid=g789&fbclid=f012&msclkid=m345", }, writable: true, }); const result = getUtmParametersFromURL(); expect(result).toEqual({ utm_source: "google", utm_medium: "cpc", utm_campaign: "spring", utm_term: "shoes", utm_content: "ad1", utm_campaign_id: "c123", utm_adgroup_id: "ag456", gclid: "g789", fbclid: "f012", msclkid: "m345", }); }); it("extracts partial UTM params", () => { Object.defineProperty(window, "location", { value: { search: "?utm_source=bing&gclid=abc" }, writable: true, }); const result = getUtmParametersFromURL(); expect(result).toEqual({ utm_source: "bing", gclid: "abc" }); }); }); // ── combineExistingAndNewUTMs ──────────────────────── describe("combineExistingAndNewUTMs", () => { it("returns existing when incoming is null", () => { const existing: UTMProperties = { utm_source: "google" }; expect(combineExistingAndNewUTMs(existing, null)).toEqual(existing); }); it("returns empty object when both are null", () => { expect(combineExistingAndNewUTMs(null, null)).toEqual({}); }); it("returns incoming when existing is null", () => { const incoming: UTMProperties = { utm_source: "bing" }; expect(combineExistingAndNewUTMs(null, incoming)).toEqual(incoming); }); it("preserves existing content/term for same campaign", () => { const existing: UTMProperties = { utm_campaign: "spring", utm_source: "google", utm_medium: "cpc", utm_content: "original-ad", utm_term: "original-keyword", }; const incoming: UTMProperties = { utm_campaign: "spring", utm_source: "google", utm_medium: "cpc", utm_content: "new-ad", utm_term: "new-keyword", }; const result = combineExistingAndNewUTMs(existing, incoming); expect(result.utm_content).toBe("original-ad"); expect(result.utm_term).toBe("original-keyword"); }); it("uses incoming content/term when existing has none (same campaign)", () => { const existing: UTMProperties = { utm_campaign: "spring", utm_source: "google", utm_medium: "cpc", }; const incoming: UTMProperties = { utm_campaign: "spring", utm_source: "google", utm_medium: "cpc", utm_content: "new-ad", utm_term: "new-keyword", }; const result = combineExistingAndNewUTMs(existing, incoming); expect(result.utm_content).toBe("new-ad"); expect(result.utm_term).toBe("new-keyword"); }); it("overwrites with incoming for different campaign", () => { const existing: UTMProperties = { utm_campaign: "spring", utm_source: "google", utm_medium: "cpc", utm_content: "old-content", utm_term: "old-term", }; const incoming: UTMProperties = { utm_campaign: "summer", utm_source: "facebook", utm_medium: "social", utm_content: "new-content", utm_term: "new-term", }; const result = combineExistingAndNewUTMs(existing, incoming); expect(result.utm_campaign).toBe("summer"); expect(result.utm_content).toBe("new-content"); expect(result.utm_term).toBe("new-term"); }); it("carries forward existing content/term if incoming doesnt have them (different campaign)", () => { const existing: UTMProperties = { utm_campaign: "spring", utm_source: "google", utm_medium: "cpc", utm_content: "old-content", utm_term: "old-term", }; const incoming: UTMProperties = { utm_campaign: "summer", utm_source: "facebook", utm_medium: "social", }; const result = combineExistingAndNewUTMs(existing, incoming); expect(result.utm_campaign).toBe("summer"); expect(result.utm_content).toBe("old-content"); expect(result.utm_term).toBe("old-term"); }); }); // ── getOrganicTrafficUtmParameters ─────────────────── describe("getOrganicTrafficUtmParameters", () => { const origReferrer = Object.getOwnPropertyDescriptor( Document.prototype, "referrer" ); function setReferrer(value: string) { Object.defineProperty(document, "referrer", { value, configurable: true, }); } afterEach(() => { if (origReferrer) { Object.defineProperty(document, "referrer", origReferrer); } }); it("returns direct/direct when no referrer", () => { setReferrer(""); expect(getOrganicTrafficUtmParameters()).toEqual({ utm_medium: "direct", utm_source: "direct", }); }); it("returns organic/google for Google referrer", () => { setReferrer("https://www.google.com/search?q=kinetic"); expect(getOrganicTrafficUtmParameters()).toEqual({ utm_medium: "organic", utm_source: "google", }); }); it("returns organic/bing for Bing referrer", () => { setReferrer("https://www.bing.com/search?q=kinetic"); expect(getOrganicTrafficUtmParameters()).toEqual({ utm_medium: "organic", utm_source: "bing", }); }); it("returns null for internal windstream.com referrer", () => { setReferrer("https://www.windstream.com/plans"); expect(getOrganicTrafficUtmParameters()).toBeNull(); }); it("returns null for internal gokinetic.com referrer", () => { setReferrer("https://www.gokinetic.com/checkout"); expect(getOrganicTrafficUtmParameters()).toBeNull(); }); it("returns referral for external referrer", () => { setReferrer("https://reddit.com/r/internet"); expect(getOrganicTrafficUtmParameters()).toEqual({ utm_medium: "referral", utm_source: "reddit.com", }); }); it("returns direct/direct for invalid referrer URL", () => { setReferrer("not-a-valid-url"); expect(getOrganicTrafficUtmParameters()).toEqual({ utm_medium: "direct", utm_source: "direct", }); }); }); // ── getCampaignProperties ──────────────────────────── describe("getCampaignProperties", () => { it("returns null for null input", () => { expect(getCampaignProperties(null)).toBeNull(); }); it("returns null for empty UTMs", () => { expect(getCampaignProperties({})).toBeNull(); }); it("maps all UTM properties to campaign properties", () => { const utms: UTMProperties = { utm_campaign: "spring", utm_source: "google", utm_medium: "cpc", utm_term: "shoes", utm_content: "ad1", utm_campaign_id: "c123", utm_adgroup_id: "ag456", gclid: "g789", fbclid: "f012", msclkid: "m345", }; expect(getCampaignProperties(utms)).toEqual({ name: "spring", source: "google", medium: "cpc", term: "shoes", content: "ad1", campaign_id: "c123", adgroup_id: "ag456", gclid: "g789", fbclid: "f012", msclkid: "m345", }); }); it("maps partial UTMs", () => { expect( getCampaignProperties({ utm_source: "bing", utm_medium: "organic" }) ).toEqual({ source: "bing", medium: "organic" }); }); }); // ── buildPreservedQueryHref ────────────────────────── describe("buildPreservedQueryHref", () => { it("returns href unchanged when no current search", () => { expect(buildPreservedQueryHref("/plans", "")).toBe("/plans"); }); it("strips UTM params from current search", () => { const result = buildPreservedQueryHref( "/plans", "?utm_source=google&foo=bar" ); expect(result).toContain("foo=bar"); expect(result).not.toContain("utm_source"); }); it("strips searchtext and page params", () => { const result = buildPreservedQueryHref( "/results", "?searchtext=hello&page=3&category=fiber" ); expect(result).toContain("category=fiber"); expect(result).not.toContain("searchtext"); expect(result).not.toContain("page=3"); }); it("preserves non-UTM params and merges with target", () => { const result = buildPreservedQueryHref( "/plans?speed=500", "?promo=SAVE20" ); expect(result).toContain("speed=500"); expect(result).toContain("promo=SAVE20"); }); it("handles absolute URLs", () => { const result = buildPreservedQueryHref( "https://gokinetic.com/plans?speed=500", "?promo=SAVE20" ); expect(result).toContain("https://gokinetic.com/plans"); expect(result).toContain("speed=500"); expect(result).toContain("promo=SAVE20"); }); it("does not duplicate params already in target", () => { const result = buildPreservedQueryHref( "/plans?promo=SAVE20", "?promo=OLD" ); const params = new URLSearchParams(result.split("?")[1]); expect(params.getAll("promo")).toHaveLength(1); expect(params.get("promo")).toBe("SAVE20"); }); it("returns href for invalid URL when href is not parseable", () => { // The catch block handles invalid absolute-looking URLs // Relative paths are handled by the else branch, so test a truly invalid URL const result = buildPreservedQueryHref("http://[invalid", "?foo=bar"); expect(result).toBe("http://[invalid"); }); it("returns basePath without query string when all params stripped", () => { const result = buildPreservedQueryHref( "/plans", "?utm_source=google&utm_medium=cpc" ); expect(result).toBe("/plans"); }); it("handles relative path with existing query", () => { const result = buildPreservedQueryHref( "/plans?existing=value", "?extra=param" ); expect(result).toContain("existing=value"); expect(result).toContain("extra=param"); }); }); });