Flutter Bloc Widget testing how to find.text under If statement in bloc pattern

Issue

I am trying to Widget test my WelcomeScreen(). WelcomeScreen has a BlocProvider and a BlocBuilder. After I load WelcomeBloc() it checks with an if statement inside the builder to check if the state is WelcomeLoadSuccessState.

How do I find something under the if statement if the statement is true?

My Welcome screen:

Widget build(BuildContext context) {
  return BlocProvider(
   create: (context) => WelcomeBloc(),
   child: BlocBuilder<WelcomeBloc, WelcomeState>(
     builder: (context, state) {
       if (state is WelcomeLoadSuccessState) {
         return Scaffold(
           body: Container(
            child: Column(
              children: [
                Wrap(
                  direction: Axis.vertical,
                  crossAxisAlignment: WrapCrossAlignment.center,
                  children: [
                    Padding(
                      padding: EdgeInsets.all(8),
                      child: ShowUp(
                          delay: _delay + 200,
                          child: Text('Welcome user’,        // <——— I want to find this one
                              )),
                    ),
                  
                  ],
                ),
              ],
            )),
      );
    }

    // return LoadingWidget();
    return Text('Something');       // <——— This one I can find
  },
),
);
}

The test that I have now:

    main() {
  WelcomeBloc welcomeBloc;
  WelcomeService welcomeService;
  final Brand brand = Brand();

  setUp(() {
    setUpMocks();
    welcomeService = localServices<WelcomeService>();
    welcomeBloc = MockWelcomeBloc();
  });

 _createWidget(WidgetTester tester) async {
    when(welcomeService.getBrand(id: '609a88d324a01928242d1ca9')).thenAnswer((realInvocation) => Future.value(brand));
    welcomeBloc.add(WelcomeLoadRequestEvent(id: '609a88d324a01928242d1ca9'));
    when(welcomeBloc.state).thenAnswer((_) => WelcomeLoadSuccessState(brand: brand));

    print(welcomeBloc.state); //Correct State (WelcomeLoadSuccessState)

    await tester.pumpWidget(
        MaterialApp(
          title: 'Flutter Demo',
          home: WelcomeScreen(),
        )
    );

    await tester.pump();
  }

  testWidgets('Welcome Screen Test', (WidgetTester tester) async {
    await _createWidget(tester);
    await tester.pump();

    //expect(find.textContaining('Welcome user'), findsOneWidget); //What I want
    expect(find.text('Something'), findsOneWidget);  //This works
  });

  tearDown(() {
    welcomeBloc?.close();
  });
}

Thank you for helping.

Solution

I solved it:

change:

create: (context) => WelcomeBloc()

to:

create: (context) => WelcomeBloc()..add(WelcomeLoadRequestEvent(id: '609a88d324a01928242d1ca9')),

and my test is now this:

main() {
  WelcomeBloc welcomeBloc;
  WelcomeService welcomeService;
  final Brand brand = Brand();

  setUp(() {
    setUpMocks();
    welcomeService = localServices<WelcomeService>();
    welcomeBloc = MockWelcomeBloc();
  });

  _createWidget(WidgetTester tester) async {
    await tester.pumpWidget(MaterialApp(
      title: 'Flutter Demo',
      home: WelcomeScreen(),
    ));

   await tester.pump(Duration(seconds: 10));
  }

  testWidgets('Welcome Screen Test', (WidgetTester tester) async {
    when(welcomeService.getBrand(id: '609a88d324a01928242d1ca9'))
        .thenAnswer((realInvocation) => Future.value(brand));
    whenListen(
        welcomeBloc,
        Stream.fromIterable([
      WelcomeLoadInProgressState(),
      WelcomeLoadSuccessState(brand: brand),
    ]));

    await _createWidget(tester);
    await tester.pump(Duration(seconds: 5));

    expect(find.textContaining('Welcome user'), findsOneWidget);
  });

 tearDown(() {
    welcomeBloc?.close();
    unRegister();
  });
}

Edit to add:

For my other pages it was useful to separate the blocProvider and the blocBuilder. This way I was able to Mock my blocProvider with a MockMyBloc() and then give the screen in the child.

My real widgets:

MyWidgetMakeBlocProviders(
    Widget build(context) {
        return BlocProvider<MyBloc>(
            create: (context) => MyBloc(),
            child: MyScreen(),
        );
    }
)


MyScreen(
    Widget build(context) {
        return BlocBuilder<MyBloc, MyBlocState>(
            builder: (context, state) {...}
        );
    }
)

My test:

testWidgets('', (tester) async {
    whenListen(MockMyBloc, Stream.fromIterable([
        InitState(),
        LoadedState()
    ]));

    await _createWidget(tester);
    await tester.pump();
    
    //expect()
});

_createWidget(tester) async {
    await tester.pumpWidget(
        MaterialApp(
            title: '',
            home: BlocProvider<MockMyBloc>(
                create: (context) => MockMyBloc(),
                child: MyScreen(),
            )
        )
    );

    await tester.pump();
}

Answered By – SilkeNL

Answer Checked By – Senaida (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.