fill.test.ts

5.2 KB · raw

1// @vitest-environment jsdom23import { beforeEach, describe, expect, it, vi } from "vitest";45import { fillFields, fillCardForm, formatCardNumber } from "./fill";67describe("content fill", () => {8  beforeEach(() => {9    document.body.innerHTML = "";10  });1112  function makeVisibleInput(type: string): HTMLInputElement {13    const input = document.createElement("input");14    input.type = type;15    Object.defineProperty(input, "getBoundingClientRect", {16      configurable: true,17      value: () => ({18        width: 100,19        height: 20,20        top: 0,21        left: 0,22        right: 100,23        bottom: 20,24        x: 0,25        y: 0,26        toJSON: () => ({}),27      }),28    });29    document.body.appendChild(input);30    return input;31  }3233  it("fillFields writes username and password into matching inputs", () => {34    const username = makeVisibleInput("text");35    const password = makeVisibleInput("password");3637    fillFields(username, password, "june", "hunter2");3839    expect(username.value).toBe("june");40    expect(password.value).toBe("hunter2");41  });4243  it("fillFields refuses to fill when the form action domain does not match", () => {44    const form = document.createElement("form");45    form.action = "https://evil.com/login";46    const username = makeVisibleInput("text");47    const password = makeVisibleInput("password");48    form.append(username, password);49    document.body.appendChild(form);5051    fillFields(username, password, "june", "hunter2", form, "github.com");5253    expect(username.value).toBe("");54    expect(password.value).toBe("");55  });5657  it("fillFields still fills the username when the username field is hidden", () => {58    const username = makeVisibleInput("text");59    const password = makeVisibleInput("password");60    Object.defineProperty(username, "getBoundingClientRect", {61      value: () => ({62        width: 0,63        height: 0,64        top: 0,65        left: 0,66        right: 0,67        bottom: 0,68        x: 0,69        y: 0,70        toJSON: () => ({}),71      }),72    });7374    fillFields(username, password, "june", "hunter2");7576    expect(username.value).toBe("june");77    expect(password.value).toBe("hunter2");78  });7980  it("fillFields dispatches standard input/change events rather than custom password events", () => {81    const username = makeVisibleInput("text");82    const password = makeVisibleInput("password");83    const usernameDispatch = vi.spyOn(username, "dispatchEvent");84    const passwordDispatch = vi.spyOn(password, "dispatchEvent");8586    fillFields(username, password, "june", "hunter2");8788    expect(usernameDispatch.mock.calls.map(([event]) => event.type)).toEqual(["input", "change"]);89    expect(passwordDispatch.mock.calls.map(([event]) => event.type)).toEqual(["input", "change"]);90    expect(passwordDispatch.mock.calls.every(([event]) => !(event instanceof CustomEvent))).toBe(true);91  });92});9394describe("card fill", () => {95  beforeEach(() => {96    document.body.innerHTML = "";97  });9899  function makeInput(attrs: Record<string, string> = {}): HTMLInputElement {100    const input = document.createElement("input");101    for (const [k, v] of Object.entries(attrs)) input.setAttribute(k, v);102    document.body.appendChild(input);103    return input;104  }105106  it("fillCardForm — fills number, expiry, CVC, and name fields", () => {107    const number = makeInput({ type: "text" });108    const expMonth = makeInput({ type: "text" });109    const expYear = makeInput({ type: "text" });110    const cvc = makeInput({ type: "text" });111    const name = makeInput({ type: "text" });112113    fillCardForm(114      { number, expMonth, expYear, expiryCombo: null, cvc, name },115      { cardNumber: "4111111111111111", expMonth: "05", expYear: "2028", cvc: "123", cardholderName: "Jane Smith" }116    );117118    expect(number.value).toBe("4111 1111 1111 1111");119    expect(expMonth.value).toBe("05");120    expect(expYear.value).toBe("2028");121    expect(cvc.value).toBe("123");122    expect(name.value).toBe("Jane Smith");123  });124125  it("fillCardForm — handles combined expiry field (MM/YY)", () => {126    const number = makeInput({ type: "text" });127    const expiryCombo = makeInput({ type: "text" });128    const cvc = makeInput({ type: "text" });129130    fillCardForm(131      { number, expMonth: null, expYear: null, expiryCombo, cvc, name: null },132      { cardNumber: "5555555555554444", expMonth: "12", expYear: "2026", cvc: "456", cardholderName: "John Doe" }133    );134135    expect(expiryCombo.value).toBe("12/26");136  });137138  it("fillCardForm — dispatches input and change events for React compatibility", () => {139    const number = makeInput({ type: "text" });140    const numberDispatch = vi.spyOn(number, "dispatchEvent");141142    fillCardForm(143      { number, expMonth: null, expYear: null, expiryCombo: null, cvc: null, name: null },144      { cardNumber: "4111111111111111", expMonth: "05", expYear: "2028", cvc: "123", cardholderName: "Jane" }145    );146147    expect(numberDispatch.mock.calls.map(([event]) => event.type)).toEqual(["input", "change"]);148  });149150  it("formatCardNumber — formats Visa as 4-4-4-4", () => {151    expect(formatCardNumber("4111111111111111")).toBe("4111 1111 1111 1111");152  });153154  it("formatCardNumber — formats Amex as 4-6-5", () => {155    expect(formatCardNumber("378282246310005")).toBe("3782 822463 10005");156  });157});