Can't find widget by key even if it is in the tree

Viewed 1125

What are the possible reasons why a widget isn't found by key in a test, even if it's in the widget tree?

So in my app, I have some categories of websites and each category has a + button so users can add their own. Now, I want to test that the page opens correctly when the + button is pressed. If I just do:

await tester.tap(find.byIcon(Icons.add));

The test fails because it finds too many widgets and doesn't know which one to tap. So I figured I'd give keys to my + buttons by wrapping them in a container like this:

Container(
    key: ValueKey('add_website_' + category.toLowerCase()),
    child: AddWebsiteButton(),  // the tappable widget that contains an Icon(Icons.add)
)

Now in my test, I call:

expect(find.byKey(ValueKey('add_website_learning')), findsOneWidget);

And, lo and behold, it fails:

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown running a test:
  Expected: exactly one matching node in the widget tree
  Actual: _KeyFinder:<zero widgets with key [<'add_website_learning'>] (ignoring offstage widgets)>
   Which: means none were found but one was expected

If I call debugDumpApp() just before the call above, I can see that the Container with that key is actually in the widget tree:

...
└KeyedSubtree-[Key <[<add_website_learning>]>]
  └AutomaticKeepAlive(state: _AutomaticKeepAliveState#470b4(handles: no notifications ever received))
    └KeepAlive(keepAlive: false)
      └NotificationListener<KeepAliveNotification>
        └IndexedSemantics(index: 4, renderObject: RenderIndexedSemantics#02bbd relayoutBoundary=up3 NEEDS-PAINT)
          └RepaintBoundary(renderObject: RenderRepaintBoundary#8170e relayoutBoundary=up4 NEEDS-PAINT)
            └Container-[<add_website_learning>]
              └Tooltip("Add website", dependencies: [_LocalizationsScope-[GlobalKey#55b7a], _InheritedTheme, TickerMode-[<CrossFadeState.showSecond>]], state: _TooltipState#87315(ticker inactive))
                └GestureDetector(startBehavior: start)
...

I tried making sure it's in view by calling ensureVisible, but that also fails saying it can't find the widget.

What am I doing wrong?

0 Answers
Related