import { fireEvent, render, screen } from "@testing-library/react"; import { useState } from "react"; import { describe, expect, it, vi } from "vitest"; import { isValidRecipient, RecipientChips, } from "../components/compose/RecipientChips"; import { I18nProvider } from "../i18n"; vi.mock("../lib/api", () => ({ api: { suggestRecipients: vi.fn().mockResolvedValue([]) }, })); // A controlled field, reporting every value it is given. function Field({ seen }: { seen: string[] }) { const [value, setValue] = useState(""); return ( { seen.push(v); setValue(v); }} /> ); } function type(text: string) { const input = screen.getByRole("textbox"); fireEvent.change(input, { target: { value: text } }); return input as HTMLInputElement; } describe("RecipientChips", () => { it("leaves typed text that is not an address in the input on blur", () => { const seen: string[] = []; render(); const input = type("John"); fireEvent.blur(input); expect(seen).toEqual([]); expect(input.value).toBe("John"); expect(input.getAttribute("aria-invalid")).toBe("true"); }); it("does not turn a non-address into a recipient on Enter either", () => { const seen: string[] = []; render(); const input = type("john@"); fireEvent.keyDown(input, { key: "Enter" }); expect(seen).toEqual([]); expect(input.value).toBe("john@"); }); it("commits a valid address on blur", () => { const seen: string[] = []; render(); const input = type("john@example.com"); fireEvent.blur(input); expect(seen).toEqual(["john@example.com"]); expect(input.value).toBe(""); }); it("keeps only the invalid part of a pasted list", () => { const seen: string[] = []; render(); const input = type("a@x.com, John, Bob "); fireEvent.keyDown(input, { key: "Enter" }); expect(seen).toEqual(["a@x.com, Bob "]); expect(input.value).toBe("John"); }); }); describe("isValidRecipient", () => { it.each([ ["john@example.com", true], ["John Smith ", true], ["John", false], ["john@", false], ["john@localhost", false], ["John ", false], ])("%s -> %s", (token, ok) => expect(isValidRecipient(token)).toBe(ok)); });