detect.test.ts

4.7 KB · raw

1// @vitest-environment jsdom23import { beforeEach, describe, expect, it } from "vitest";45import {6  detectCardForm,7  detectLoginFields,8  getPageDomain,9  hasPaymentProcessorIframe,10  isLoginForm,11  isSignupForm,12} from "./detect";1314describe("content detect", () => {15  beforeEach(() => {16    document.body.innerHTML = "";17  });1819  function visibleInput(20    attributes: Record<string, string> = {},21    tagName: "input" = "input"22  ): HTMLInputElement {23    const input = document.createElement(tagName);24    Object.entries(attributes).forEach(([key, value]) => input.setAttribute(key, value));25    Object.defineProperty(input, "getBoundingClientRect", {26      configurable: true,27      value: () => ({28        width: 100,29        height: 20,30        top: 0,31        left: 0,32        right: 100,33        bottom: 20,34        x: 0,35        y: 0,36        toJSON: () => ({}),37      }),38    });39    document.body.appendChild(input);40    return input as HTMLInputElement;41  }4243  it("isLoginForm returns true for a username/password pair", () => {44    const username = visibleInput({ type: "email", name: "email" });45    const password = visibleInput({ type: "password", autocomplete: "current-password" });4647    expect(48      isLoginForm([49        { type: "username", el: username },50        { type: "password", el: password },51      ])52    ).toBe(true);53  });5455  it("isLoginForm returns false for fields without a password", () => {56    const username = visibleInput({ type: "text", name: "username" });5758    expect(isLoginForm([{ type: "username", el: username }])).toBe(false);59  });6061  it("isSignupForm returns true for confirm-password flows", () => {62    const password = visibleInput({ type: "password", name: "password" });63    const confirm = visibleInput({ type: "password", name: "confirmPassword" });6465    expect(66      isSignupForm([67        { type: "password", el: password },68        { type: "password", el: confirm },69      ])70    ).toBe(true);71  });7273  it("isSignupForm returns false for a single current-password field", () => {74    const password = visibleInput({ type: "password", autocomplete: "current-password" });7576    expect(isSignupForm([{ type: "password", el: password }])).toBe(false);77  });7879  it("detectLoginFields matches email and username-style inputs but not tag-name fields", () => {80    const email = visibleInput({ type: "email", name: "email" });81    const username = visibleInput({ type: "text", name: "login-id" });82    const tagName = visibleInput({ type: "text", name: "tag-name" });83    const password = visibleInput({ type: "password", autocomplete: "current-password" });84    const hidden = visibleInput({ type: "hidden", name: "username" });8586    const fields = detectLoginFields(document);8788    expect(fields.some((field) => field.el === email && field.type === "username")).toBe(true);89    expect(fields.some((field) => field.el === username && field.type === "username")).toBe(true);90    expect(fields.some((field) => field.el === password && field.type === "password")).toBe(true);91    expect(fields.some((field) => field.el === tagName)).toBe(false);92    expect(fields.some((field) => field.el === hidden)).toBe(false);93  });9495  it("getPageDomain falls back to the current hostname when no registrable domain exists", () => {96    expect(getPageDomain()).toBe(window.location.hostname);97  });98});99100describe("card form detection", () => {101  beforeEach(() => {102    document.body.innerHTML = "";103  });104105  it("detectCardForm — finds number field by autocomplete attribute", () => {106    document.body.innerHTML = '<input autocomplete="cc-number" /><input autocomplete="cc-exp-month" /><input autocomplete="cc-exp-year" /><input autocomplete="cc-csc" />';107    const result = detectCardForm(document);108    expect(result).not.toBeNull();109    expect(result!.number).toBeTruthy();110    expect(result!.expMonth).toBeTruthy();111  });112113  it("detectCardForm — finds fields by name/id heuristics when no autocomplete", () => {114    document.body.innerHTML = '<input name="cardnum" /><input name="expiry" /><input name="cvv" />';115    const result = detectCardForm(document);116    expect(result).not.toBeNull();117    expect(result!.number).toBeTruthy();118  });119120  it("detectCardForm — returns null when no card number field found", () => {121    document.body.innerHTML = '<input type="text" name="username" />';122    expect(detectCardForm(document)).toBeNull();123  });124125  it("hasPaymentProcessorIframe — returns true when Stripe iframe present", () => {126    document.body.innerHTML = '<iframe src="https://js.stripe.com/v3/"></iframe>';127    expect(hasPaymentProcessorIframe()).toBe(true);128  });129130  it("hasPaymentProcessorIframe — returns false on standard checkout page", () => {131    document.body.innerHTML = '<input name="cardnum" />';132    expect(hasPaymentProcessorIframe()).toBe(false);133  });134});