Bloc: ExpectLater does not complete when all states are added to the state stream

Created on 2 Nov 2019  Β·  10Comments  Β·  Source: felangel/bloc

Describe the bug
I've been looking on how to test the bloc listener here and here but for some reason the following test won't complete and I'm not sure why is that.

To Reproduce
This is the test in question:
Test that is not completing

And this is the bloc code for the login. I can see the breakpoints hitting but when the state LoginFailure returns it just won't complete.

Login bloc under test

Expected behavior
Test to be completed

Screenshots
It can even run for minutes! if I don't stop it manually
image

*Logs *

$ flutter doctor -v
[√] Flutter (Channel stable, v1.9.1+hotfix.4, on Microsoft Windows [Version 10.0.18362.418], locale en-US)
    β€’ Flutter version 1.9.1+hotfix.4 at C:\flutter\flutter
    β€’ Framework revision cc949a8e8b (5 weeks ago), 2019-09-27 15:04:59 -0700
    β€’ Engine revision b863200c37
    β€’ Dart version 2.5.0


[√] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    β€’ Android SDK at C:\Android\android-sdk
    β€’ Android NDK location not configured (optional; useful for native profiling support)
    β€’ Platform android-28, build-tools 28.0.3
    β€’ ANDROID_HOME = C:\Android\android-sdk
    β€’ Java binary at: C:\Program Files\Java\jdk1.8.0_221\bin\java
    β€’ Java version Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
    β€’ All Android licenses accepted.

[!] Android Studio (not installed)
    β€’ Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/setup/#android-setup for detailed instructions).

[√] VS Code (version 1.39.2)
    β€’ VS Code at C:\Users\mihai\AppData\Local\Programs\Microsoft VS Code
    β€’ Flutter extension version 3.6.0

[!] Connected device
    ! No devices available

! Doctor found issues in 2 categories.
question

Most helpful comment

@mihai9112 you should change your expectation to

expectLater(_authenticationBloc, emitsInOrder(expectedStates));

because in v1.0.0 blocs extend Stream so there is no longer a state stream property. The state property now refers to the bloc's current state.

Let me know if that helps πŸ‘

All 10 comments

When removing one of the expected states from the test I get the following error

The following assertion was thrown running a test:
A Timer is still pending even after the widget tree was disposed.
'package:flutter_test/src/binding.dart':
Failed assertion: line 1056 pos 7: '_currentFakeAsync.nonPeriodicTimerCount == 0'

Hi @mihai9112 πŸ‘‹
Thanks for opening an issue!

I’ll take a closer look shortly but at first glance your expectLater should come before the β€œact” because you can potentially miss states. Also, it seems like you’re writing widget tests to test a bloc which is not recommended. Blocs should be unit tested and when writing widget tests the blocs should be mocked.

Let me know if that helps and I’ll take a closer look at the test shortly πŸ‘

Thank you for you quick reply. I will act on your recommendations. The reason why I'm widget testing is to check if the SnackBar is showning. The only way to wait for it to show, was to listen if all the states have been emitted successfully. I will try and mock the bloc.

No problem! In that case I would use whenListen to mock the bloc states and then expect that the SnackBar is shown.

Let me know if that helps πŸ‘

Good news and bad news.

The bloc_test package worked in that test where I was testing if the snack bar will be displayed.

Now most of my tests that unit test a specific bloc and not a mocked bloc fail with the following message:

Expected: should do the following in order:
            * emit an event that Uninitialized:<Uninitialized>
            * emit an event that Unauthenticated:<Unauthenticated>
    Actual: Uninitialized:<Uninitialized>
     Which: was not a Stream or a StreamQueue

Is the package bloc_test something that must be used always in the future, even when testing an actual instance of a bloc and not a mocked one?

Nice! Can you share the bloc unit tests that are failing?

These tests used to pass before: https://github.com/mihai9112/reazzon/blob/feature/testing/test/authentication_tests/authentication_bloc_test.dart

Now they are failing with that above mentioned error

@mihai9112 you should change your expectation to

expectLater(_authenticationBloc, emitsInOrder(expectedStates));

because in v1.0.0 blocs extend Stream so there is no longer a state stream property. The state property now refers to the bloc's current state.

Let me know if that helps πŸ‘

That worked, thank you!

One thing that also caught my eye with the new package is that if you want to mock the return of the current state, you now have to initialise the stream first and then mock the return.

Before

when(_authenticationBlocMock.state).thenAnswer((_) => Unauthenticated());

After

whenListen(_authenticationBlocMock, Stream<AuthenticationState>.empty());
when(_authenticationBlocMock.state).thenReturn(Unauthenticated());

It's not a major issue, but it can be unintuitive for beginners in the bloc package. Maybe have extra method in the bloc test that will do that automatically?

Keep up the good work anyway!

@mihai9112 I'm glad I was able to help! Yeah I'm working on improving the testing as we speak πŸ˜„

Thanks so much! πŸ™

Was this page helpful?
0 / 5 - 0 ratings

Related issues

clicksocial picture clicksocial  Β·  3Comments

craiglabenz picture craiglabenz  Β·  3Comments

shawnchan2014 picture shawnchan2014  Β·  3Comments

nhwilly picture nhwilly  Β·  3Comments

hivesey picture hivesey  Β·  3Comments