128 lines
5.0 KiB
TypeScript
128 lines
5.0 KiB
TypeScript
import "@testing-library/jest-dom";
|
|
import { fireEvent, render, screen, within } from "@testing-library/react";
|
|
import React from "react";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import { RegisterForm } from "./RegisterForm";
|
|
|
|
const routerState = vi.hoisted(() => ({
|
|
searchParams: new URLSearchParams(),
|
|
}));
|
|
|
|
vi.mock("react-router", async (importOriginal) => {
|
|
const actual = await importOriginal<typeof import("react-router")>();
|
|
return {
|
|
...actual,
|
|
Form: ({ children, ...props }: React.FormHTMLAttributes<HTMLFormElement>) => <form {...props}>{children}</form>,
|
|
useLocation: () => ({ pathname: "/register" }),
|
|
useMatches: () => [],
|
|
useNavigation: () => ({ state: "idle" }),
|
|
useSearchParams: () => [routerState.searchParams],
|
|
};
|
|
});
|
|
|
|
vi.mock("react-i18next", () => ({
|
|
useTranslation: () => ({
|
|
i18n: { exists: () => true },
|
|
t: (key: string) => key,
|
|
}),
|
|
}));
|
|
|
|
vi.mock("~/utils/data/useRootData", () => ({
|
|
useRootData: () => ({
|
|
csrf: "csrf-token",
|
|
appConfiguration: {
|
|
auth: {
|
|
requireEmailVerification: false,
|
|
requireName: false,
|
|
requireOrganization: false,
|
|
authMethods: {
|
|
emailPassword: { enabled: true },
|
|
},
|
|
captcha: {
|
|
enabled: false,
|
|
instanceUrl: undefined,
|
|
loginSiteKey: undefined,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
}));
|
|
|
|
describe("RegisterForm", () => {
|
|
it("posts redirectTo from inside the email-password form", () => {
|
|
routerState.searchParams = new URLSearchParams({ redirect: "/app/acme/dashboard" });
|
|
|
|
render(<RegisterForm error={undefined} />);
|
|
|
|
const form = document.querySelector('[data-ui-id="ui.auth.register.form"]');
|
|
expect(form).toBeInTheDocument();
|
|
expect(form?.querySelector('input[name="redirectTo"]')).toHaveValue("/app/acme/dashboard");
|
|
});
|
|
|
|
it("renders registration copy and localized password requirement labels", () => {
|
|
routerState.searchParams = new URLSearchParams();
|
|
|
|
render(
|
|
<RegisterForm
|
|
error={undefined}
|
|
passwordPolicy={{
|
|
minLength: 8,
|
|
requireUpper: true,
|
|
requireLower: true,
|
|
requireDigit: true,
|
|
requireSpecial: true,
|
|
}}
|
|
/>
|
|
);
|
|
|
|
expect(document.querySelector('[data-ui-id="ui.auth.register.form"]')).toBeInTheDocument();
|
|
expect(screen.getByRole("button", { name: "account.register.prompts.register.title" })).toBeInTheDocument();
|
|
expect(screen.getByText("account.register.bySigningUp", { exact: false })).toBeInTheDocument();
|
|
expect(screen.getByRole("link", { name: "account.register.termsAndConditions" })).toHaveAttribute("href", "/terms-and-conditions");
|
|
expect(screen.getByRole("link", { name: "account.register.privacyPolicy" })).toHaveAttribute("href", "/privacy-policy");
|
|
|
|
const requirements = screen.getByRole("list");
|
|
expect(requirements).toHaveAccessibleName("account.register.passwordRequirements.label");
|
|
const items = within(requirements).getAllByRole("listitem");
|
|
expect(items.map((item) => item.textContent)).toEqual([
|
|
"[ ] account.register.passwordRequirements.minLength",
|
|
"[ ] account.register.passwordRequirements.upper",
|
|
"[ ] account.register.passwordRequirements.lower",
|
|
"[ ] account.register.passwordRequirements.digit",
|
|
"[ ] account.register.passwordRequirements.special",
|
|
]);
|
|
expect(items[0]).toHaveAccessibleName("account.register.passwordRequirements.notMet: account.register.passwordRequirements.minLength");
|
|
|
|
fireEvent.change(screen.getByLabelText(/account\.shared\.password/), { target: { value: "Abcdef1!" } });
|
|
|
|
expect(items.map((item) => item.textContent)).toEqual([
|
|
"[x] account.register.passwordRequirements.minLength",
|
|
"[x] account.register.passwordRequirements.upper",
|
|
"[x] account.register.passwordRequirements.lower",
|
|
"[x] account.register.passwordRequirements.digit",
|
|
"[x] account.register.passwordRequirements.special",
|
|
]);
|
|
expect(items[0]).toHaveAccessibleName("account.register.passwordRequirements.met: account.register.passwordRequirements.minLength");
|
|
});
|
|
|
|
it("keeps lead-conversion email locked while preserving hidden conversion fields", () => {
|
|
routerState.searchParams = new URLSearchParams();
|
|
|
|
render(
|
|
<RegisterForm
|
|
error={undefined}
|
|
data={{ email: "lead@example.com" }}
|
|
leadConversion={{ leadId: "lead_123", token: "signed-token", planId: "plan_pro" }}
|
|
passwordPolicy={{ minLength: 8, requireUpper: false, requireLower: false, requireDigit: false, requireSpecial: false }}
|
|
/>
|
|
);
|
|
|
|
expect(screen.getByLabelText(/account\.shared\.email/)).toHaveAttribute("readonly");
|
|
expect(screen.getByLabelText(/account\.shared\.email/)).toHaveAttribute("type", "email");
|
|
expect(document.querySelector('input[name="leadId"]')).toHaveValue("lead_123");
|
|
expect(document.querySelector('input[name="leadToken"]')).toHaveValue("signed-token");
|
|
expect(document.querySelector('input[name="leadPlanId"]')).toHaveValue("plan_pro");
|
|
});
|
|
});
|