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

Epics break testing when using timers #31

Closed
kentcb opened this issue Aug 22, 2019 · 3 comments
Closed

Epics break testing when using timers #31

kentcb opened this issue Aug 22, 2019 · 3 comments

Comments

@kentcb
Copy link

kentcb commented Aug 22, 2019

Hi,

I might be missing something obvious here, but it seems to me that epics that include timers break tests, even if one explicitly tears down the store.

Here's the simplest possible repro:

void main() {
  group('repro', () {
    testWidgets('test', (tester) async {
      final store = Store<String>(
        (state, dynamic action) => state,
        initialState: 'Greetings!',
        middleware: [
          EpicMiddleware(_middleware),
        ],
      );

      final widget = StoreProvider<String>(
        store: store,
        child: MaterialApp(
          home: StoreConnector<String, String>(
            converter: (s) => s.state,
            builder: (context, state) => Text(state),
            // At least one dispatch is required, otherwise the epic is never initialized
            onInit: (store) => store.dispatch('whatever'),
          ),
        ),
      );

      await tester.pumpWidget(widget);

      await store.teardown();
    });
  });
}

Stream<dynamic> _middleware(Stream<dynamic> actions, EpicStore<String> store) => Observable<dynamic>(actions).debounceTime(aSecond).ignoreElements();

Running this gives:

_AssertionError ('package:flutter_test/src/binding.dart': Failed assertion: line 1050 pos 7: '_currentFakeAsync.nonPeriodicTimerCount == 0': A Timer is still pending even after the widget tree was disposed.)

I considered doing something like this:

Stream<dynamic> _middleware(Stream<dynamic> actions, EpicStore<String> store) =>
  Observable<dynamic>(actions)
    .debounceTime(aSecond)
    .ignoreElements()
    .takeUntil<dynamic>(Observable<dynamic>.fromFuture(actions.last));

But it appears as though the actions stream never completes either (even when tearing down the store).

Am I doing something wrong here?

@kentcb
Copy link
Author

kentcb commented Aug 22, 2019

One silly little workaround I could use (just tested and it seems to work) is to define my own Teardown action that I dispatch (only from tests) when I want to bring things to an end. All relevant epics can listen for that action as a means of terminating their pipelines.

@kentcb
Copy link
Author

kentcb commented Aug 22, 2019

Spoke too soon. My workaround doesn't appear to be working for Observable.periodic 🤔

@brianegan
Copy link
Owner

Heya @kentcb -- after a long search, the fundamental reason all of these timers are breaking has finally been tracked down and is being discussed here: dart-lang/sdk#40131

Gonna close this out of this repo since there's really nothing I can do to fix this :/

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

2 participants