Repository navigation
Some flutter_tools tests using FakeAsync are always passing #60675
Description
There are some tests that use FakeAsync.run() that are not awaiting the call, for example:
flutter/packages/flutter_tools/test/general.shard/device_test.dart
Lines 92 to 95 in 0e735e4
| FakeAsync().run((FakeAsync time) async { | |
| final FakePollingDeviceDiscovery pollingDeviceDiscovery = FakePollingDeviceDiscovery(); | |
| await pollingDeviceDiscovery.startPolling(); | |
| time.elapse(const Duration(milliseconds: 4001)); |
It seems like this is resulted in the tests always passing immediately. For example adding throw 'fail'; as the first line inside the callback does nothing - the test still passes.
I think these tests need await in front of the FakeAsync().run, however doing so right now causes them to hang - which I think is because the implementation uses await which queues a microtask but the queue is never flushed (since the code stops on the await).
Based on what @Hixie said, I think flutter_test is handling this by constantly pumping the microtask queue, however the flutter_tools tests don't run with flutter_test so don't have an equivilent. I think the relevant code in flutter_test is this bit:
flutter/packages/flutter_test/lib/src/binding.dart
Lines 1128 to 1146 in 868c4d8
| return Future<void>.microtask(() async { | |
| // testBodyResult is a Future that was created in the Zone of the | |
| // fakeAsync. This means that if we await it here, it will register a | |
| // microtask to handle the future _in the fake async zone_. We avoid this | |
| // by calling '.then' in the current zone. While flushing the microtasks | |
| // of the fake-zone below, the new future will be completed and can then | |
| // be used without fakeAsync. | |
| final Future<void> resultFuture = testBodyResult.then<void>((_) { | |
| // Do nothing. | |
| }); | |
| // Resolve interplay between fake async and real async calls. | |
| fakeAsync.flushMicrotasks(); | |
| while (_pendingAsyncTasks != null) { | |
| await _pendingAsyncTasks.future; | |
| fakeAsync.flushMicrotasks(); | |
| } | |
| return resultFuture; | |
| }); |
Activity
DanTup commentedon Jul 1, 2020
For my tests, I just made a small loop that flushes the queue:
https://github.com/flutter/flutter/pull/55376/files#diff-1a0ff66910e803e1ddabc1968f7d9e8bR358-R371
I don't know if this may be suitable to use elsewhere too (it may also be worth having a lint or something to catch these - perhaps the existing unawaited futures one would work?).
zanderso commentedon Aug 5, 2020
Bumping to P2 due to lost test coverage of currently unknown scope, and to force to surface in the next triage meeting to discuss.
jonahwilliams commentedon Aug 13, 2020
FakeAsync cases are now updated where feasible and skips added for the existing failures. Since we can't regress further, I'm bumping to a P3
zanderso commentedon Aug 13, 2020
What's the rough number of tests that are skipped?
jonahwilliams commentedon Aug 13, 2020
5 test cases
jonahwilliams commentedon Dec 2, 2020
3 test cases left
jonahwilliams commentedon Dec 4, 2020
removing assignment because I will be OOO
jonahwilliams commentedon May 4, 2021
One remaining test: https://github.com/flutter/flutter/blob/cbf885b74919bf4b0796cc216b8b80e6b3ccb266/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart
Restore skipped iOS test by looping over `FakeAsync` elapse. (#158204)
github-actions commentedon Nov 20, 2024
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.