Bloc: How to test widgets depending on BlocBuilder state?

Created on 25 Jul 2020  路  2Comments  路  Source: felangel/bloc

Hi Felix, I tried different approaches for testing the widgets depending on BlocBuilder but you gave me another answer like this

class MockAuthBloc extends MockBloc<AuthenticationEvent, AuthenticationState> implements AuthenticationBloc {}

void main() {
MockAuthBloc mockAuthBloc;

setUp(() {
    mockAuthBloc = MockAuthBloc();
  });

testWidgets('formBuilder', (WidgetTester tester) async {
    when(mockAuthBloc.state).thenReturn(AuthenticationAuthenticated());

    await tester.pumpWidget(widgetTester);
    await tester.pumpAndSettle();

    expect(find.byType(MenuNavigatorScreen), findsOneWidget);
  });
}

I also tried with:

when(mockAuthBloc.state).thenAnswer((_) => AuthenticationAuthenticated());
````
and also with:

```dart
whenListen(mockAuthBloc, emitsInOrder(statesExpected));

or

whenListen(mockAuthBloc, Stream.fromIterable(expectedStates));
````
and I always get this error:

![Screen Shot 2020-07-25 at 8 55 39 AM](https://user-images.githubusercontent.com/8518699/88458574-9f18d180-ce54-11ea-85bc-ee2641915a79.png)

This is the code I want to test:

```dart
return MultiBlocProvider(
    providers: [
      BlocProvider<AuthenticationBloc>(
        create: (context) => AuthenticationBloc(
          loginRepository: loginRepository
        )..add(AppStarted()),
      ),
      BlocProvider<LoginFormBloc>(
        create: (context) => LoginFormBloc(
          repository: loginRepository,
          authenticationBloc: context.bloc<AuthenticationBloc>()
        ),
      )
    ],
    child: BlocBuilder<AuthenticationBloc, AuthenticationState>(
      builder: (context, state) {
        if (state is AuthenticationUninitialized) {
          return SplashPage();
        }
        if (state is AuthenticationAuthenticated) {
          return MenuNavigatorScreen();
        }
        if (state is AuthenticationUnauthenticated) {
          return LoginScreen();
        }
        if (state is AuthenticationLoading) {
          return LoadingIndicatorScreen();
        }
      }
    ),
  );

I don't know what I'm doing wrong or if I have to add something else 馃 馃

question

Most helpful comment

Thank you so much for your help!! 馃憤 馃憣

All 2 comments

Hi @data987 馃憢
Thanks for opening an issue!

The code you want to test isn't very testable in its current form because the blocs are both created and consumed within the same widget. I would highly recommend decoupling the creation from the consumption of the blocs:

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider<AuthenticationBloc>(
          create: (context) => AuthenticationBloc(
            loginRepository: loginRepository
          )..add(AppStarted()),
        ),
        BlocProvider<LoginFormBloc>(
          create: (context) => LoginFormBloc(
            repository: loginRepository,
            authenticationBloc: context.bloc<AuthenticationBloc>()
          ),
        )
      ],
      child:AppView();
    );
  }
}
class AppView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<AuthenticationBloc, AuthenticationState>(
      builder: (context, state) {
        if (state is AuthenticationUninitialized) {
          return SplashPage();
        }
        if (state is AuthenticationAuthenticated) {
          return MenuNavigatorScreen();
        }
        if (state is AuthenticationUnauthenticated) {
          return LoginScreen();
        }
        if (state is AuthenticationLoading) {
          return LoadingIndicatorScreen();
        }
      }
    );
  }
}

Then you can use the approach to easily test AppView using a MockBloc like:

class MockAuthBloc extends MockBloc<AuthenticationState> implements AuthenticationBloc {}

void main() {
  AuthBloc mockAuthBloc;

  setUp(() {
    mockAuthBloc = MockAuthBloc();
  });

  testWidgets('renders MenuNavigationScreen when state is Authenticated', (WidgetTester tester) async {
    when(authBloc.state).thenReturn(AuthenticationAuthenticated());
    await tester.pumpWidget(BlocProvider.value(value:authBloc, child: AppView());
    expect(find.byType(MenuNavigatorScreen), findsOneWidget);
  });
}

Hope that helps 馃憤

Thank you so much for your help!! 馃憤 馃憣

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MahdiPishguy picture MahdiPishguy  路  3Comments

wheel1992 picture wheel1992  路  3Comments

nerder picture nerder  路  3Comments

komapeb picture komapeb  路  3Comments

abinvp picture abinvp  路  3Comments