1234567891011121314151617181920import "./_setup"; 21import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";22import { showAutofillSelector } from "./inject";23import { makeInput } from "./_setup";2425const ENTRIES = [26 { id: "e1", title: "Acme", username: "[email protected]" },27 { id: "e2", title: "Acme Admin", username: "[email protected]" },28];29303132function selectorHost(): HTMLElement | null {33 return document.body.querySelector<HTMLElement>('div[style*="2147483647"]');34}3536beforeEach(() => {37 document.body.innerHTML = "";38});39afterEach(() => {40 document.body.innerHTML = "";41});4243describe("T-I01: mount + dismiss (the observable contract)", () => {44 45 46 it("T-I01: showAutofillSelector mounts a host and returns a dismiss fn", () => {47 const anchor = makeInput({ type: "password" });48 const dismiss = showAutofillSelector(anchor, ENTRIES, vi.fn());49 expect(typeof dismiss).toBe("function");50 expect(selectorHost()).not.toBeNull();51 dismiss();52 });5354 55 56 57 it("T-I05/T-I06 (teardown half): the returned dismiss removes the host", async () => {58 const anchor = makeInput({ type: "password" });59 const dismiss = showAutofillSelector(anchor, ENTRIES, vi.fn());60 expect(selectorHost()).not.toBeNull();61 dismiss();62 await new Promise((r) => setTimeout(r, 180));63 expect(selectorHost()).toBeNull();64 });6566 67 it("T-I01b: locked-mode open also mounts a host", () => {68 const anchor = makeInput({ type: "password" });69 const dismiss = showAutofillSelector(anchor, [], vi.fn(), { locked: true });70 expect(selectorHost()).not.toBeNull();71 dismiss();72 });7374 75 76 77 it("T-I01c: each open creates its own host (caller owns single-instance policy)", () => {78 const anchor = makeInput({ type: "password" });79 const d1 = showAutofillSelector(anchor, ENTRIES, vi.fn());80 const d2 = showAutofillSelector(anchor, ENTRIES, vi.fn());81 expect(document.body.querySelectorAll('div[style*="2147483647"]').length).toBe(2);82 d1();83 d2();84 });85});