Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter Test: Testing if a checkbox is checked on build

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

like image 410
Tom Ryan Avatar asked Sep 12 '25 01:09

Tom Ryan


2 Answers

I found the solution.

Edit: Update after @brightknight08's comment

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

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

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

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

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

like image 143
lsaudon Avatar answered Sep 13 '25 16:09

lsaudon


another method:

expect(tester.widget<Checkbox>(find.byKey("your-key")).value, false);

or if you are using CheckboxListTile try the following

expect(tester.widget<CheckboxListTile>(find.byKey("your-key")).value, false);

like image 39
Gülsen Keskin Avatar answered Sep 13 '25 14:09

Gülsen Keskin