Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FakeAsync can't always flush timers properly #583

Open
dmitryelagin opened this issue Jan 17, 2020 · 5 comments
Open

FakeAsync can't always flush timers properly #583

dmitryelagin opened this issue Jan 17, 2020 · 5 comments

Comments

@dmitryelagin
Copy link

There are cases, when flushTimers can't properly work.

Here is the test case:

import 'package:quiver/testing/async.dart';
import 'package:test/test.dart';

void main() {
  group('Counter should', () {
    int counter;

    setUp(() {
      counter = 0;
    });

    test('be incremented two times', () {
      FakeAsync().run((FakeAsync fakeAsync) {
        Stream<Object>
          .periodic(Duration(hours: 1))
          .take(1)
          .listen(
            (_) {
              counter += 1;
            },
            onDone: () {
              counter += 1;
            }
          );

        fakeAsync.flushTimers();

        expect(counter, 2);
      });
    });
  });
}

Here is the result:

Expected: <2>
  Actual: <1>

package:test_api                                         expect
test/quiver_test.dart 30:9                               main.<fn>.<fn>.<fn>
package:quiver/testing/src/async/fake_async.dart 196:24  _FakeAsync.run.<fn>
dart:async                                               _CustomZone.runGuarded
package:quiver/testing/src/async/fake_async.dart 195:11  _FakeAsync.run
test/quiver_test.dart 13:19                              main.<fn>.<fn>

✖ Counter should be incremented two times
Exited (1)

The reason for failure is that sometimes subscription cancel method returns Future._nullFuture. The onDone callback will be called after resolving of this Future, but it is already resolved. So, it will be called with scheduleMicrotask of the zone where the Future was resolved, and it is the root zone for Future._nullFuture. See this issue for additional details.

I have a lot of failing tests just because of such behavior and I am trying to find a proper solution.

@IgorZubov
Copy link

Have the same problem. Is there any chance of update?

@cbracken
Copy link
Member

/cc @yjbanov for thoughts.

@brianegan
Copy link

brianegan commented Mar 4, 2020

This issue has been reported to the RxDart issues tracker a few times, and I've also seen it crop up on the Flutter side as well.

It looks like Stream.periodic also uses Future._nullFuture under the hood so I'd bet that could be the root cause of these issues as well:

flutter/flutter#40074
flutter/flutter#17738
ReactiveX/rxdart#365

@yjbanov
Copy link
Member

yjbanov commented Mar 5, 2020

Thanks for the detailed report. I can reproduce this locally. I'm not yet sure what we can do about it in FakeAsync. FakeAsync relies on zones to function. Anything that explicitly changes the zone will interfere with this functionality. Something as simple as Stream.periodic explicitly throwing you out into the root zone looks extremely suspicious to me. I think it shouldn't be doing that. It defeats the purpose of the zones in the first place.

dart-lang/sdk#40131 seems to be the right place for this discussion. I'll see if I can contribute to that discussion.

@fzyzcjy
Copy link

fzyzcjy commented Jun 8, 2022

Hi is there any updates? Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants