Font namespacing in self-tests¶
Handled automatically since 1.1.1
loadAppFonts() now reads your package name from pubspec.yaml and also
registers each bundled text family under its packages/<pkg>/<family>
alias — so a package that references its own fonts with the prefix renders
correctly in its own test suite with no extra setup. Just call
loadAppFonts(). The rest of this page explains the underlying mismatch and
the manual workaround needed on older versions.
loadAppFonts() reads the family names Flutter wrote into FontManifest.json — but a package that references its own fonts with the packages/<name>/ prefix asks for a family name that the manifest does not contain when the package tests itself. This page explains why that mismatch happens, how to recognize it, and how to fix it.
The symptom¶
You call loadAppFonts() in flutter_test_config.dart, yet your goldens still render text as Ahem squares (or in the wrong typeface) — only inside the package's own test suite. The same widgets render correctly when the package is consumed by an app. Icons may also be missing.
The tell: text geometry is wrong even though loadAppFonts() ran without error and the font files are clearly bundled.
Why it happens¶
Flutter namespaces a package's fonts with a packages/<package_name>/ prefix only when that package is a dependency of another app. A package referencing its own bundled font must therefore hardcode the prefixed family name so it resolves in consumer apps:
// lib/src/tokens.dart — referenced by the package's widgets AND its public API
static const String fontDisplay = 'packages/ui_kit/BrandSans';
But when the package runs its own flutter test, it is the root project, not a dependency. The generated manifest lists the fonts with their bare family names and un-prefixed asset paths:
// build/unit_test_assets/FontManifest.json (package testing itself)
[
{ "family": "BrandSans",
"fonts": [ { "asset": "fonts/BrandSans-Medium.ttf", "weight": 500 } ] }
]
loadAppFonts() registers exactly what the manifest says — the family BrandSans. Its derivedFontFamily() helper only re-applies the packages/<pkg>/ prefix when the asset path starts with packages/.... Here the asset path is fonts/BrandSans-Medium.ttf, so no prefix is added.
The result is a name mismatch:
| Side | Family name |
|---|---|
loadAppFonts() registers |
BrandSans |
| Widget / theme requests | packages/ui_kit/BrandSans |
Flutter finds no match for the requested name and falls back to the font's fallback chain — Ahem (or Roboto) in a test — so glyphs and metrics are wrong.
This is specific to a package testing itself
Inside a consumer app's test suite the manifest asset paths are
packages/ui_kit/fonts/..., so derivedFontFamily() produces
packages/ui_kit/BrandSans and everything matches. The break only occurs
when the package that owns the prefixed font name is the root project
under test.
How to confirm it¶
-
Inspect the generated manifest and the family name your widgets request:
find build .dart_tool -name FontManifest.json -exec cat {} \; grep -rn "packages/<your_package>/" lib/If the manifest shows a bare family (
"family": "BrandSans") while your code requestspackages/<pkg>/BrandSans, that is the mismatch. -
The names won't line up: manifest family ≠ requested family.
The fix¶
On 1.1.1+ there is nothing to do — just call loadAppFonts(). It reads the
root package name from pubspec.yaml and registers every bundled text family
under both its bare name and its packages/<pkg>/<family> alias, so whichever
name your widgets request resolves. Icon families (MaterialIcons, etc.) are not
aliased; pass loadAppFonts(iconFonts: false) if you want the text fix without
also loading Material icons.
// test/flutter_test_config.dart — 1.1.1+
import 'dart:async';
import 'package:golden_matrix/golden_matrix.dart';
Future<void> testExecutable(FutureOr<void> Function() testMain) async {
await loadAppFonts();
return testMain();
}
Manual workaround (older versions)¶
If you're pinned to an older golden_matrix, register the fonts under the
same prefixed names your widgets request by loading the files directly
instead of relying on the manifest-derived names, in flutter_test_config.dart:
// test/flutter_test_config.dart
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
/// Load the package's own fonts under their `packages/<pkg>/` family names —
/// the names the widgets/theme actually request — by reading the TTFs from
/// disk. `loadAppFonts()` cannot do this in a self-test because the manifest
/// lists the families un-prefixed.
Future<void> _loadOwnFonts() async {
const families = <String, List<String>>{
'packages/ui_kit/BrandSans': [
'fonts/BrandSans-Medium.ttf',
'fonts/BrandSans-SemiBold.ttf',
'fonts/BrandSans-Bold.ttf',
],
'packages/ui_kit/BrandSerif': ['fonts/BrandSerif-Regular.ttf'],
'packages/ui_kit/BrandMono': ['fonts/BrandMono-Regular.ttf'],
};
for (final entry in families.entries) {
final loader = FontLoader(entry.key);
for (final path in entry.value) {
final bytes = File(path).readAsBytesSync();
loader.addFont(Future.value(ByteData.view(bytes.buffer)));
}
await loader.load();
}
}
Future<void> testExecutable(FutureOr<void> Function() testMain) async {
await _loadOwnFonts();
return testMain();
}
Keep loadAppFonts() for icons and Roboto
The custom loader only covers your prefixed text families. loadAppFonts()
additionally pulls MaterialIcons and Roboto from the Flutter SDK
cache, so Material icons render as real glyphs instead of empty boxes.
Call both — they register disjoint families and don't conflict:
Alternatives¶
- Drop the prefix in the package's own code. If your widgets referenced the
bare family (
'BrandSans'),loadAppFonts()would match in the self-test — but then the fonts would not resolve in consumer apps, where the prefix is required. Not recommended for a published UI package. - Move goldens into an
example/app that depends on the package. There the manifest is correctly prefixed andloadAppFonts()alone works — at the cost of testing through an extra app target.
See also¶
- Advanced — the
## Font loadingsection andloadAppFonts()options - Migration guide
- CI integration
- Home