fix(react-native): wait for AfterQuery subscribers before settling - #12767
fix(react-native): wait for AfterQuery subscribers before settling#12767kyungseopk1m wants to merge 1 commit into
Conversation
The success callback awaited the AfterQuery subscribers before resolving, but the error callback rejected straight after broadcasting. A subscriber that logs or transforms failures never finished before the caller saw the rejection, and a subscriber that threw surfaced as an unhandled rejection because fail() had already run. The outer finally could not cover this: executeSql is callback based, so it ran before either callback fired, with an empty promise list. That is why the success path awaited again inside the callback. Drop it. The success path now rejects with the subscriber error, while the error path swallows it so it cannot hide the original QueryFailedError. This matches how the same pair is handled in the cordova and nativescript runners.
commit: |
Code Review by Qodo
1. as unknown as ReactNativeDriver cast
|
|
Both are pre-existing: |
Fixes #12769.
Problem
ReactNativeQueryRunner.query()treats the twoexecuteSqlcallbacks differently.The success callback waits for the
AfterQuerysubscribers before resolving:The error callback broadcasts and rejects immediately:
So on a failed query the caller sees the rejection before the subscribers have run. A subscriber that records failures may still be in flight, and one that throws produces an unhandled rejection, since
fail()has already been called and nobody is holding its promise.The outer
finally { await broadcasterResult.wait() }did not help.executeSqlis callback based, so thetrybody returns as soon as the call is registered and thefinallyruns whilebroadcasterResult.promisesis still empty. Neither callback has fired at that point. That is exactly why the success path had to await a second time inside the callback.The success path has a related hole. If a subscriber rejects,
await Promise.all(...)rejects inside an async callback with no handler, so neitherok()norfail()is ever called and the query promise hangs forever.Fix
Await the subscribers on both paths and drop the outer
finally, which was dead.The two paths handle a throwing subscriber differently, matching the cordova and nativescript runners:
QueryFailedErrorthe caller needs to see, so its error is swallowed.Tests
test/unit/driver/query-broadcast-events.test.tsdrives the runner against a mockedexecuteSql:unhandledRejectionEach case is guarded by a timeout so a regression into the hang fails the test rather than stalling the run. Reverting the error path fails the first two, reverting the success path fails the third.
pnpm run test:fastis otherwise unchanged.Related
Same class as the cordova and nativescript work. The runners share this callback shape, and react-native was the one left with the asymmetry.