如何在 Flutter 小部件测试中停用或忽略布局溢出消息?

How to deactivate or ignore layout overflow messages in Flutter widget tests?

使用 Ahem 字体 测试 运行,字体太大,有时会溢出,破坏测试。有些测试无论如何都不关心溢出,所以应该有办法停用它们。

我有很多测试 运行 在模拟器中正常,但在测试中中断。

我们被迫防止现实中永远不会溢出的小部件溢出,或者为测试提供字体而不是Ahem,只是为了不溢出测试。测试溢出错误是没有意义的,除非你正在做 "overflow error tests".

如何关闭这些错误,或者如何让测试忽略它们?

您不能专门禁用溢出。但还有一些选择:

  • 将字体更改为 "real" 字体。您的测试不必使用 A​​hem 字体。缺少文档,这是添加此功能的问题:https://github.com/flutter/flutter/issues/17700
  • 更改虚拟屏幕大小。参见
  • FlutterError.onError设置为null

根据 @RémiRousselet 的回答,我开发了一个解决方案。

FlutterError.onError = _onError_ignoreOverflowErrors;

Function _onError_ignoreOverflowErrors = (
  FlutterErrorDetails details, {
  bool forceReport = false,
}) {
  assert(details != null);
  assert(details.exception != null);
  // ---

  bool ifIsOverflowError = false;

  // Detect overflow error.
  var exception = details.exception;
  if (exception is FlutterError)
    ifIsOverflowError = !exception.diagnostics
        .any((e) => e.value.toString().startsWith("A RenderFlex overflowed by"));

  // Ignore if is overflow error.
  if (ifIsOverflowError)
    print('Overflow error.');

  // Throw others errors.
  else
    FlutterError.dumpErrorToConsole(details, forceReport: forceReport);
};

这个函数只忽略溢出异常。

如果您的问题纯粹是由 Ahem 字体 有点太大引起的,您可以尝试使用可访问性 textScaleFactor 缩小所有文本,方法是将 WidgetUnderTest 包装在 MediaQuery 中像这样:

MediaQuery(
  // Shrink the text avoid overflow caused by large Ahem font.
  data: MediaQueryData(textScaleFactor: 0.5),
  child: WidgetUnderTest(),
);

这应该比在小部件测试中加载不同的字体要快得多,并且不会因弄乱 FlutterError.onError 而引入丢失错误的风险。但是,如果您的小部件不支持 textScaleFactor,或者溢出是由其他原因引起的,这将无济于事。

请注意,这可能隐藏了一个实际问题。最好的解决方案是修复或重新设计 UI,这样即使使用大字体的 testScaleFactor: 1.5 也不会溢出,因此将字体设置为最大设置的用户将能够使用您的应用程序。

略微改进了 Eduardo 的回答:修复了检测测试,并针对非溢出错误抛出实际异常,以便小部件测试实际上会中断。

Function onError_ignoreOverflowErrors = (
  FlutterErrorDetails details, {
  bool forceReport = false,
}) {
  assert(details != null);
  assert(details.exception != null);

  var isOverflowError = false;

  // Detect overflow error.
  var exception = details.exception;
  if (exception is FlutterError) {
    isOverflowError = exception.diagnostics.any((e) => e.value.toString().contains("A RenderFlex overflowed by"));
  }

  // Ignore if is overflow error: only report to the console, but do not throw exception as it will
  // cause widget tests to fail.
  if (isOverflowError) {
    FlutterError.dumpErrorToConsole(details, forceReport: forceReport);
  } else {
    FlutterError.dumpErrorToConsole(details, forceReport: forceReport);
    throw (exception);
  }
};

如果文本小部件出现溢出,请使用属性 softWrap: false,像这样

Text(
           'text here',
            softWrap: false,
)

感谢大佬分享,效果不错!

任何想在测试中使用它的人:

testWidgets('your test name', (tester) async {
      disableOverflowErrors();
 });

void disableOverflowErrors() {
  //TODO MyScreen throws overflow error. Will be investigate in a different ticket.
  FlutterError.onError = (FlutterErrorDetails details) {
    final exception = details.exception;
    final isOverflowError = exception is FlutterError &&
        !exception.diagnostics.any(
            (e) => e.value.toString().startsWith("A RenderFlex overflowed by"));

    if (isOverflowError) {
      print(details);
    } else {
      FlutterError.presentError(details);
    }
  };
}