Scenario
I have a CustomButton
, which when tapped should trigger a LoginEvent
. I want to widget test my UI and LoginBloc
. The following is my widget test code:
Code
testWidgets('Should show LoaderRow when state is loading', (tester) async {
// Arrange
when(() => mockLoginBloc.state).thenReturn(LoginLoading());
// Act
await tester.pumpWidget(const MainApp());
// await tester.pumpWidget(initialWidget);
await tester.pumpWidget(_makeTestableWidget(const LoginPage()));
await tester.enterText(
find.byKey(const ValueKey('EmailAddress')), '[email protected]');
await tester.enterText(find.byKey(const ValueKey('Password')), 'Test@123');
expect(find.byKey(const ValueKey('Login')), findsOneWidget);
await tester.tap(find.byKey(const ValueKey('Login')));
await tester.pumpAndSettle();
// await tester.pump();
// for (int i = 0; i < 5; i++) {
// await tester.pump(const Duration(seconds: 1));
// }
// Assert
verify(() => mockLoginBloc.add(LoginAttempt(loginRequest: tLoginRequest)))
.called(1);
expect(find.byType(LoaderRow), findsOneWidget);
});
Here, LoaderRow
is a SpinKitFadingCircle
taken from https://pub.dev/packages/flutter_spinkit
Problem
When I run the test above I encounter the following error which fails my test:
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ The following assertion was thrown running a test: pumpAndSettle timed out
Upon searching for solutions to this error on SO, I tried replacing pumpAndSettle
with pump
or even placing pump
inside a loop, but that yielded me with yet another error:
The following TestFailure was thrown running a test:
No matching calls.
(If you called verify(...).called(0);
, please instead use verifyNever(...);
.)
My Bloc, State and Event related code are as follows:
LoginBloc
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final GetLoginDetails _getLoginDetails;
LoginBloc(this._getLoginDetails) : super(LoginInitial()) {
on<LoginAttempt>((event, emit) async {
final loginRequest = event.loginRequest;
emit(LoginLoading());
final result = await _getLoginDetails.execute(loginRequest);
result.fold(
(failure) {
emit(LoginError(failure.message));
},
(data) {
emit(LoginSuccess(data));
},
);
}, transformer: debounce(const Duration(milliseconds: 250)));
}
EventTransformer<T> debounce<T>(Duration duration) {
return (events, mapper) => events.debounceTime(duration).flatMap(mapper);
}
}
LoginEvent
abstract class LoginEvent extends Equatable {
const LoginEvent();
@override
List<Object> get props => [];
}
class LoginAttempt extends LoginEvent {
final Map<String, dynamic> loginRequest;
const LoginAttempt({
required this.loginRequest,
});
@override
List<Object> get props => [loginRequest];
}
LoginState
abstract class LoginState extends Equatable {
const LoginState();
@override
List<Object> get props => [];
}
final class LoginInitial extends LoginState {}
final class LoginLoading extends LoginState {}
final class LoginSuccess extends LoginState {
final Login result;
const LoginSuccess(this.result);
@override
List<Object> get props => [result];
}
final class LoginError extends LoginState {
final String message;
const LoginError(this.message);
@override
List<Object> get props => [message];
}
Request
I would like to know what is wrong in my code that causes the test to fail and what changes I need to make to it to make the test pass.