123import { afterEach, describe, expect, it, vi } from "vitest";4import { AdoptionConsentModal } from "./AdoptionConsentModal";5import { flushView, inputText, renderView } from "../views/view-test-utils";67function button(container: HTMLElement, text: string): HTMLButtonElement {8 const found = Array.from(container.querySelectorAll("button")).find((b) =>9 (b.textContent ?? "").includes(text),10 );11 if (!found) throw new Error(`button not found: ${text}`);12 return found as HTMLButtonElement;13}1415function mount(overrides: Partial<Parameters<typeof AdoptionConsentModal>[0]> = {}) {16 const props = {17 receiverDeviceName: "June's iPhone",18 sas: "895245",19 verifyMasterPassword: vi.fn(async () => true),20 onCancel: vi.fn(),21 onApprove: vi.fn(async () => {}),22 ...overrides,23 };24 const rendered = renderView(<AdoptionConsentModal {...props} />);25 return { ...rendered, props };26}2728describe("AdoptionConsentModal", () => {29 const cleanups: Array<() => void> = [];3031 afterEach(() => {32 while (cleanups.length) cleanups.pop()!();33 });3435 function mounted(overrides: Partial<Parameters<typeof AdoptionConsentModal>[0]> = {}) {36 const rendered = mount(overrides);37 cleanups.push(rendered.dispose);38 return rendered;39 }4041 it("T-A16: renders receiver device name, consequence copy, and SAS code", () => {42 const { container } = mounted();43 expect(container.textContent).toContain("June's iPhone");44 expect(container.textContent).toContain("copies your entire vault including all passwords and Pro");45 expect(container.textContent).toContain("8 9 5 2 4 5");46 });4748 it("T-A17: Share vault button is disabled until a password is entered", () => {49 const { container } = mounted();50 const share = button(container, "Share vault");51 expect(share.disabled).toBe(true);52 inputText(container.querySelector("#adoption-consent-password") as HTMLInputElement, "pw");53 expect(share.disabled).toBe(false);54 });5556 it("T-A18: wrong password shows inline error, clears the field, and does not approve", async () => {57 const { container, props } = mounted({ verifyMasterPassword: vi.fn(async () => false) });58 const input = container.querySelector("#adoption-consent-password") as HTMLInputElement;59 inputText(input, "wrong");60 button(container, "Share vault").click();61 await flushView();6263 expect(container.textContent).toContain("Incorrect password");64 expect(input.value).toBe("");65 expect(document.activeElement).toBe(input);66 expect(props.onApprove).not.toHaveBeenCalled();67 });6869 it("T-A19: correct password calls onApprove", async () => {70 const { container, props } = mounted({ verifyMasterPassword: vi.fn(async () => true) });71 inputText(container.querySelector("#adoption-consent-password") as HTMLInputElement, "correct");72 button(container, "Share vault").click();73 await flushView();7475 expect(props.verifyMasterPassword).toHaveBeenCalledWith("correct");76 expect(props.onApprove).toHaveBeenCalledTimes(1);77 });7879 it("T-A20: cancel closes without approval", () => {80 const { container, props } = mounted();81 button(container, "Cancel").click();82 expect(props.onCancel).toHaveBeenCalledTimes(1);83 expect(props.onApprove).not.toHaveBeenCalled();84 });85});