import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; // The vanilla runtime is an IIFE that auto-executes. To test it in // isolation we need to import the built file or re-execute the IIFE // in a controlled DOM. Since the source is TypeScript that compiles // to an IIFE, we test by setting up DOM fixtures and dynamically // importing the source module. For unit testing purposes we extract // the testable behaviors into DOM-based assertions. // Helper: reset body classes and DOM between tests function resetDOM(): void { document.body.className = ""; document.body.innerHTML = ""; } describe("Vanilla Runtime: :has() fallback", () => { beforeEach(resetDOM); afterEach(resetDOM); it("adds strand-glass-nav-active to body when glass nav present and :has() not supported", () => { // Simulate no :has() support const originalSupports = CSS.supports; CSS.supports = (() => false) as typeof CSS.supports; document.body.innerHTML = ''; // Simulate the fallback logic const hasSupport = CSS.supports("selector(:has(*))"); if (!hasSupport && document.querySelector(".strand-nav--glass")) { document.body.classList.add("strand-glass-nav-active"); } expect(document.body.classList.contains("strand-glass-nav-active")).toBe(true); CSS.supports = originalSupports; }); it("adds strand-banner-active to body when banner present and :has() not supported", () => { const originalSupports = CSS.supports; CSS.supports = (() => false) as typeof CSS.supports; document.body.innerHTML = '
'; const hasSupport = CSS.supports("selector(:has(*))"); if (!hasSupport && document.querySelector(".strand-banner")) { document.body.classList.add("strand-banner-active"); } expect(document.body.classList.contains("strand-banner-active")).toBe(true); CSS.supports = originalSupports; }); it("does not add body classes when :has() is supported", () => { // jsdom may or may not support :has(), but we mock it as supported const originalSupports = CSS.supports; CSS.supports = ((sel: string) => { if (sel === "selector(:has(*))") return true; return false; }) as typeof CSS.supports; document.body.innerHTML = ''; const hasSupport = CSS.supports("selector(:has(*))"); if (!hasSupport && document.querySelector(".strand-nav--glass")) { document.body.classList.add("strand-glass-nav-active"); } expect(document.body.classList.contains("strand-glass-nav-active")).toBe(false); CSS.supports = originalSupports; }); }); describe("Vanilla Runtime: Nav mobile menu", () => { beforeEach(resetDOM); afterEach(resetDOM); it("wires hamburger to toggle mobile menu", () => { document.body.innerHTML = ` `; const btn = document.querySelector(".strand-nav__hamburger") as HTMLElement; const menu = document.querySelector(".strand-nav__mobile-menu") as HTMLElement; // Simulate attachNav logic btn.setAttribute("data-strand-nav-wired", "true"); btn.addEventListener("click", () => { const open = menu.classList.toggle("strand-nav__mobile-menu--open"); btn.setAttribute("aria-expanded", String(open)); }); btn.click(); expect(menu.classList.contains("strand-nav__mobile-menu--open")).toBe(true); expect(btn.getAttribute("aria-expanded")).toBe("true"); btn.click(); expect(menu.classList.contains("strand-nav__mobile-menu--open")).toBe(false); expect(btn.getAttribute("aria-expanded")).toBe("false"); }); it("is idempotent via data-strand-nav-wired", () => { document.body.innerHTML = ` `; const btn = document.querySelector(".strand-nav__hamburger") as HTMLElement; // Should skip because already wired expect(btn.getAttribute("data-strand-nav-wired")).toBe("true"); }); }); describe("Vanilla Runtime: Tabs enhancement", () => { beforeEach(resetDOM); afterEach(resetDOM); function setupTabs(): { tabs: HTMLElement[]; panels: HTMLElement[] } { document.body.innerHTML = `test';
const pre = document.querySelector(".strand-code-block__pre")!;
// Simulate wrap logic
let wrapper = pre.parentElement;
if (!wrapper || !wrapper.classList.contains("strand-code-block")) {
const newWrapper = document.createElement("div");
newWrapper.className = "strand-code-block";
pre.parentNode?.insertBefore(newWrapper, pre);
newWrapper.appendChild(pre);
wrapper = newWrapper;
}
expect(wrapper.classList.contains("strand-code-block")).toBe(true);
expect(wrapper.contains(pre)).toBe(true);
});
it("is idempotent (does not double-inject copy button)", () => {
document.body.innerHTML = `
test