Presupuestador_web/client/src/ui/form.test.tsx

102 lines
2.7 KiB
TypeScript

import { act, useEffect, useRef } from "react";
import { createRoot } from "react-dom/client";
import { FormProvider, UseFormReturn, useForm } from "react-hook-form";
import { FormField } from "./form";
type TestFormValues = {
items: Array<{ quantity: string }>;
};
declare global {
var IS_REACT_ACT_ENVIRONMENT: boolean;
}
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
type DynamicQuantityFieldProps = {
name: "items.0.quantity" | "items.1.quantity";
onMount: () => void;
};
const DynamicQuantityField = ({ name, onMount }: DynamicQuantityFieldProps) => {
const onMountRef = useRef(onMount);
useEffect(() => {
onMountRef.current();
}, []);
return (
<FormField
name={name}
render={({ field }) => <input aria-label='quantity' {...field} />}
/>
);
};
type FormHarnessProps = DynamicQuantityFieldProps & {
onFormReady: (form: UseFormReturn<TestFormValues>) => void;
};
const FormHarness = ({ name, onMount, onFormReady }: FormHarnessProps) => {
const form = useForm<TestFormValues>({
defaultValues: {
items: [{ quantity: "1" }, { quantity: "2" }],
},
});
useEffect(() => {
onFormReady(form);
}, [form, onFormReady]);
return (
<FormProvider {...form}>
<DynamicQuantityField name={name} onMount={onMount} />
</FormProvider>
);
};
describe("FormField", () => {
let container: HTMLDivElement;
let root: ReturnType<typeof createRoot>;
beforeEach(() => {
container = document.createElement("div");
document.body.appendChild(container);
root = createRoot(container);
});
afterEach(() => {
act(() => root.unmount());
container.remove();
});
it("resubscribes a Controller when its name changes without remounting its parent", () => {
const onMount = jest.fn();
let form: UseFormReturn<TestFormValues> | undefined;
const renderHarness = (name: DynamicQuantityFieldProps["name"]) => {
root.render(
<FormHarness name={name} onMount={onMount} onFormReady={(value) => (form = value)} />
);
};
act(() => renderHarness("items.0.quantity"));
const inputBeforeRename = container.querySelector("input[aria-label='quantity']") as HTMLInputElement;
expect(inputBeforeRename.value).toBe("1");
expect(onMount).toHaveBeenCalledTimes(1);
act(() => renderHarness("items.1.quantity"));
expect(onMount).toHaveBeenCalledTimes(1);
expect((container.querySelector("input[aria-label='quantity']") as HTMLInputElement).value).toBe("2");
act(() => {
form?.setValue("items.1.quantity", "5");
});
expect((container.querySelector("input[aria-label='quantity']") as HTMLInputElement).value).toBe("5");
expect(form?.getValues("items.1.quantity")).toBe("5");
});
});