Flutter小部件测试tap - 无法在指定的小部件上进行命中测试

19

在以下警告输出后,我的小部件测试失败:

flutter: 警告:使用查找器“仅一个具有文本“Tab 2”的小部件(忽略非显示小部件):Text(“Tab 2”,softWrap:只在换行字符处换行,溢出:淡出,依赖项:[MediaQuery,DefaultTextStyle])”来调用tap()导出了一个偏移量(Offset(600.0,23.0)),该偏移量不会在指定的小部件上进行测试。 flutter:也许小部件实际上是屏幕外的,或者另一个小部件遮挡了它,或者小部件无法接收指针事件。

点击操作从未执行,因此测试的下一部分失败了。我在测试中加入了一些延迟,并且似乎测试尝试点击正确的小部件-它不是屏幕外,没有被遮挡,并且过去能够接收指针事件-不确定为什么它当前失败了。

这里是一个最小的可再现示例:

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 2,
        child: Scaffold(
          appBar: TabBar(
            labelColor: Color(0xff8391e4),
            tabs: [
              Tab(text: 'Tab 1'),
              Tab(text: 'Tab 2'),
            ],
          ),
          body: TabBarView(
            children: <Widget>[
              Text('Tab 1 Text'),
              Text('Tab 2 Text'),
            ],
          ),
        ),
      ),
    );
  }
}

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('My Test', (WidgetTester tester) async {
    await tester.pumpWidget(MyApp());
    await tester.pumpAndSettle();

    // Warning thrown on this tap - tap never executed
    await tester.tap(find.text('Tab 2'));
    await tester.pumpAndSettle();

    // Test fails here
    expect(find.text('Tab 2 Text'), findsOneWidget);
  });
}

1
我也遇到了同样的问题,你找到解决方案了吗?我也尝试了ensureVisible,但是没有成功。 - Chen
@LeeMordell 有关于这个问题的最新消息吗?你找到解决方案了吗? - Dirk
@Dirk - 我已经有一段时间没有进行测试了,很遗憾没有解决方案。 :( - Lee Mordell
4个回答

12
尝试在“tap()”之前设置“ensureVisible()”:
// Warning thrown on this tap - tap never executed
await tester.ensureVisible(find.text('Tab 2'));
await tester.tap(find.text('Tab 2'));
await tester.pumpAndSettle();

4
谢谢您的建议。ensureVisible 在小部件超出屏幕并且您想要滚动到该位置时非常有用;但是,在我的情况下,该小部件在屏幕上明显可见。 - Lee Mordell
我目前也遇到了@LeeMordell提到的同样问题,但是当我在模拟器上运行测试时,它就像你在评论中提到的那样可见。你解决了这个问题吗? - Emir Bostancı
1
ensureVisible 不是关于在真实模拟器中不可见,而是关于此特定组件在测试模拟器屏幕上可见。因此,它模拟了在模拟器屏幕上滚动,直到相关组件可见。 - William Cunha Cardoso

1
如果将来有人遇到这个问题,请注意。
我曾经遇到过同样的问题,是因为后台还有动画在运行。解决方法是调用await tester.pumpAndSettle();,它将清除所有挂起的动画。
我认为ensureVisible()的一个副作用类似,这就是为什么它有效的原因。

0
在我的情况下,当我有模态屏幕时,这个工作:
await tester.tap(find.byKey(Key('some_key')), warnIfMissed: false);

4
这只是消除了警告,但测试人员仍无法点击您的查找器。 - Pierre Monier

0

我找到了解决我的问题的方法,但它可能不是通用的解决方案。这个测试所针对的应用程序是一个专门的Web应用程序,因此它被设计为在较大的屏幕尺寸上运行。当我在Chrome上运行测试时,它会通过,但在无头模式下运行时会失败。

为了修复这个问题,我在更大的屏幕尺寸上运行测试,现在它可以在无头模式下通过了。 因此,如果你遇到了A call to tap() ... that would not hit test on the specified widget错误,调整屏幕尺寸可能会解决这个问题。

  testWidgets('My test', (WidgetTester tester) async {
      // Here we use physicalSizeTestValue to adjust the test screen size to
      // simulate running on a desktop computer which the app was designed for
      tester.binding.window.physicalSizeTestValue = Size(1080, 1920);
      tester.binding.window.devicePixelRatioTestValue = 1.0;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接