Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default finders from flutter_test don't work with FaIcon #198

Open
bartekpacia opened this issue Feb 7, 2022 · 0 comments
Open

Default finders from flutter_test don't work with FaIcon #198

bartekpacia opened this issue Feb 7, 2022 · 0 comments

Comments

@bartekpacia
Copy link

bartekpacia commented Feb 7, 2022

The problem

Let's say that I have the following Widget:

IconButton(
    iconSize: 20,
    icon: FaIcon(FontAwesomeIcons.eye),
    onPressed: () {/* change PasswordTextField visibility */},
  );

If I want to test that this Widget is visible, I'd normally use

// password_text_field_test.dart

 testWidgets(
      'tapping on password visibility button toggles it',
      (tester) async {
        final eyeFinder = find.widgetWithIcon(IconButton, FontAwesomeIcons.eye);
        expect(eyeFinder, findsOneWidget);
});

But the above will fail:

tapping on password visibility button toggles it
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure was thrown running a test:
Expected: exactly one matching node in the widget tree
  Actual: _AncestorFinder:<zero widgets with type "IconButton" which is an ancestor of icon
"IconData(U+0F06E)">
   Which: means none were found but one was expected

The reason is that FaIcon is not an Icon (i.e FaIcon extends StatelessWidget), so find.widgetWithIcon can't find it.

The solution 1/2

To make find.widgetWithIcon work with FaIcon, we have to create a custom implementation of Flutter's WidgetIconFinder:

class WidgetFaIconFinder extends MatchFinder {
  WidgetFaIconFinder(this.icon, {bool skipOffstage = true})
      : super(skipOffstage: skipOffstage);

  final IconData icon;

  @override
  String get description => 'Font Awesome icon "$icon"';

  @override
  bool matches(Element candidate) {
    final widget = candidate.widget;
    return widget is FaIcon && widget.icon == icon;
  }
}

Then, to make it shorter for use in tests, we can create our own CustomFinders class, basing on Flutter's CommonFinders:

// finders.dart

const customFind = CustomFinders._();

class CustomFinders {
  const CustomFinders._();

  /// Like [CommonFinders.byIcon], but for FontAwesomeIcons.
  Finder byFaIcon(IconData icon, {bool skipOffstage = true}) =>
      WidgetFaIconFinder(icon, skipOffstage: skipOffstage);

  /// Like [CommonFinders.widgetWithIcon], but for FontAwesomeIcons.
  Finder widgetWithFaIcon(
    Type widgetType,
    IconData icon, {
    bool skipOffstage = true,
  }) {
    return find.ancestor(
      of: customFind.byFaIcon(icon),
      matching: find.byType(widgetType),
    );
  }
}

The solution 2/2

Then, we can use our custom finders just like we'd use the default ones

// password_text_field_test.dart

 testWidgets(
      'tapping on password visibility button toggles it',
      (tester) async {
        final eyeFinder = customFind.widgetWithFaIcon(IconButton, FontAwesomeIcons.eye);
        expect(eyeFinder, findsOneWidget);
});

Further steps

I see 2 ways:

  • add custom finders to this package, so users don't have to write their own
  • include information about how to test FaIcon (maybe link to this issue?)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant