I'm trying to run an integration test in my app. The screen is my login screen which leads to a signup flow and logged in to Home Screen. I'm using flutter integration test from the framework it self.
I've tried to run an integration test on the login screen but I get this error,
The following TestFailure object was thrown running a test: Expected: exactly one matching node in the widget tree Actual: _WidgetPredicateFinder:<zero widgets with widget matching predicate (Closure: (Widget) => bool) (ignoring offstage widgets)> Which: means none were found but one was expected
My Login screen looks like this
class LoginScreen extends StatefulWidget {
static String tag = loginScreenRoute;
const LoginScreen({Key? key}) : super(key: key);
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final _userLoginFormKey = GlobalKey<FormState>();
String? _userName = "";
String? _password = "";
bool _invisiblePass = false;
TextEditingController usernameController = TextEditingController();
TextEditingController passwordController = TextEditingController();
bool hasInterNetConnection = false;
late StreamSubscription _connectionChangeStream;
@override
initState() {
//Create instance
ConnectionUtil connectionStatus = ConnectionUtil.getInstance();
//Initialize
connectionStatus.initialize();
//Listen for connection change
_connectionChangeStream =
connectionStatus.connectionChange.listen(connectionChanged);
super.initState();
}
@override
void dispose() {
_connectionChangeStream.cancel();
super.dispose();
}
void connectionChanged(dynamic hasConnection) {
setState(() {
hasInterNetConnection = hasConnection;
//print(isOffline);
});
if (!hasInterNetConnection) {
offlineBar(context);
}
}
final loading = Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
CircularProgressIndicator(
color: lightWTextColor,
),
Text(" Login in ... Please wait")
],
);
void _showPassword() {
setState(() {
_invisiblePass = !_invisiblePass;
});
}
@override
Widget build(BuildContext context) {
//// user email ////
TextFormField userName() => TextFormField(
key: const Key('login username input'),
autofocus: false,
keyboardType: TextInputType.emailAddress,
controller: usernameController,
validator: validateEmail,
onSaved: (value) => _userName = value!.trim(),
textInputAction: TextInputAction.next,
style: AppTheme.body1WTextStyle,
decoration: buildInputDecoration(
'Enter Email',
Icons.email,
lightWTextColor.withOpacity(0.4),
),
// focusNode: _usernameFocusNode,
// onFieldSubmitted: (String val) {
// final focusNode = FocusNode();
// focusNode.unfocus();
// },
);
//// user password ////
TextFormField userPassword() => TextFormField(
key: const Key('login password input'),
obscureText: !_invisiblePass,
keyboardType: TextInputType.visiblePassword,
controller: passwordController,
validator: validatePassword,
onSaved: (value) => _password = value!.trim(),
textInputAction: TextInputAction.done,
style: AppTheme.body1WTextStyle,
decoration: buildInputDecoration(
'Enter Password',
Icons.vpn_lock,
lightWTextColor.withOpacity(0.4),
).copyWith(
suffixIcon: GestureDetector(
onTap: () {
_showPassword();
},
child: Icon(
_invisiblePass ? Icons.visibility : Icons.visibility_off,
color: Colors.black54,
),
),
),
);
final forgotLabel = Padding(
padding: const EdgeInsets.all(0.0),
child: Container(
alignment: Alignment.topRight,
child: TextButton(
child: const Text(
"Forgot password?",
style: AppTheme.body1WTextStyle,
),
onPressed: () {
Navigator.of(context).pushNamed(passwordResetScreenRoute);
},
),
),
);
final signupLabel = Padding(
padding: const EdgeInsets.all(10.0),
child: TextButton(
child: const Text(
"Sign Up for an Account",
style: AppTheme.subTitleWTextStyle,
),
onPressed: () {
Navigator.of(context).pushNamed(
userEditScreenRoute,
arguments: eProfile.addProfile,
);
},
),
);
final loginButton = ButtonWidget(
key: const Key('login button'),
text: 'LOG IN',
btnColor: accentColor,
borderColor: accentColor,
textColor: lightWTextColor,
onPressed: () {
Navigator.of(context).pushReplacementNamed(homeScreenRoute);
// _submit();
},
);
final loginForm = Form(
key: _userLoginFormKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
userName(),
const SizedBox(
height: 10.0,
),
userPassword(),
forgotLabel,
const SizedBox(
height: 10.0,
),
loginButton,
const SizedBox(
height: 10.0,
),
signupLabel,
],
),
);
final mainBody = InkWell(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: wBackground(),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/_logo.png',
height: 200.0,
),
Expanded(
flex: 1,
child: loginForm, //Text('this text here'),
),
],
),
),
),
),
);
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
child: mainBody,
),
),
);
}
}
and when I try to navigate to Home Screen on tap of login button, the test fails.
my test case is like this
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
//
// start.main();
login.main();
}
//
void main() {
doLoginTest();
}
void doLoginTest() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets("Login in test run", (WidgetTester tester) async {
//
pawfect.main();
await tester.pumpAndSettle(const Duration(seconds: 3));
//test here
final Finder login =
find.byWidgetPredicate((widget) => widget is LoginScreen);
expect(login, findsOneWidget);
await tester.pumpAndSettle(const Duration(seconds: 1));
//
var emailInput = find.byKey(const Key('login username input'));
await tester.tap(emailInput);
await tester.enterText(emailInput, "test@m.com");
await tester.pumpAndSettle(const Duration(seconds: 1));
//
var passwordInput = find.byKey(const Key('login password input'));
await tester.tap(passwordInput);
await tester.enterText(passwordInput, "password");
await tester.pumpAndSettle(const Duration(seconds: 1));
//
var loginButton = find.byKey(const Key('login button'));
await tester.tap(loginButton, warnIfMissed: false);
await tester.pumpAndSettle(const Duration(seconds: 3));
//
// expect(version, findsOneWidget);
// final Finder home = find.byWidget(const HomeScreen());
expect(find.byWidgetPredicate((widget) => widget is HomeScreen),
findsOneWidget);
// await tester.pumpAndSettle(const Duration(seconds: 1));
var version = find.byWidgetPredicate(
(widget) => widget is Text && widget.data!.contains("Version: 2.0"));
expect(version, findsOneWidget);
await tester.pumpAndSettle(const Duration(seconds: 3));
});
}
what am I doing wrong here? I tried to look for something helpful over the internet and in the docs but I couldn't get my hands dirty enough. Will someone please help me to write a fine Integration test move in with screen to another screen. Thank you so much in advance.