Flutter Web浏览器端Golden测试中自定义字体加载失败,loadAppFonts()无限挂起
Flutter Web浏览器端Golden测试中自定义字体加载失败,loadAppFonts()无限挂起
最近帮朋友排查Flutter Web Golden测试的问题时,正好碰到了一模一样的情况——自定义字体加载失败,不管是用golden_toolkit的loadAppFonts()还是手动调用FontLoader,都会无限挂起,导致测试只能用系统字体,和生产环境的渲染效果差老远了。下面我把问题细节、复现步骤以及可行的解决办法整理出来,希望能帮到你。
问题核心
在标记了@TestOn('browser')的Golden测试中,自定义字体无法正常加载,不管是工具库提供的加载方法还是手动实现,都会出现挂起卡死的情况,最终测试只能 fallback 到系统字体,完全失去了视觉回归测试的准确性。
预期应该达到的效果
- 配置在
pubspec.yaml里的自定义字体,能在浏览器端Golden测试中正常加载 - 测试的渲染效果和生产环境完全一致,保证视觉回归测试的有效性
实际遇到的问题
loadAppFonts()在浏览器测试中直接无限挂起,根本没法继续执行后续测试- 手动调用
FontLoader('Inter').load()也会出现同样的挂起问题 - 测试被迫使用系统字体,和生产环境的字体渲染效果有明显差异
复现步骤
要复现这个问题,你只需要按下面的步骤操作就行:
- 在项目的
pubspec.yaml里配置自定义字体:
fonts: - family: Inter fonts: - asset: assets/fonts/inter/Inter-VariableFont_slnt,wght.ttf
- 写一个带
@TestOn('browser')标记的Golden测试:
@TestOn('browser') testGoldens('test with custom fonts', (tester) async { await tester.pumpWidgetBuilder(MyWidget()); await screenMatchesGolden(tester, 'test'); });
- 在
flutter_test_config.dart里加入loadAppFonts()初始化:
Future<void> testExecutable(FutureOr<void> Function() testMain) async { await loadAppFonts(); // 这里在浏览器测试中会直接挂起 await testMain(); }
- 执行测试命令:
flutter test --platform chrome --update-goldens
我试过的无效方案
当时为了解决这个问题,我试了好几种办法,但都没奏效:
- 手动用FontLoader加载:直接调用
FontLoader('Inter').load(),结果还是挂起 - 加超时机制:给加载方法加
.timeout(),但超时后还是会 fallback 到系统字体,问题没解决 - 用dart:html注入CSS:尝试直接给浏览器注入字体样式,但遇到了编译问题
- 换VM环境测试:VM环境下字体加载正常,但没法测试Web端特有的行为,根本不满足需求
环境信息
- Flutter版本:3.x.x(稳定通道)
- Dart版本:3.x.x
- golden_toolkit版本:^0.15.0
可行的解决办法
后来摸索出几个可行的方案,你可以根据自己的情况选择:
1. 给Web端字体加载加超时处理
在flutter_test_config.dart里针对Web环境做特殊处理,给字体加载加个超时,避免无限挂起,同时打印日志提示:
import 'dart:io' show Platform; import 'package:golden_toolkit/golden_toolkit.dart'; Future<void> testExecutable(FutureOr<void> Function() testMain) async { if (Platform.isWeb) { // Web环境下给字体加载设置5秒超时 try { await loadAppFonts().timeout(const Duration(seconds: 5)); } catch (_) { debugPrint('字体加载超时,将使用 fallback 字体继续测试'); } } else { await loadAppFonts(); } await testMain(); }
2. 直接用浏览器API预加载字体
绕开Flutter的字体加载机制,直接用dart:html让浏览器提前加载字体,这样测试时就能正常使用自定义字体了:
import 'dart:html' as html; import 'package:golden_toolkit/golden_toolkit.dart'; Future<void> testExecutable(FutureOr<void> Function() testMain) async { if (html.window != null) { // 创建字体样式标签并注入到页面 final style = html.StyleElement() ..text = ''' @font-face { font-family: 'Inter'; src: url('assets/fonts/inter/Inter-VariableFont_slnt,wght.ttf') format('truetype'); } '''; html.document.head?.append(style); // 等待浏览器加载完成字体 await html.document.fonts?.load('12px Inter'); } else { await loadAppFonts(); } await testMain(); }
注意:这种方法要确保测试时能正确访问到字体文件,记得检查pubspec.yaml里的资源配置是否正确,保证字体文件能被测试环境访问到。
3. 升级golden_toolkit到最新版本
有时候这类问题是工具库的已知bug,你可以尝试把golden_toolkit升级到最新版本,看看官方是否已经修复了Web端字体加载的问题:
dependencies: golden_toolkit: ^0.16.0 # 替换成当前最新版本
内容来源于stack exchange
相关产品推荐
相关产品推荐

