Flutter testing find.byValueKey() for item in drop down menu doesn't work

2,502

I recreated your case. Instead of using key property on DropdownMenuItem, you need to use it inside it's child, ie, in Text widget. That way, since the flutter driver will look for text to be selected when dropdown menu is open, the key property will come into play when menu items are displayed and then easier to click on whatever option we pass in the test. It worked well. Updated working code below:

final List<DropdownMenuItem<String>> _dropDownMenuSigns = menuSigns
      .map<DropdownMenuItem<String>>((String value) => DropdownMenuItem<String>(
  //  key: new ValueKey('sign_$value'),
    value: value,
    child: new Text(value, key: Key('sign_$value'),),  // use key here on text
  ))
      .toList();

driver test:

class AstroSignValidation extends GivenWithWorld<FlutterWorld> {
  @override
  Future<void> executeStep() async {
    await FlutterDriverUtils.getText(world.driver, find.text('Choose a sign'));
    await FlutterDriverUtils.tap(world.driver, find.byValueKey('sign_list')); // open drop down menu is ok
    await FlutterDriverUtils.tap(world.driver, find.byValueKey('sign_virgo')); // selects sign properly
    print('selected sign');
  }
  RegExp get pattern => RegExp(r"I expect the user enters sign");
}

And test passes :

enter image description here

Note: I directly used Given statement in feature file and accordingly extended GivenWithWorld class in my test. You'll need to use it per your needs.

Hope this answers your question.

Share:
2,502
Author by

Michael Bouhier

Updated on December 14, 2022

Comments

  • Michael Bouhier 3 minutes

    My test doesn't found the item in drop down menu with a value key. It's works with getText() and the value.

    I create a dynamic function to fill every items with a value, a child with Text(value) and a key with Key('sign_$value_item');

    This is my full form in the app:

      static const menuSigns = <String>[
        'aries',
        'taurus',
        'gemini',
        'cancer',
        'leo',
        'virgo',
        'libra',
        'scorpio',
        'sagittarius',
        'capricorn',
        'aquarius',
        'pisces'
      ];
      final List<DropdownMenuItem<String>> _dropDownMenuSigns = menuSigns
          .map<DropdownMenuItem<String>>((String value) => DropdownMenuItem<String>(
                key: new ValueKey('sign_$value_item'), // i even try with new Key('sign_$value')
                value: value,
                child: new Text(value),
              ))
          .toList();
    @override
      Widget build(BuildContext context) {
        return Form(
          key: _formKey,
          child: Container(
            margin: EdgeInsets.fromLTRB(_hPad, 16.0, _hPad, 0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Center(
                  child: Container(
                    padding: EdgeInsets.fromLTRB(0, 0, 0, 16.0),
                    width: CustomTheme.customFormSize.width(context),
                    child: DropdownButton(
                      key: Key('sign_list'),
                      isExpanded: true,
                      value: _sign,
                      style: CustomTheme.style.dropDownMenu(context),
                      hint: Text('Choose a sign'),
                      icon: Icon(Icons.arrow_drop_down_circle),
                      onChanged: ((newValue) {
                        setState(() {
                          _sign = newValue;
                        });
                      }),
                      items: _dropDownMenuSigns,
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    

    And strange things, the test works with the Key if the length of value is very long, for exemple more 10 characters.

    This is my test:

    import 'package:flutter_driver/flutter_driver.dart';
    import 'package:flutter_gherkin/flutter_gherkin.dart';
    import 'package:gherkin/gherkin.dart';
    class AstroSignValidation extends AndWithWorld<FlutterWorld> {
      @override
      Future<void> executeStep() async {
        await FlutterDriverUtils.getText(world.driver, find.text('AstroDay'));
        await FlutterDriverUtils.tap(world.driver, find.byValueKey('sign_list')); // open drop down menu is ok
        await FlutterDriverUtils.tap(world.driver, find.byValueKey('sign_cancer_item')); // here test not passed
      }
      RegExp get pattern => RegExp(r"I expect the user enters sign");
    }
    

    Edit: This is my feature file :

    Feature: Get Astro day
      User should be able to get successfully his astro after cliking astro button.
      Scenario: User get astro in successfully
        Given I expect the "user" 1 sign
        And I expect the user enters day
        When user hits Show your astro button
        Then user should land on result screen