import type { DetectorContext } from "@suaveplan/i18n-detector"; import { describe, expect, it } from "@suaveplan/testing/runner"; import { htmlLangDetector } from "./html-lang.js"; const SUPPORTED = ["en-GB", "fr-FR", "de-DE"] as const; function browserContext(): DetectorContext { return { supportedLocales: SUPPORTED, fallbackLocale: "en-GB", }; } function withDocumentLang(lang: unknown, fn: () => T): T { const original = (globalThis as { document?: unknown }).document; Object.defineProperty(globalThis, "document", { configurable: true, value: { documentElement: { lang } }, }); try { return fn(); } finally { Object.defineProperty(globalThis, "document", { configurable: true, value: original, }); } } describe("htmlLangDetector", () => { it("exposes name and environment per spec", { timeout: 5000 }, () => { const detector = htmlLangDetector(); expect(detector.name).toBe("htmlLang"); expect(detector.environment).toBe("browser"); }); it("reads document.documentElement.lang", { timeout: 5000 }, () => { const detector = htmlLangDetector(); withDocumentLang("fr-FR", () => { expect(detector.detect?.(browserContext())).toBe("fr-FR"); }); }); it("trims surrounding whitespace", { timeout: 5000 }, () => { const detector = htmlLangDetector(); withDocumentLang(" de-DE ", () => { expect(detector.detect?.(browserContext())).toBe("de-DE"); }); }); it("returns null for empty lang attribute", { timeout: 5000 }, () => { const detector = htmlLangDetector(); withDocumentLang("", () => { expect(detector.detect?.(browserContext())).toBeNull(); }); }); it("returns null when documentElement is missing", { timeout: 5000, }, () => { const detector = htmlLangDetector(); const original = (globalThis as { document?: unknown }).document; Object.defineProperty(globalThis, "document", { configurable: true, value: { documentElement: null }, }); try { expect(detector.detect?.(browserContext())).toBeNull(); } finally { Object.defineProperty(globalThis, "document", { configurable: true, value: original, }); } }); it("returns null when lang is not a string", { timeout: 5000 }, () => { const detector = htmlLangDetector(); withDocumentLang(12345, () => { expect(detector.detect?.(browserContext())).toBeNull(); }); }); it("returns null when no document is available", { timeout: 5000 }, () => { const detector = htmlLangDetector(); const original = (globalThis as { document?: unknown }).document; Object.defineProperty(globalThis, "document", { configurable: true, value: undefined, }); try { expect(detector.detect?.(browserContext())).toBeNull(); } finally { Object.defineProperty(globalThis, "document", { configurable: true, value: original, }); } }); it("uses ctx.document over globalThis.document when supplied", { timeout: 5000, }, () => { const detector = htmlLangDetector(); withDocumentLang("en-GB", () => { const injected = { documentElement: { lang: "fr-FR" }, } as unknown as Document; expect( detector.detect?.({ ...browserContext(), document: injected, }) ).toBe("fr-FR"); }); }); });