Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit Test a Flutter TextFormField maxlines

Is it possible to write a unit test that verifies that the maxLines property of a TextFormField is set correctly. I can not find a way to access the property:

i create a TextFormField

final field = TextFormField(
    initialValue: "hello",
    key: Key('textformfield'),
    maxLines: 2,
  );

then in the test i get access to the form field with tester.widget

 final formfield =
    await tester.widget<TextFormField>(find.byKey(Key('textformfield')));

but since the maxLines property is passed to the Builder which returns a Textfield, how can i get access to the textfield.

Or is there an completely other ways to verify this?

like image 640
autlunatic Avatar asked Apr 29 '19 21:04

autlunatic


2 Answers

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);
like image 139
autlunatic Avatar answered Oct 04 '22 01:10

autlunatic


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);
like image 45
Daniel Avatar answered Oct 04 '22 00:10

Daniel