In provided example todos_bloc.dart has code like that:
@override
Stream<TodosState> mapEventToState(TodosEvent event) async* {
if (event is LoadTodos) {
yield* _mapLoadTodosToState();
} else if (event is TodosUpdated) {
yield* _mapTodosUpdateToState(event);
}
}
Stream<TodosState> _mapLoadTodosToState() async* {
_todosSubscription?.cancel();
_todosSubscription = _todosRepository.todos().listen(
(todos) => add(TodosUpdated(todos)),
);
}
Stream<TodosState> _mapTodosUpdateToState(TodosUpdated event) async* {
yield TodosLoaded(event.todos);
}
So I would expect to write a test like this:
group('LoadTodos', () {
blocTest(
'should emit [TodosLoaded] state',
build: () async => TodosBloc(todosRepository: mockTodosRepository),
act: (bloc) => bloc.add(LoadTodos()),
expect: [
isA<TodosLoaded>(),
],
);
});
but it doesn't pass. No events are emitted even if I mock the repository.todos() response. I would like to catch the state from the repository stream. Can you help me with it?
HI @adamsmaka 馃憢
Thanks for opening an issue!
Are you able to share a link to the failing test? I'm happy to open a pull request with suggestions, thanks 馃憤
Hi @felangel , thanks for quick reply.
Of course, here is a failing test:
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import '../lib/blocs/todos/todos_bloc.dart';
import '../lib/blocs/todos/todos_event.dart';
import '../lib/blocs/todos/todos_state.dart';
import '../todos_repository/lib/todos_repository.dart';
class MockTodosRepository extends Mock implements TodosRepository {}
main() {
MockTodosRepository mockTodosRepository;
setUp(() {
mockTodosRepository = MockTodosRepository();
});
TodosBloc getSut() {
when(mockTodosRepository.todos())
.thenAnswer((_) => Stream<List<Todo>>.value([]));
return TodosBloc(todosRepository: mockTodosRepository);
}
group('Load', () {
blocTest(
'should emit [TodosLoading, TodosLoaded] states',
build: () async => getSut(),
act: (bloc) => bloc.add(LoadTodos()),
expect: [
isA<TodosLoaded>(),
],
);
});
}
@adamsmaka no problem! Can you try to provide a wait with Duration.zero?
blocTest(
'...',
build: () async => getSut(),
act: (bloc) => bloc.add(LoadTodos()),
wait: Duration.zero,
expect: [isA<TodosLoaded>()],
)
Let me know if that works. I believe this should be resolved in the upcoming release and you can test it in v7.0.0-dev.2 of bloc_test.
wait: Duration.zero helped! thank you.
Also tried bloc_test 7.0.0-dev.2 and it also works. I like that it doesn't require async on build anymore. But is it intentional that it doesn't recognise initial state anymore?
@adamsmaka that's great to hear! Yeah it's intentional because blocs no longer emit the current state upon subscription 馃憤
Ok so problem solved. Thank you so much, appreciate your work. Bloc library is awesome.
No problem! Regarding the initial state I recommend writing a separate test for it like:
test('initial state is...', () {
expect(MyBloc().state, InitialState());
});
Thanks so much for the positive feedback, I really appreciate it 馃檹 馃挋
Most helpful comment
Ok so problem solved. Thank you so much, appreciate your work. Bloc library is awesome.