Flutter Test: Testing if a checkbox is checked on build

2,174

I found the solution.

final checkboxFinder = find.byKey(Key('aKey'));

var checkbox = tester.firstWidget(checkboxFinder) as Checkbox;
expect(checkbox.value, false);

await tester.tap(checkboxFinder);
await tester.pump();

checkbox = tester.firstWidget(checkboxFinder) as Checkbox;
expect(checkbox.value, true);

I think it works the same way with find.byType(Checkbox).

Share:
2,174
Tom Ryan
Author by

Tom Ryan

Updated on December 26, 2022

Comments

  • Tom Ryan
    Tom Ryan over 1 year

    I have a dynamic form system that builds widgets based on a json. One of the components that can be parsed is a Checkbox and a default value is passed to determine whether or not it is checked/unchecked initially. I'm writing a unit test for this and am running into trouble with semantics.

    My test begins with checking the widget has been built (the following test is successful)

    //create form
    await tester.pumpWidget(buildTestableWidget(testWidget));
    
    //setup Finder
    Finder widgetFinder = find.widgetWithText(FormCheckbox, "test checkbox");
    
    //test for widget
    expect(widgetFinder, findsOneWidget);
    

    The FormCheckbox class is as follows

    class FormCheckbox extends StatefulWidget {
      final forms.Checkbox component;
    
      FormCheckbox(this.component) : super(key: Key("${component.propertyKey().getId()}"));
    
      _FormCheckboxState createState() => _FormCheckboxState(component);
    }
    
    class _FormCheckboxState extends State<FormCheckbox> {
      _FormCheckboxState(this._component) {
        this.boxValue = _component.isDefaultSelected();
      }
    
      final forms.Checkbox _component;
      bool boxValue;
    
      @override
      Widget build(BuildContext context) {
        return Padding(
            padding: const EdgeInsets.only(left: 16, right: 16, top: 6, bottom: 6),
            child: ListTile(
              leading: Material(
                child: Checkbox(
                    value: boxValue,
                    onChanged: (bool newValue) {
                      setState(() {
                        boxValue = newValue;
                      });
                })),
              title: Text("${_component.getLabel()}"),
            ));
      }
    
      String validator(String value) {
        //TODO: Implement validator
        throw UnimplementedError();
      }
    
    }
    

    Which despite everything else, has a Checkbox component as a child which defaults to a boolean I can set (which I can confirm is definitely working properly).

    I would expect, from looking at flutter's own tests for checkboxes here that I can use getSemantics and expect it to equal a matchedSemantics within which isChecked = true as shown here

    //test default value
    expect(
      tester.getSemantics(find.byType(Checkbox)),
      matchesSemantics(
        isChecked: true,
        hasEnabledState: true,
        isEnabled: true,
    ));
    

    However the isChecked state is remaining as false, even after a tap with await tester.tap(find.byKey(Key("1")));

    The error message given is

    Expected: has semantics with actions: [] with flags: [
                SemanticsFlag:SemanticsFlag.isChecked,
                SemanticsFlag:SemanticsFlag.hasEnabledState,
                SemanticsFlag:SemanticsFlag.isEnabled
              ]
    Actual: SemanticsNode:<SemanticsNode#5(Rect.fromLTRB(0.0, 0.0, 800.0, 68.0), tags:
    [RenderViewport.twoPane], flags: [hasEnabledState, isEnabled], label: "test checkbox",
    textDirection: ltr)>
       Which: flags were: [hasEnabledState, isEnabled]
    

    What am I missing here? Why is a created Checkbox object with value: true not giving a semantics value of isChecked = true

  • Jarin Rocks
    Jarin Rocks about 2 years
    I t works. But why we have to again create checkbox widget after pumping. //checkbox = tester.firstWidget(checkboxFinder) as Checkbox;
  • lsaudon
    lsaudon about 2 years
    This is to see that the "checkbox" has gone from false to true. @JarinRocks