I am trying to test a BLoC that depends on another BLoC via subscription. Now, the subscriptions should be canceled, so I override the close() method of BLoC in which I cancel the subscription and call super. The problem is that in the BLoC tests, no states get emitted. If I remove the close() override, then it works, but linter complains that subscriptions should be canceled.
Here is my BLoC code
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:dartz/dartz.dart';
import 'package:equatable/equatable.dart';
import 'package:injectable/injectable.dart';
import 'package:meta/meta.dart';
import '../../../facade/collections/collections_facade.dart';
import '../../../model/collection.dart';
import '../../../util/error/data_failure.dart';
import '../profile/profile_bloc.dart';
part 'collections_event.dart';
part 'collections_state.dart';
@prod
@lazySingleton
class CollectionsBloc extends Bloc<CollectionsEvent, CollectionsState> {
final CollectionsFacade _collectionsFacade;
final ProfileBloc _profileBloc;
StreamSubscription _profileBlocStreamSubscription;
CollectionsBloc(
{@required CollectionsFacade collectionsFacade,
@required ProfileBloc profileBloc})
: _collectionsFacade = collectionsFacade,
_profileBloc = profileBloc {
_profileBlocStreamSubscription = _profileBloc.listen((ProfileState state) {
if (state is CompleteProfileState) {
this.add(GetCollectionsEvent(username: state.userProfile.username));
}
});
}
@override
Future<void> close() async {
if (_profileBlocStreamSubscription != null)
_profileBlocStreamSubscription.cancel();
super.close();
}
@override
CollectionsState get initialState => InitialCollectionsState();
@override
Stream<CollectionsState> mapEventToState(
CollectionsEvent event,
) async* {
if (event is GetCollectionsEvent) {
yield LoadingCollectionsState();
final Either<DataFailure, List<Collection>> collectionsOrFailure =
await _collectionsFacade.getCollectionsForUser(event.username);
yield collectionsOrFailure.fold<CollectionsState>(
(_) => ErrorCollectionsState(),
(List<Collection> collections) =>
LoadedCollectionsState(collections: collections),
);
}
}
}
@test
@lazySingleton
@RegisterAs(CollectionsBloc)
class MockedCollectionsBloc extends MockBloc<CollectionsEvent, CollectionsState>
implements CollectionsBloc {}
And this is my test:
import 'package:bloc_test/bloc_test.dart';
import 'package:collectio/app/bloc/collections/collections_bloc.dart';
import 'package:collectio/app/bloc/profile/profile_bloc.dart';
import 'package:collectio/facade/collections/collections_facade.dart';
import 'package:collectio/facade/collections/firebase/firebase_collections_facade.dart';
import 'package:collectio/model/collection.dart';
import 'package:collectio/util/error/data_failure.dart';
import 'package:collectio/util/injection/injection.dart';
import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import 'package:mockito/mockito.dart';
void main() {
configureInjection(Environment.test);
final String username = 'username';
final List<Collection> collections = [
Collection.fromJson(
{
'id': 'id',
'owner': 'owner',
'title': 'title',
'subtitle': 'subtitle',
'thumbnail': 'thumbnail',
'description': 'description',
},
),
];
final MockedFirebaseCollectionsFacade mockedFirebaseCollectionsFacade =
getIt<CollectionsFacade>();
final MockedProfileBloc mockedProfileBloc = getIt<ProfileBloc>();
blocTest(
'should emit Loading and Loaded on success',
build: () async {
when(mockedFirebaseCollectionsFacade.getCollectionsForUser(username))
.thenAnswer((_) async => Right(collections));
return CollectionsBloc(
collectionsFacade: mockedFirebaseCollectionsFacade,
profileBloc: mockedProfileBloc,
);
},
act: (CollectionsBloc bloc) async =>
bloc.add(GetCollectionsEvent(username: username)),
expect: [
LoadingCollectionsState(),
LoadedCollectionsState(collections: collections),
],
);
}
The actual emited states are []. @felangel Do you have any idea what could go wrong and how to fix the issue? It looks like the BLoC is getting closed before executing the test ...
This is the whole code in case you need it https://github.com/stelynx/collectio/tree/SLCOL-22
Hi @campovski 馃憢
Thanks for opening an issue!
This is because you weren't returning super.close() from the bloc close override so the events that were being processed weren't being awaited before executing the expectation.
I opened a pull request with the fix 馃憤
Thank you very much! 馃槏 I guess I found an old example of how things are done.
Most helpful comment
Thank you very much! 馃槏 I guess I found an old example of how things are done.