Skip to content

Commit

Permalink
Fix bug where unmounted input would still be validated
Browse files Browse the repository at this point in the history
  • Loading branch information
zackify committed Mar 11, 2021
1 parent 1d27337 commit 16e673e
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 13 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-validify",
"version": "6.0.3",
"version": "6.0.4",
"description": "Form validation made easy",
"main": "dist/index.js",
"module": "lib/index.js",
Expand Down
10 changes: 8 additions & 2 deletions src/use-field.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect } from "react";
import get from "lodash/get";
import set from "lodash/set";
import validate from "./validate";
Expand All @@ -21,7 +21,13 @@ const useField = ({ name, rules: fieldRules }: UseFieldProps) => {
rules,
} = React.useContext(FormContext);

rules.current[name] = fieldRules || [];
//set the rules when they change, clear when unmounted
useEffect(() => {
rules.current[name] = fieldRules || [];
return () => {
rules.current[name] = [];
};
}, [fieldRules]);

let value = get(values, name);
// Pulling out just this field's errors
Expand Down
1 change: 1 addition & 0 deletions src/use-submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const useSubmit = () => {

return {
values,
errors,
handleSubmit,
canSubmit: !errors.length,
};
Expand Down
40 changes: 32 additions & 8 deletions tests/form.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { render, fireEvent, wait } from "@testing-library/react";
import { TestForm } from "./helpers/form";
import { render, fireEvent, wait, act } from "@testing-library/react";
import { TestForm, TestFormWithRemovedField } from "./helpers/form";

test("Checks dependent rule", async () => {
let errorMessage = "Must be longer value than date 2 field";
Expand Down Expand Up @@ -122,7 +122,7 @@ test("Submit calls onSubmit if validation passes", async () => {
});

test("Form works without rules object passed", async () => {
let { queryByPlaceholderText, queryByText } = render(<TestForm noRules />);
let { queryByPlaceholderText } = render(<TestForm noRules />);

//blur the field
const name = queryByPlaceholderText("name");
Expand All @@ -135,9 +135,7 @@ test("Form works without rules object passed", async () => {

test("Empty input value gets passed as empty string to rule fn", async () => {
const spy = jest.fn();
let { queryByPlaceholderText, queryByText } = render(
<TestForm nameRule={spy} />
);
let { queryByText } = render(<TestForm nameRule={spy} />);
const submit = queryByText("Submit Form");

//press the submit button
Expand All @@ -149,8 +147,7 @@ test("Empty input value gets passed as empty string to rule fn", async () => {
});

test("Field validation shows errors on submit even without touching any fields", async () => {
let { queryByPlaceholderText, getByText } = render(<TestForm />);
const name = queryByPlaceholderText("name");
let { getByText } = render(<TestForm />);

//trigger submit
getByText("Submit Form").click();
Expand Down Expand Up @@ -186,3 +183,30 @@ test(`Untouched fields shouldn't validate unless submitted first`, () => {

expect(queryByText("This field is required")).toBeNull();
});

test(`Doesnt check rule after component is unmounted`, async () => {
const spy = jest.fn();
let { getByText, queryByPlaceholderText } = render(
<TestFormWithRemovedField onSubmit={spy} />
);
fireEvent.change(queryByPlaceholderText("email"), {
target: { value: "" },
});
await act(async () => await new Promise((resolve) => setTimeout(resolve, 0)));
expect(queryByPlaceholderText("email")).toEqual(null);

fireEvent.change(queryByPlaceholderText("name"), {
target: { value: "testing" },
});
fireEvent.change(queryByPlaceholderText("date1"), {
target: { value: "testing" },
});
fireEvent.change(queryByPlaceholderText("date2"), {
target: { value: "test" },
});

getByText("Submit Form").click();

//it should call submit even though email is empty, because it was unmounted
expect(spy.mock.calls[0][0].email).toEqual("");
});
22 changes: 20 additions & 2 deletions tests/helpers/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Props = {
noRules?: boolean;
nameRule?: RuleFn;
onSubmit?: (values: any) => any;
unmountEmail?: boolean;
};

type TestValues = {
Expand All @@ -24,16 +25,33 @@ type TestValues = {
name?: string;
};

export const TestForm = ({ onSubmit, noRules, nameRule }: Props) => {
export const TestForm = ({
onSubmit,
noRules,
nameRule,
unmountEmail,
}: Props) => {
let [values, setValues] = useState<TestValues>({ email: "test" });

return (
<Form values={values} onValues={setValues}>
<Input name="email" rules={noRules ? undefined : [required, email]} />
{unmountEmail ? null : (
<Input name="email" rules={noRules ? undefined : [required, email]} />
)}
<Input name="name" rules={noRules ? undefined : [nameRule || required]} />
<Input name="date1" rules={noRules ? undefined : [greaterThanDate2]} />
<Input name="date2" />
<Submit onSubmit={onSubmit} />
</Form>
);
};

export const TestFormWithRemovedField = (props: Props) => {
let [unmountEmail, setUnmount] = useState(false);

useEffect(() => {
setTimeout(() => setUnmount(true), 0);
}, []);

return <TestForm {...props} unmountEmail={unmountEmail} />;
};

0 comments on commit 16e673e

Please sign in to comment.