Skip to content

Commit ffb8edd

Browse files
committed
try fix side effect on field level async validation
1 parent 334f001 commit ffb8edd

1 file changed

Lines changed: 154 additions & 0 deletions

File tree

src/Field.test.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import "@testing-library/jest-dom/extend-expect";
44
import { ErrorBoundary, Toggle, wrapWith } from "./testUtils";
55
import Form from "./ReactFinalForm";
66
import Field from "./Field";
7+
import { useFormState } from ".";
78

89
const onSubmitMock = (values) => {};
910

@@ -1161,6 +1162,159 @@ describe("Field", () => {
11611162
expect(getByTestId("validating")).toHaveTextContent("Not Validating");
11621163
});
11631164

1165+
it("should have validating state false after a field has been unregistred during mixed async validation", async () => {
1166+
const Test = () => {
1167+
const [hasField, setHasField] = React.useState(true);
1168+
const state = useFormState({ subscription: { validating: true } });
1169+
1170+
return (
1171+
<div>
1172+
{!hasField && (
1173+
<Field
1174+
name="lastname"
1175+
component="input"
1176+
validate={(value) => (value ? undefined : "Required")}
1177+
data-testid="lastname"
1178+
/>
1179+
)}
1180+
{hasField && (
1181+
<Field
1182+
name="name"
1183+
component="input"
1184+
validate={async (value) => {
1185+
await timeout(5);
1186+
return value === "erikras" ? "Username taken" : undefined;
1187+
}}
1188+
data-testid="name"
1189+
/>
1190+
)}
1191+
<div data-testid="validating">
1192+
{state.validating === true ? "Spinner" : "Not Validating"}
1193+
</div>
1194+
<button data-testid="hide" onClick={() => setHasField(false)}>
1195+
Hide field
1196+
</button>
1197+
</div>
1198+
);
1199+
};
1200+
1201+
const { getByTestId, queryByTestId } = render(
1202+
<Form onSubmit={onSubmitMock}>
1203+
{({ handleSubmit }) => (
1204+
<form onSubmit={handleSubmit}>
1205+
<Test />
1206+
</form>
1207+
)}
1208+
</Form>,
1209+
);
1210+
1211+
expect(getByTestId("validating")).toHaveTextContent("Spinner");
1212+
await sleep(6);
1213+
expect(getByTestId("name").value).toBe("");
1214+
1215+
// validating state is ok as long as a Field with async validation is visible
1216+
expect(getByTestId("validating")).toHaveTextContent("Not Validating");
1217+
fireEvent.change(getByTestId("name"), { target: { value: "erik" } });
1218+
1219+
expect(getByTestId("validating")).toHaveTextContent("Spinner");
1220+
await sleep(6);
1221+
1222+
expect(getByTestId("validating")).toHaveTextContent("Not Validating");
1223+
1224+
// validating state is KO if Field is unregistered while validating
1225+
fireEvent.change(getByTestId("name"), { target: { value: "erikr" } });
1226+
1227+
expect(getByTestId("validating")).toHaveTextContent("Spinner");
1228+
fireEvent.click(getByTestId("hide"));
1229+
expect(queryByTestId("name")).not.toBeInTheDocument();
1230+
1231+
// when an other field with sync validation is present, it should not have side effect on the async validation
1232+
expect(queryByTestId("lastname")).toBeInTheDocument();
1233+
expect(getByTestId("validating")).toHaveTextContent("Spinner");
1234+
1235+
await sleep(6);
1236+
1237+
expect(getByTestId("validating")).toHaveTextContent("Not Validating");
1238+
});
1239+
1240+
it("should have validating state false after a field has been unregistred during full async validation", async () => {
1241+
const Test = () => {
1242+
const [hasField, setHasField] = React.useState(true);
1243+
const state = useFormState({ subscription: { validating: true } });
1244+
1245+
return (
1246+
<div>
1247+
{!hasField && (
1248+
<Field
1249+
name="lastname"
1250+
component="input"
1251+
validate={async (value) => {
1252+
await timeout(5);
1253+
return value ? undefined : "Required";
1254+
}}
1255+
data-testid="lastname"
1256+
/>
1257+
)}
1258+
{hasField && (
1259+
<Field
1260+
name="name"
1261+
component="input"
1262+
validate={async (value) => {
1263+
await timeout(5);
1264+
return value === "erikras" ? "Username taken" : undefined;
1265+
}}
1266+
data-testid="name"
1267+
/>
1268+
)}
1269+
<div data-testid="validating">
1270+
{state.validating === true ? "Spinner" : "Not Validating"}
1271+
</div>
1272+
<button data-testid="hide" onClick={() => setHasField(false)}>
1273+
Hide field
1274+
</button>
1275+
</div>
1276+
);
1277+
};
1278+
1279+
const { getByTestId, queryByTestId } = render(
1280+
<Form onSubmit={onSubmitMock}>
1281+
{({ handleSubmit }) => (
1282+
<form onSubmit={handleSubmit}>
1283+
<Test />
1284+
</form>
1285+
)}
1286+
</Form>,
1287+
);
1288+
1289+
expect(getByTestId("validating")).toHaveTextContent("Spinner");
1290+
await sleep(6);
1291+
expect(getByTestId("name").value).toBe("");
1292+
1293+
// validating state is ok as long as a Field with async validation is visible
1294+
expect(getByTestId("validating")).toHaveTextContent("Not Validating");
1295+
fireEvent.change(getByTestId("name"), { target: { value: "erik" } });
1296+
1297+
expect(getByTestId("validating")).toHaveTextContent("Spinner");
1298+
await sleep(6);
1299+
1300+
expect(getByTestId("validating")).toHaveTextContent("Not Validating");
1301+
1302+
// validating state is KO if Field is unregistered while validating
1303+
fireEvent.change(getByTestId("name"), { target: { value: "erikr" } });
1304+
1305+
expect(getByTestId("validating")).toHaveTextContent("Spinner");
1306+
fireEvent.click(getByTestId("hide"));
1307+
expect(queryByTestId("name")).not.toBeInTheDocument();
1308+
1309+
// when an other field with sync validation is present, it should not have side effect on the async validation
1310+
expect(queryByTestId("lastname")).toBeInTheDocument();
1311+
expect(getByTestId("validating")).toHaveTextContent("Spinner");
1312+
1313+
await sleep(6);
1314+
1315+
expect(getByTestId("validating")).toHaveTextContent("Not Validating");
1316+
});
1317+
11641318
it("not call record-level validation on Field mount", () => {
11651319
const validate = jest.fn();
11661320
const { getByText } = render(

0 commit comments

Comments
 (0)