printEntry function
Future<List<PrintManifestEntry> >
printEntry(
- WidgetTester tester, {
- required PrintEntry entry,
- required PrintSession session,
- DeviceFrame? deviceOverride,
- PrintConfig? config,
Renders a single PrintEntry using a PrintSession.
For pages (PrintType.page): the widget is passed directly to
session.appWrapper as a full-screen child.
For widgets (PrintType.widget): the widget is wrapped in a Scaffold with Center for proper layout.
If the entry has PrintEntry.states, each state is rendered as a
separate screenshot. The file naming depends on PrintSession.stateOutputMode:
prefix → <name>/<state>_<device>.png, suffix → <name>/<device>_<state>.png,
folder → <name>/<state>/<device>.png.
Implementation
Future<List<PrintManifestEntry>> printEntry(
WidgetTester tester, {
required PrintEntry entry,
required PrintSession session,
DeviceFrame? deviceOverride,
PrintConfig? config,
}) async {
final effectiveConfig = config ?? const PrintConfig();
final devices = entry.devices ??
[deviceOverride ?? session.defaultDevice ?? DeviceFrame.iPhone15Pro];
final manifestEntries = <PrintManifestEntry>[];
// Build the list of (stateName, widget) pairs to render.
final renderTargets = <(String?, Widget)>[];
if (entry.states != null && entry.states!.isNotEmpty) {
for (final s in entry.states!) {
renderTargets.add((s.name, s.widget));
}
} else {
renderTargets.add((null, entry.widget));
}
for (final (stateName, targetWidget) in renderTargets) {
for (final device in devices) {
final deviceConfig = effectiveConfig.copyWith(
size: entry.size ?? device.size,
pixelRatio: device.pixelRatio,
);
// Configure surface size.
await tester.binding.setSurfaceSize(deviceConfig.size);
tester.view.physicalSize = deviceConfig.size * deviceConfig.pixelRatio;
tester.view.devicePixelRatio = deviceConfig.pixelRatio;
// Build widget tree based on print type.
final Widget child;
if (entry.type == PrintType.page) {
child = session.appWrapper(targetWidget);
} else {
child = session.appWrapper(
Scaffold(
body: Center(
child: Padding(
padding: deviceConfig.padding,
child: targetWidget,
),
),
),
);
}
await tester.pumpWidget(child);
await tester.pumpAndSettle();
await _precacheAllImages(tester);
final String fileName;
if (session.flat) {
if (stateName != null) {
switch (session.stateOutputMode) {
case StateOutputMode.prefix:
fileName =
'${session.outputDir}/${entry.name}_${stateName}_${device.name}.png';
case StateOutputMode.suffix:
fileName =
'${session.outputDir}/${entry.name}_${device.name}_$stateName.png';
case StateOutputMode.folder:
fileName =
'${session.outputDir}/${entry.name}_${stateName}_${device.name}.png';
}
} else {
fileName = '${session.outputDir}/${entry.name}_${device.name}.png';
}
} else {
if (stateName != null) {
switch (session.stateOutputMode) {
case StateOutputMode.prefix:
fileName =
'${session.outputDir}/${entry.name}/${stateName}_${device.name}.png';
case StateOutputMode.suffix:
fileName =
'${session.outputDir}/${entry.name}/${device.name}_$stateName.png';
case StateOutputMode.folder:
fileName =
'${session.outputDir}/${entry.name}/$stateName/${device.name}.png';
}
} else {
fileName = '${session.outputDir}/${entry.name}/${device.name}.png';
}
}
await expectLater(find.byType(MaterialApp), matchesGoldenFile(fileName));
// Extract named regions if the entry defines crops. Runs after the
// full-page PNG is written by matchesGoldenFile.
if (entry.crops != null || entry.cropsFrom != null) {
await processEntryCrops(
goldenPath: fileName,
inlineCrops: entry.crops,
cropsFromJson: entry.cropsFrom,
pixelRatio: deviceConfig.pixelRatio,
);
}
manifestEntries.add(
PrintManifestEntry(
name: entry.name,
type: entry.type == PrintType.page ? 'page' : 'widget',
file: fileName,
device: device.name,
state: stateName,
width: deviceConfig.size.width,
height: deviceConfig.size.height,
widthPx: (deviceConfig.size.width * deviceConfig.pixelRatio).round(),
heightPx:
(deviceConfig.size.height * deviceConfig.pixelRatio).round(),
),
);
// Reset surface size.
await tester.binding.setSurfaceSize(null);
}
}
return manifestEntries;
}