0c9f3f8635
React 19 types React.ReactElement props as unknown instead of any. Test helper functions that access element.props.children, .className, or .href need explicit props type parameters on React.ReactElement and isValidElement. Changes: - admin/PublicShell.test.ts: add WithChildren type, use React.ReactElement<WithChildren> - dashboard/PublicShell.test.ts: same pattern for childTypes and contentWrapper - dashboard/StatCard.test.ts: add ElementWithClass type for className access - dashboard/public-auth-pages.test.ts: add ElementWithHref type for href access No any, @ts-ignore, or type assertion bypass used.
97 lines
3.4 KiB
TypeScript
97 lines
3.4 KiB
TypeScript
import React, { isValidElement } from "react";
|
|
import { describe, expect, it } from "vitest";
|
|
import ForgotPasswordPageClient from "./forgot-password/ForgotPasswordPageClient";
|
|
import ResetPasswordPageClient from "./reset-password/ResetPasswordPageClient";
|
|
import ForgotPasswordPage from "./forgot-password/page";
|
|
import ResetPasswordPage from "./reset-password/page";
|
|
import AcceptInvitePage from "./onboarding/accept-invite/page";
|
|
import SignUpForm from "./sign-up/[[...sign-up]]/SignUpForm";
|
|
import SignUpPage from "./sign-up/[[...sign-up]]/page";
|
|
|
|
function collectText(node: unknown): string[] {
|
|
if (node === null || node === undefined || typeof node === "boolean")
|
|
return [];
|
|
if (typeof node === "string" || typeof node === "number")
|
|
return [String(node)];
|
|
if (Array.isArray(node)) return node.flatMap(collectText);
|
|
if (isValidElement<{ children?: React.ReactNode }>(node))
|
|
return collectText(node.props.children);
|
|
return [];
|
|
}
|
|
|
|
type ElementWithHref = { children?: React.ReactNode; href?: string; embedded?: boolean }
|
|
|
|
function findElement(
|
|
node: unknown,
|
|
predicate: (element: React.ReactElement<ElementWithHref>) => boolean,
|
|
): React.ReactElement<ElementWithHref> | null {
|
|
if (node === null || node === undefined || typeof node === "boolean")
|
|
return null;
|
|
if (Array.isArray(node)) {
|
|
for (const child of node) {
|
|
const found = findElement(child, predicate);
|
|
if (found) return found;
|
|
}
|
|
return null;
|
|
}
|
|
if (!isValidElement<ElementWithHref>(node)) return null;
|
|
if (predicate(node)) return node;
|
|
return findElement(node.props.children, predicate);
|
|
}
|
|
|
|
describe("dashboard public auth pages", () => {
|
|
it("renders forgot-password with public chrome by default", async () => {
|
|
const page = await ForgotPasswordPage({
|
|
searchParams: Promise.resolve({}),
|
|
});
|
|
|
|
expect(isValidElement(page)).toBe(true);
|
|
expect(page.type).toBe(ForgotPasswordPageClient);
|
|
expect(page.props.embedded).toBe(false);
|
|
});
|
|
|
|
it("renders forgot-password in embedded mode when requested", async () => {
|
|
const page = await ForgotPasswordPage({
|
|
searchParams: Promise.resolve({ embedded: "1" }),
|
|
});
|
|
|
|
expect(isValidElement(page)).toBe(true);
|
|
expect(page.type).toBe(ForgotPasswordPageClient);
|
|
expect(page.props.embedded).toBe(true);
|
|
});
|
|
|
|
it("renders sign-up in embedded mode when requested", async () => {
|
|
const page = await SignUpPage({
|
|
searchParams: Promise.resolve({ embedded: "1" }),
|
|
});
|
|
|
|
expect(isValidElement(page)).toBe(true);
|
|
expect(page.type).toBe(React.Suspense);
|
|
const child = page.props.children;
|
|
expect(isValidElement(child)).toBe(true);
|
|
expect(child.type).toBe(SignUpForm);
|
|
expect(child.props.embedded).toBe(true);
|
|
});
|
|
|
|
it("renders reset-password in embedded mode for the public shell route", () => {
|
|
const page = ResetPasswordPage();
|
|
|
|
expect(isValidElement(page)).toBe(true);
|
|
expect(page.type).toBe(ResetPasswordPageClient);
|
|
expect(page.props.embedded).toBe(true);
|
|
});
|
|
|
|
it("keeps accept-invite copy and sign-in handoff visible", () => {
|
|
const page = AcceptInvitePage();
|
|
const text = collectText(page).join(" ");
|
|
const signInLink = findElement(
|
|
page,
|
|
(element) => element.props.href === "/sign-in",
|
|
);
|
|
|
|
expect(text).toContain("Invitation accepted");
|
|
expect(text).toContain("Sign in to dashboard");
|
|
expect(signInLink).not.toBeNull();
|
|
});
|
|
});
|