11

In my app I create a button using FlatButton.icon (Flutter docs). Now I'm trying to find the button during testing.

I've tried

find.byType(MaterialButton); // -> zero widgets
find.byType(FlatButton); // -> zero widget

The strange thing is that I can find the text for the button

find.text('my button text');

and I can also find the icon for the button

find.byType('Icon');

I'm not sure what I should be searching for to find the button.

0p3r4t0r
  • 623
  • 5
  • 13

5 Answers5

5

Alright, so I wasn't able to find the FlatButton itself, but it's easy to find the icon with . . .

find.byIcon(Icons.yourIcon);

See the relevant docs for more info: flutter_test find.byIcon

0p3r4t0r
  • 623
  • 5
  • 13
5

Even though the question might seem quite old, I'd like to expand on the topic since none of the answers actually shows how to find the FlatButton itself. The problem is that FlatButton.icon is not a constructor, but a factory creating a different object _FlatButtonWithIcon extending FlatButton, which is apparently only available inside its file. In the meantime, find.byType only looks for widgets by an identical type - it doesn't work for derived types.

So, to return the object itself: find.ancestor(of: find.byIcon(Icons.your_icon), matching: find.byWidgetPredicate((widget) => widget is FlatButton)). This approach let us get the button object and therefore test its properties (e.g., onPressed) or child widgets (e.g., label) by calling find.descendant.

Oleg Safarov
  • 2,325
  • 14
  • 19
  • 1
    @YazeedAlKhalaf, sure! You get the finder by the approach I mentioned above, then use it to get the label widget. Assuming that it's a Text one: `final textFinder = find.descendant(of: flatBtnFinder, matching: find.byType(Text))`. Later you can retrieve its label from the widget itself by WidgetTester: `final btnLabel = tester.widget(textFinder).data`. – Oleg Safarov Dec 22 '20 at 13:38
0

The next code (I faced this issue and had some help from the flutter discord server ...) did not work. Here's the right test code. The correction is located on the last line.

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('TextButton.icon test', (WidgetTester tester) async {
    const IconData iconData = Icons.add;

    await tester.pumpWidget(
      MaterialApp(
        home: Center(
          child: TextButton.icon(
            onPressed: () { },
            icon: const Icon(iconData),
            label: const Text('text button'),
          ),
        ),
      ),
    );
    final dynamic textButtonWithIconWidget = tester.widget(find.byWidgetPredicate((Widget widget) => '${widget.runtimeType}' == '_TextButtonWithIconChild'));
    expect(textButtonWithIconWidget.icon.icon, iconData); // MODIFIED CODE. NOW WORKS !
  });
}
Jean-Pierre Schnyder
  • 1,572
  • 1
  • 15
  • 24
0

Oleg's answer worked for me, then I applied some generics to get the following function for my use case. I was trying to find an ElevatedButton.icon() generated button, but this approach may work with other icon button as well.

Finder widgetWithText<T>(String text) {
    return find.ancestor(
        of: find.text(text),
        matching: find.byWidgetPredicate((widget) => widget is T));
}

The test code looks like:

final textFinder = widgetWithText<ElevatedButton>('Like');
JonathanN
  • 672
  • 7
  • 17
-1

I faced this issue and had some help from the flutter discord server, and here I am sharing the solution: NOTE: you have to use dynamic for the returned widget because the class is private.

void main() {
  testWidgets('TextButton.icon test', (WidgetTester tester) async {
    const IconData iconData = Icons.add;

    await tester.pumpWidget(
      MaterialApp(
        home: Center(
          child: TextButton.icon(
            onPressed: () { },
            icon: const Icon(iconData),
            label: const Text('text button'),
          ),
        ),
      ),
    );
    final dynamic textButtonWithIconWidget = tester.widget(find.byWidgetPredicate((Widget widget) => '${widget.runtimeType}' == '_TextButtonWithIconChild'));
    expect(textButtonWithIconWidget.icon, const Icon(iconData));
  });
}
Yazeed AlKhalaf
  • 313
  • 4
  • 14