Flutter bloc emmitInOrder doesn't emit initial state, but it does
Asked Answered
U

2

9

So I'm trying to unit test a bloc

My test is simple

test("When loading patients, bloc should emmit [Loading], [OwnersLoaded]", (){
      //arrange
      var owners = [Owner(id: "TestId")];
      when (mockPatientsRepository.getOwnersForCurrentPractice()).thenAnswer((_)=>Future.value(owners));
      final List<PatientsState> expected = [patientsBloc.initialState, Loading(), OwnersLoaded(owners)];

      //assert later
      expectLater(patientsBloc, emitsInOrder(expected));

      //act
      useCase.getPatients();
    }); 

Owners does override equals and hash

My error message

Expected: should do the following in order:
          • emit an event that <Instance of 'InitialPatientsState'>
          • emit an event that <Instance of 'Loading'>
          • emit an event that <Instance of 'OwnersLoaded'>
  Actual: <Instance of 'PatientsBloc'>
   Which: emitted • Instance of 'InitialPatientsState'
                  • Instance of 'Loading'
                  • Instance of 'OwnersLoaded'
            which didn't emit an event that <Instance of 'InitialPatientsState'> 

So it says it emitted the initial state, but didn't?

Uptotheminute answered 24/10, 2019 at 22:12 Comment(3)
can you put the code of your block as well?Saguache
How did you fix this error ?Jasminjasmina
@Jasminjasmina What happens is if events are "equal" then they're not re-emitted. I've started using freezer to get value equality in the blocUptotheminute
U
0

We had the same error. It was fixed by using equatable.

Undergarment answered 25/4, 2021 at 11:5 Comment(1)
Welcome to SO. Please provide relevant details in your answer. One line answers are not recommended. stackoverflow.com/help/how-to-answerMolybdenite
K
0

I hope this issue is still relevant.

Actually, there's no need to write streams & yield statements from scratch, as per the newer versions of bloc. But as we are setting the Later calles in testing, we will need to parse a bloc-stream while expecting the result. So, the solution to your code is to use bloc.stream instead of bloc.state which converts the bloc to a bloc stream & yeilds the output in order. Do remember that the stream does not contain the initial/EmptyState(), but all other events are handle in order & hence emitted the same. Refer to the below code snippet for the proper implementat,

This is the bloc file that contains the bloc logic as per the latest versions.

///<inputs an event, outputs the state> => <NumberTriviaEvent, 
NumberTriviaState>
class NumberTriviaBloc extends Bloc<NumberTriviaEvent, NumberTriviaState> {
  final GetConcreteNumberTrivia concreteNumberTrivia;
  final GetRandomNumberTrivia randomNumberTrivia;
  final InputConverter inputConverter;

  NumberTriviaBloc(
      {required this.concreteNumberTrivia,
      required this.randomNumberTrivia,
      required this.inputConverter}) : super(EmptyState()) {
    on<NumberTriviaEvent>((event, emit) async{
        if(event is GetTriviaForConcreteNumber){
          final input = inputConverter.stringToUnsignedInteger(event.numberString);
          input.fold((lFailure){
             emit( const ErrorState(errorMessage: INVALID_INPUT_FAILURE_MESSAGE));
          }, (rSuccess) {
             emit(const LoadedState(numberTrivia: NumberTrivia(text: 'sample test', number: 1)));
          });
        }
    });
  }
}

This is the test file that tests the output over the block that is written above.

    test('should emit [Error] when theres an invalid input', () {
      //  arrange
      when(inputConverter.stringToUnsignedInteger('abc'))
          .thenAnswer((realInvocation) => Left(InvalidInputFailure()));

      //  assert Later
      /// As we will be checking if the emit contains the expected result, we will use expectLater() method in test
      /// which puts the particular test on hold until the data is been emitted(upper limit 30 seconds) & then applies the checks
      expectLater(
        bloc.stream,
        emitsInOrder([
          const ErrorState(errorMessage: INVALID_INPUT_FAILURE_MESSAGE)
          ]));

      //  act
      bloc.add(const GetTriviaForConcreteNumber(numberString: 'abc'));
    });
  });

Learning Source: Reso Coders
Kultur answered 11/3, 2023 at 20:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.