102 lines
2.7 KiB
TypeScript
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");
|
|
});
|
|
});
|