spb/worthdoing Public
Autonomous investigation agent that discovers, challenges, and ranks things genuinely worth doing — Claude + Firecrawl, Next.js 16, PostgreSQL
TypeScript 91.5%
SQL 5.8%
CSS 2.2%
1/**2 * WorthDoing.ai3 * Author: Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File: tests/canonical-url.test.ts6 * Description: URL canonicalization + content hashing tests (deduplication layer).7 */8import { describe, it, expect } from "vitest";9import { canonicalizeUrl, sha256 } from "@/lib/firecrawl/url";1011describe("canonicalizeUrl", () => {12 it("strips www, fragments, and trailing slashes", () => {13 expect(canonicalizeUrl("https://www.Example.com/path/#section")).toBe("https://example.com/path");14 });1516 it("removes tracking parameters but keeps meaningful ones", () => {17 expect(canonicalizeUrl("https://example.com/a?utm_source=x&page=2&fbclid=abc")).toBe(18 "https://example.com/a?page=2",19 );20 });2122 it("sorts query parameters for stable comparison", () => {23 expect(canonicalizeUrl("https://example.com/a?b=2&a=1")).toBe(canonicalizeUrl("https://example.com/a?a=1&b=2"));24 });2526 it("normalizes equivalent URLs to the same canonical form", () => {27 const variants = [28 "https://www.example.com/post/",29 "https://example.com/post",30 "https://example.com/post#comments",31 "https://example.com/post?utm_campaign=news",32 ];33 const canon = new Set(variants.map(canonicalizeUrl));34 expect(canon.size).toBe(1);35 });3637 it("keeps the root path as /", () => {38 expect(canonicalizeUrl("https://example.com")).toBe("https://example.com/");39 });40});4142describe("sha256", () => {43 it("is deterministic and collision-distinct for different content", () => {44 expect(sha256("hello")).toBe(sha256("hello"));45 expect(sha256("hello")).not.toBe(sha256("hello!"));46 expect(sha256("hello")).toHaveLength(64);47 });48});49