How to unit Test a Flutter TextFormField maxlines How to unit Test a Flutter TextFormField maxlines flutter flutter

How to unit Test a Flutter TextFormField maxlines


I don't know if this is a good solution but as i set the value of my TextFormField i can find the EditableText widget directly.of this widget i can find test the property maxLines.

final EditableText formfield =   tester.widget<EditableText>(find.text('testvalue'));expect(formfield.maxLines, 2);


The reason you can't see properties such as maxLines or maxLength is because they belong to the TextField class.

Take a look at the documentation of the TextFormField constructor in the source file:

  /// Creates a [FormField] that contains a [TextField].  ///  /// When a [controller] is specified, [initialValue] must be null (the  /// default). If [controller] is null, then a [TextEditingController]  /// will be constructed automatically and its `text` will be initialized  /// to [initialValue] or the empty string.  ///  /// For documentation about the various parameters, see the [TextField] class  /// and [new TextField], the constructor.

Unfortunately you can't retrieve the TextField object from a TextFormField, you'll have to find the TextField object through a finder instead.

Let's assume you have a form with 2 fields - first name and last name. What you need to do is find all widgets of type TextField, add them to a list and then you can loop through each element of the list and run your test. Here's an example:

  testWidgets('Form fields have the correct maximum length and number of lines',      (WidgetTester tester) async {    await tester.pumpWidget(MaterialApp(      home: Scaffold(        body: Form(          child: Column(            children: <Widget>[              TextFormField(                key: Key('first_name'),                decoration: InputDecoration(hintText: 'First name'),                maxLines: 1,                maxLength: 50,                obscureText: true,              ),              TextFormField(                key: Key('last_name'),                decoration: InputDecoration(hintText: 'Last name'),                maxLines: 1,                maxLength: 25,              ),            ],          ),        ),      ),    ));    List<TextField> formFields = List<TextField>();    find.byType(TextField).evaluate().toList().forEach((element) {      formFields.add(element.widget);    });    formFields.forEach((element) {      expect(element.maxLines, 1);      switch (element.decoration.hintText) {        case 'First name':          expect(element.maxLength, 50);          break;        case 'Last name':          expect(element.maxLength, 25);          break;      }    });  });

If you only one field, you could do this instead:

TextField textField = find.byType(TextField).evaluate().first.widget as TextField;expect(textField.maxLines, 1);expect(textField.maxLength, 50);


You can test it with an Integration test. The logic would be to type more text into the TextFormField that the one it's expected.
So we can verify the TextFormField is only allowing 2 character, as follow.
e.g. component:

import 'package:flutter/material.dart';import 'package:flutter/rendering.dart';import 'package:font_awesome_flutter/font_awesome_flutter.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {  // This widget is the root of your application.  @override  Widget build(BuildContext context) {    return MaterialApp(      title: 'Flutter Demo',      theme: ThemeData(        primarySwatch: Colors.blue,      ),      home: Scaffold(        body: SingleChildScrollView(          child: MyLoginPage(title: 'Flutter Demo Home Page'),        ),      ),    );  }}class MyLoginPage extends StatefulWidget {  MyLoginPage({Key key, this.title}) : super(key: key);  final String title;  @override  _MyLoginPageState createState() => _MyLoginPageState();}class _MyLoginPageState extends State<MyLoginPage> {  String _email;  String _password;  TextStyle style = TextStyle(fontSize: 25.0);  @override  Widget build(BuildContext context) {    final emailField = TextField(      key: Key('textformfield'),      obscureText: false,      maxLength: 2,      style: style,      decoration: InputDecoration(          contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),          prefixIcon: Icon(FontAwesomeIcons.solidEnvelope),          hintText: "Email",          focusedBorder: OutlineInputBorder(              borderSide: BorderSide(color: Colors.red[300], width: 32.0),              borderRadius: BorderRadius.circular(97.0))),      onChanged: (value) {        setState(() {          _email = value;        });      },    );    final passwordField = TextField(      obscureText: true,      style: style,      decoration: InputDecoration(          contentPadding: EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),          prefixIcon: Icon(FontAwesomeIcons.key),          hintText: "Password",          focusedBorder: OutlineInputBorder(              borderSide: BorderSide(color: Colors.red[300], width: 32.0),              borderRadius: BorderRadius.circular(25.0))),      onChanged: (value) {        setState(() {          _password = value;        });      },    );    return Center(      child: Column(        children: <Widget>[          Container(            color: Colors.yellow[300],            height: 300.0,          ),          emailField,          passwordField,        ],      ),    );  }}

The test:

import 'package:flutter/material.dart';import 'package:flutter_test/flutter_test.dart';import 'package:flutter_textfields_up/main.dart';void main() {  testWidgets('Email should be only 2 characters', (WidgetTester tester) async {    // Build our app and trigger a frame.    await tester.pumpWidget(MyApp());    var txtForm = find.byKey(Key('textformfield'));    await tester.enterText(txtForm, '123');    expect(find.text('123'), findsNothing); // 3 characters shouldn't be allowed    expect(find.text('12'), findsOneWidget); // 2 character are valid.  });}

Please observe I'm sending 3 character, and the TextFormField should only allow 2.
Hope this help.