@@ -110,11 +110,17 @@ describe("form.async-validation - utility behavior", () => {
110110 assert . deepEqual ( result , { username : "Taken" } ) ;
111111 } ) ;
112112
113- test ( "runAsyncValidation swallows validator rejection" , async ( ) => {
114- const result = await runAsyncValidation ( { username : "x" } , async ( ) =>
115- Promise . reject ( new Error ( "network" ) ) ,
113+ test ( "runAsyncValidation wraps validator rejection" , async ( ) => {
114+ await assert . rejects (
115+ runAsyncValidation ( { username : "x" } , async ( ) => Promise . reject ( new Error ( "network" ) ) ) ,
116+ ( error : unknown ) => {
117+ assert . ok ( error instanceof Error ) ;
118+ assert . equal ( error . message , "async form validation failed: network" ) ;
119+ assert . ok ( ( error as { cause ?: unknown } ) . cause instanceof Error ) ;
120+ assert . equal ( ( ( error as { cause ?: unknown } ) . cause as Error ) . message , "network" ) ;
121+ return true ;
122+ } ,
116123 ) ;
117- assert . deepEqual ( result , { } ) ;
118124 } ) ;
119125
120126 test ( "createDebouncedAsyncValidator executes only after debounce window" , async ( ) => {
@@ -259,6 +265,36 @@ describe("form.async-validation - utility behavior", () => {
259265 timers . restore ( ) ;
260266 }
261267 } ) ;
268+
269+ test ( "createDebouncedAsyncValidator ignores rejected in-flight results after cancel" , async ( ) => {
270+ const timers = useFakeTimers ( ) ;
271+ try {
272+ const deferred = createDeferred < ValidationResult < Values > > ( ) ;
273+ const results : ValidationResult < Values > [ ] = [ ] ;
274+ const errors : unknown [ ] = [ ] ;
275+ const validator = createDebouncedAsyncValidator < Values > (
276+ async ( ) => deferred . promise ,
277+ 0 ,
278+ ( value ) => {
279+ results . push ( value ) ;
280+ } ,
281+ ( error ) => {
282+ errors . push ( error ) ;
283+ } ,
284+ ) ;
285+
286+ validator . run ( { username : "late" , email : "" } ) ;
287+ timers . tick ( 0 ) ;
288+ validator . cancel ( ) ;
289+ deferred . reject ( new Error ( "late failure" ) ) ;
290+ await flushMicrotasks ( ) ;
291+
292+ assert . equal ( results . length , 0 ) ;
293+ assert . equal ( errors . length , 0 ) ;
294+ } finally {
295+ timers . restore ( ) ;
296+ }
297+ } ) ;
262298} ) ;
263299
264300describe ( "form.async-validation - useForm behavior" , ( ) => {
@@ -422,7 +458,7 @@ describe("form.async-validation - useForm behavior", () => {
422458 assert . equal ( form . errors . email , "taken" ) ;
423459 } ) ;
424460
425- test ( "handleSubmit continues when async validation throws network error" , async ( ) => {
461+ test ( "handleSubmit aborts submit when async validation throws network error" , async ( ) => {
426462 const h = createFormHarness ( ) ;
427463 let submitCalls = 0 ;
428464 const opts = options ( {
@@ -434,11 +470,13 @@ describe("form.async-validation - useForm behavior", () => {
434470 } ,
435471 } ) ;
436472
437- const form = h . render ( opts ) ;
473+ let form = h . render ( opts ) ;
438474 form . handleSubmit ( ) ;
439475 await flushMicrotasks ( 4 ) ;
476+ form = h . render ( opts ) ;
440477
441- assert . equal ( submitCalls , 1 ) ;
478+ assert . equal ( submitCalls , 0 ) ;
479+ assert . equal ( form . isSubmitting , false ) ;
442480 } ) ;
443481
444482 test ( "handleSubmit rejects concurrent submits while pending" , async ( ) => {
0 commit comments