Skip to content

Make color property accessible when testing Container widgets #28753

Closed

Description

@maryx

This is somewhat related to #15042 but it's more about the accessibility of color when testing a Container.

I have a StatelessWidget that in build() does return Container(color: Colors.black);

In my test I do:

testWidgets('Container is black.',
      (WidgetTester tester) async {
    await _setUp();
    final background = tester.firstWidget(find.byType(Container)) as Container;
    expect((background.decoration as BoxDecoration).color, Colors.black);
  });

It would be nice to do:

testWidgets('Container is black.',
      (WidgetTester tester) async {
    await _setUp();
    final background = tester.firstWidget(find.byType(Container)) as Container;
    expect(background.color, Colors.black);
  });

I was hoping that, as setting color is a shorthand, during testing, getting color would also be available (and it would look for the decoration property's color property for me).

Activity

  1. added
    a: tests"flutter test", flutter_test, or one of our tests
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Mar 2, 2019
  2. dnfield commented on Mar 2, 2019

    @dnfield
    Contributor

    I'm not sure either of these is the right thing to do here...

    It would probably be good to jus timplement a custom matcher, like this:

    class ContianerByColorFinder extends MatchFinder {
      ContainerByColorFinder(this.color, { bool skipOffstage = true }) : super(skipOffstage: skipOffstage);
    
      final Color color;
    
      @override
      String get description => 'Container{color: "$color"}';
    
      @override
      bool matches(Element candidate) {
        if (candidate.widget is Container) {
          final Container contianerWidget = candidate.widget;
          if (container.decoration is BoxDecoration) {
            final BoxDecoration decoration = containerWidget.decoration;
            return decoration.color == color;
        }
        return false;
      }
    }

    Which you could then reuse like expect(ContainerByColorFinder(Colors.black), findsOneWidget);

  3. dnfield commented on Mar 2, 2019

    @dnfield
    Contributor

    We could possibly implement something like this in our test package, but It seems a bit specific. @goderbauer or @jonahwilliams might have ideas on this.

  4. added this to the milestone on Mar 2, 2019
  5. jonahwilliams commented on Mar 2, 2019

    @jonahwilliams
    Contributor

    Find the color property on a particular widget is not good enough for testing accessibility. You want the actual color that ends up on screen after it has been transformed and composited and such. This can be different if you have opacity layers or blending for example

  6. dnfield commented on Mar 2, 2019

    @dnfield
    Contributor

    Ahh is this for a11y accessibility or do you just mean you want to access the property?

  7. maryx commented on Apr 24, 2019

    @maryx
    ContributorAuthor

    This is just for extra ease of accessing the property directly, without having to write the code for a custom matcher :)

  8. modified the milestones: , on Jan 7, 2020
  9. maks commented on Feb 18, 2020

    @maks
    Contributor

    @dnfield just to chime to say that I had exactly same requirement for a widget test just now for an "empty" state of my app so found your example code above super helpful - thank you!
    In my case there were no requirements around a11y or transforms/compositing.

    I fixed up a few typos in it and put it in a gist in case others find it useful until if/when it makes it into the flutter widget tests package.

  10. dnfield commented on Feb 18, 2020

    @dnfield
    Contributor

    Great!

    As a heads up, the fix I'm planning for #9672 will likely break whatever someone does to make this work.

    And to be clear - you're usually going to be better off asserting that a widget with a specific key is in the tree rather than finding a widget of a specific color. The way widgets draw colors can change in ways that shouldn't break a test for something like this.

  11. dnfield commented on Feb 25, 2020

    @dnfield
    Contributor

    The best part is once that lands, you'll be able to access color from the color property, as long as you didn't explicitly supply a decoration instead.

  12. maks commented on Feb 25, 2020

    @maks
    Contributor

    thanks @dnfield that does sound good! Though also I've taken your advice to heart and think in my specific case, this time round I probably should just use a key for it.

  13. dnfield commented on Mar 5, 2020

    @dnfield
    Contributor

    After #50979 (which first appeared in v1.15.4), the Container now has a color property, which is set to whatever you passed into color on the ctor. Of course, if you pass decoration, the color property will not be set, but then you can test for decoration since you explicitly wrote it that way. Closing this as resolved - though unfortunately we didn't do this sooner, so existing tests may be broken :)

  14. mhbdev commented on Aug 8, 2020

    @mhbdev
    Contributor

    I'm not sure either of these is the right thing to do here...

    It would probably be good to jus timplement a custom matcher, like this:

    class ContianerByColorFinder extends MatchFinder {
      ContainerByColorFinder(this.color, { bool skipOffstage = true }) : super(skipOffstage: skipOffstage);
    
      final Color color;
    
      @override
      String get description => 'Container{color: "$color"}';
    
      @override
      bool matches(Element candidate) {
        if (candidate.widget is Container) {
          final Container contianerWidget = candidate.widget;
          if (container.decoration is BoxDecoration) {
            final BoxDecoration decoration = containerWidget.decoration;
            return decoration.color == color;
        }
        return false;
      }
    }

    Which you could then reuse like expect(ContainerByColorFinder(Colors.black), findsOneWidget);

    I think this is more complete than yours.

    class ContainerByColorFinder extends MatchFinder {
      ContainerByColorFinder(this.color, {bool skipOffstage = true})
          : super(skipOffstage: skipOffstage);
    
      final Color color;
    
      @override
      String get description => 'Container{color: "$color"}';
    
      @override
      bool matches(Element candidate) {
        if (candidate.widget is Container) {
          final Container containerWidget = candidate.widget;
          return containerWidget.decoration is BoxDecoration
              ? (containerWidget.decoration as BoxDecoration).color == color
              : containerWidget.color == color;
        }
        return false;
      }
    }

    What if we have not defined a decoration for our Container widget?

  15. dnfield commented on Aug 9, 2020

    @dnfield
    Contributor

    @mhbdev when this big was created, container did not have a color property - it was only available through the decoration.

    Either way, I'm not sure a matcher is good here. If your test really cares about what color a container is, shouldn't it also care about whether that color is via a ColoredBox or a Box decoration or some sort?

  16. github-actions commented on Aug 17, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  17. locked as resolved and limited conversation to collaborators on Aug 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: tests"flutter test", flutter_test, or one of our testsframeworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions