import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { render } from "solid-js/web"; import type { JSX } from "solid-js"; import PasswordInput from "./PasswordInput"; import SocialAuthButtons from "./SocialAuthButtons"; import AuthLayout from "./AuthLayout"; import { Input, Button } from "~/components/ui"; function mount(comp: () => JSX.Element): HTMLDivElement { const container = document.createElement("div"); document.body.appendChild(container); render(() => comp(), container); return container; } beforeEach(() => { document.body.innerHTML = ""; if (!globalThis.crypto) { Object.defineProperty(globalThis, "crypto", { value: {} }); } (globalThis.crypto as unknown as Record).randomUUID = vi.fn( () => "test-uuid-1234", ); }); afterEach(() => { document.body.innerHTML = ""; }); describe("PasswordInput", () => { it("renders with label", () => { mount(() => ); expect(document.body.textContent).toContain("Password"); expect(document.querySelector("label")).toBeTruthy(); }); it("renders password type by default", () => { mount(() => ); const input = document.querySelector("input")!; expect(input.getAttribute("type")).toBe("password"); }); it("toggles visibility when eye icon is clicked", () => { mount(() => ); const input = document.querySelector("input")!; const toggle = document.querySelector("button[aria-label]")!; expect(input.getAttribute("type")).toBe("password"); expect(toggle.getAttribute("aria-label")).toBe("Show password"); toggle.dispatchEvent(new MouseEvent("click", { bubbles: true })); expect(input.getAttribute("type")).toBe("text"); expect(toggle.getAttribute("aria-label")).toBe("Hide password"); toggle.dispatchEvent(new MouseEvent("click", { bubbles: true })); expect(input.getAttribute("type")).toBe("password"); }); it("shows error message", () => { mount(() => ( )); expect(document.body.textContent).toContain("Password is required"); }); it("shows helper text when no error", () => { mount(() => ( )); expect(document.body.textContent).toContain("At least 8 characters"); }); it("hides helper text when error is present", () => { mount(() => ( )); expect(document.body.textContent).toContain("Required"); expect(document.body.textContent).not.toContain("Helper text"); }); it("forwards onInput handler", () => { const onInput = vi.fn(); mount(() => ); const input = document.querySelector("input")!; input.dispatchEvent(new InputEvent("input", { bubbles: true })); expect(onInput).toHaveBeenCalled(); }); }); describe("SocialAuthButtons", () => { it("renders Google and Apple buttons", () => { mount(() => ); const buttons = document.querySelectorAll("button"); expect(buttons.length).toBe(2); expect(buttons[0].textContent).toContain("Google"); expect(buttons[1].textContent).toContain("Apple"); }); it("renders SVG icons in each button", () => { mount(() => ); const buttons = document.querySelectorAll("button"); expect(buttons[0].querySelector("svg")).toBeTruthy(); expect(buttons[1].querySelector("svg")).toBeTruthy(); }); }); describe("AuthLayout", () => { it("renders children inside the form card", () => { mount(() => (

Form content

)); expect(document.body.textContent).toContain("Form content"); }); it("renders Kordant branding", () => { mount(() => (

Content

)); expect(document.body.textContent).toContain("Kordant"); }); it("renders gradient-card wrapper", () => { mount(() => (

Content

)); expect(document.querySelector(".gradient-card")).toBeTruthy(); }); it("renders testimonial text", () => { mount(() => (

Content

)); expect(document.body.textContent).toContain("Kordant"); expect(document.body.textContent).toContain("AI-Powered Identity Protection"); }); });