How can I test a Timer inside a Bloc, using blocTest
?
I’m using the bloc library, with freezed to build the state and event objects (might not matter here, but who knows).
So let’s say I have something like this in my bloc class:
@override
Stream<MyState> mapEventToState(
MyEvent event,
) {
return event.when(
start: (value) async* {
yield state.copyWith(/* add state data */);
},
getStream: _myStream(),
);
}
Stream<MyState> _myStream() async* {
MyResult? result;
try {
final repo = await _repoProvider();
result = await repo.fetchResult();
} on Exception catch (e) {
_logger.e(e);
/* do some stuff irrelevant to the example */
}
Timer(const Duration(minutes: 1), () {
add(const MyEvent.getStream());
});
yield state.copyWith(
/* fill state object with data*/
);
}
So if my bloc receives a getStream event, the _myStream() function is called to handle the emitting. This function starts a timer, to submit another getStream event after 1 minute. How can I test this in a unit test without having to wait for a minute (I’m using bloc library’s bloc_test to write blocTest functions for my blocs. This comes with a wait functionality, but it really just waits for the submitted amount of time)? I’ve tried to solve this using FakeAsync, but to no avail - I could always only register the first event. I thought something like this would work, but it doesn’t: blocTest<MyBloc, MyState>( "repo should be called twice", build: () {
return TravelBloc(
mockRepoProvider,
mockTrackerProvider,
);
},
act: (bloc) =>
fakeAsync((async) {
bloc.add(const MyEvent.getStream());
async.elapse(Duration(minutes: 1, seconds: 1));
}),
expect: () => [
/* check state here */
],
verify: (_) {
verify(mockRepo.fetchResult).called(2);
});
Is there any good solution how to test such a construction properly without actual waiting? fakeAsync
seems to be the correct choice but I see myself unable to combine it with blocTest
.