@@ -4,6 +4,7 @@ import "@testing-library/jest-dom/extend-expect";
44import { ErrorBoundary , Toggle , wrapWith } from "./testUtils" ;
55import Form from "./ReactFinalForm" ;
66import Field from "./Field" ;
7+ import { useFormState } from "." ;
78
89const 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