Describe the bug
The tests are failed with the following error when I'm testing widget with MultiBlocListener on v1.0.0.
Exception has occurred.
TestFailure (Expected: exactly one matching node in the widget tree
Actual: ?:<zero widgets with key [<'EMAIL_LOGIN_EMAIL_TEXT_FIELD'>] (ignoring offstage widgets)>
Which: means none were found but one was expected
)
To Reproduce
Steps to reproduce the behavior:
builder: (BuildContext context, LoginState loginState)Expected behavior
In version 0.19.0 it goes to the builder: (BuildContext context, LoginState loginState) and build the widget.
Test
setUp(() {
authBloc = MockAuthenticationBloc();
loginBloc = MockLoginBloc();
testWidget = wrapWidget(Scaffold(
body: BlocProvider.value(
value: loginBloc,
child: EmailLoginForm(authBloc: authBloc, loginBloc: loginBloc),
)
), null);
});
testWidgets('form is initially displayed', (WidgetTester tester) async {
when(loginBloc.state).thenAnswer((_) => LoginState.loading());
await tester.pumpWidget(testWidget);
await tester.pumpAndSettle(); // to wait for localization
expect(find.byKey(EMAIL_LOGIN_EMAIL_TEXT_FIELD), findsOneWidget);
expect(find.byKey(EMAIL_LOGIN_PASSWORD_TEXT_FIELD), findsOneWidget);
expect(find.byKey(EMAIL_LOGIN_SUBMIT_BUTTON), findsOneWidget);
});
Widget
@override
Widget build(BuildContext context) {
return MultiBlocListener(
listeners: [
BlocListener<LoginBloc, LoginState>(
bloc: _loginBloc,
listener: (context, state) {
if (_loginSucceeded(state)) {
widget.tracker.trackEvent(event: Events.LOGIN_SUCCESS);
_authBloc.onLogin(token: state.token);
}
},
),
BlocListener<AuthenticationBloc, AuthenticationState>(
bloc: _authBloc,
listener: (context, state) {
if (state.isAuthenticated) {
Navigator.pushReplacementNamed(context, Constants.ROUTE_HOME);
}
},
),
],
child: BlocBuilder<LoginBloc, LoginState>(
bloc: _loginBloc,
builder: (BuildContext context, LoginState loginState) {
if (_loginFailed(loginState)) {
buttonEnabled = true;
widget.tracker.trackEvent(event: Events.LOGIN_FAILED);
onWidgetDidBuild(() {
final String errorMessage = _isNetworkError(loginState.error)
? AppLocalizations.of(context).loginNetworkErrorMessage
: AppLocalizations.of(context).loginErrorMessage;
_displayLoginErrorDialog(errorMessage);
});
}
return _form(loginState);
},
),
);
}
*Logs *
There is no errors in flutter analyze and flutter doctor
Hi @Den-Ree 馃憢
Thanks for opening an issue!
The problem is in 1.0.0 you no longer access the state stream via bloc.state because the bloc itself extends Stream.
You need to change when(loginBloc.state).thenAnswer((_) => LoginState.loading());
to
whenListen(loginBloc, Stream<LoginState>.fromIterable([LoginState.loading()));
whenListen comes from the bloc_test package.
Hope that helps and sorry for any inconvenience!
@felangel thanks for the answer. But the problem is still happens. When I debug the test then code never go to inside. If I correctly understand that it should be called during building the widget or not?
builder: (BuildContext context, LoginState loginState) {
....
}
If you want to just mock the current state of the bloc you can do:
when(bloc.state).thenReturn(LoginState.loading());
Use whenListen if you want to mock the bloc stream. In your test you will likely need to do something like:
// Set the bloc's stream to empty
whenListen(loginBloc, Stream<LoginState>.empty());
// Set the bloc's state to Loading
when(loginBloc.state).thenReturn(LoginState.loading());
Hope that helps 馃憤
@felangel thanks a lot for the help, it works as you suggested. But I noticed the following thing, which is not clear for me.
During running the test, the first time state are null in
builder: (BuildContext context, LoginState loginState)
and only for the second time I get the needed state.
@Den-Ree can you please provide a link to a sample app which illustrates the issue you're seeing? If you're initially seeing a null state that means that the bloc's state has not been properly stubbed. Are you using when(loginBloc.state).thenReturn(LoginState.loading());?
Most helpful comment
If you want to just mock the current state of the bloc you can do:
Use
whenListenif you want to mock the bloc stream. In your test you will likely need to do something like:Hope that helps 馃憤