118 lines
3.7 KiB
TypeScript
118 lines
3.7 KiB
TypeScript
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<T>(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");
|
|
});
|
|
});
|
|
});
|