Skip to content

Commit 3d188a4

Browse files
Merge branch 'main' into 16_create-theme-for-scenes
2 parents a579abf + e35c5d0 commit 3d188a4

27 files changed

+837
-288
lines changed

lib/flutter_test_goldens.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export 'src/flutter/flutter_test_extensions.dart';
22
export 'src/fonts/fonts.dart';
3+
export 'src/fonts/icons.dart';
34
export 'src/goldens/golden_camera.dart';
45
export 'src/goldens/golden_collections.dart';
56
export 'src/goldens/golden_comparisons.dart';

lib/src/fonts/icons.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import 'dart:io';
2+
3+
import 'package:file/file.dart' show FileSystem;
4+
import 'package:file/local.dart' show LocalFileSystem;
5+
import 'package:flutter/services.dart';
6+
import 'package:path/path.dart';
7+
import 'package:platform/platform.dart';
8+
9+
/// Loads the Material icons font into the [FontLoader], which doesn't happen by
10+
/// default in widget tests.
11+
///
12+
/// In widget tests. icons render as empty squares. This is because in widget tests
13+
/// the Material icons font isn't loaded by default. Unfortunately, Flutter doesn't
14+
/// provide a first-class ability to load the font, so this method was copied from
15+
/// Flutter to dig into implementation details and load it.
16+
///
17+
/// After loading this font into a widget test, Material icons should render normally.
18+
Future<void> loadMaterialIconsFont() async {
19+
const FileSystem fs = LocalFileSystem();
20+
const Platform platform = LocalPlatform();
21+
final Directory flutterRoot = fs.directory(platform.environment['FLUTTER_ROOT']);
22+
23+
final File iconFont = flutterRoot.childFile(
24+
fs.path.join(
25+
'bin',
26+
'cache',
27+
'artifacts',
28+
'material_fonts',
29+
'MaterialIcons-Regular.otf',
30+
),
31+
);
32+
33+
final Future<ByteData> bytes = Future<ByteData>.value(iconFont.readAsBytesSync().buffer.asByteData());
34+
35+
await (FontLoader('MaterialIcons')..addFont(bytes)).load();
36+
}
37+
38+
extension on Directory {
39+
File childFile(String basename) => File("$path$separator$basename");
40+
}

lib/src/goldens/golden_camera.dart

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,42 +16,35 @@ class GoldenCamera {
1616
/// along with its [description].
1717
///
1818
/// {@macro golden_image_bounds_default_finder}
19+
///
20+
/// The photo captures a screenshot of the entire widget tree, and then extracts the pixels
21+
/// within the [finder] region. This requires moving more pixel data, but this is done so
22+
/// that the photo captures widgets that sit in the app overlay, such as the mobile drag
23+
/// handles, magnifier, or popover toolbar for a text field.
1924
Future<void> takePhoto(String description, [Finder? finder]) async {
2025
finder = finder ?? find.byType(GoldenImageBounds);
2126

2227
expect(finder, findsOne);
2328

2429
final renderObject = finder.evaluate().first.findRenderObject();
2530
late final Image photo;
26-
if (renderObject!.isRepaintBoundary) {
27-
// The render object that we want to screenshot is already a repaint boundary,
28-
// so we can directly request an image from it.
29-
final repaintBoundary = finder.evaluate().first.renderObject! as RenderRepaintBoundary;
30-
photo = await repaintBoundary.toImage(pixelRatio: 1.0);
31-
} else {
32-
// The render object that we want to screenshot is NOT a repaint boundary, so we need
33-
// to screenshot the entire UI and then extract the region belonging to this widget.
34-
if (renderObject is! RenderBox) {
35-
throw Exception(
36-
"Can't take screenshot because the root of the widget tree isn't a RenderBox. It's a ${renderObject.runtimeType}",
37-
);
38-
}
31+
if (renderObject is! RenderBox) {
32+
throw Exception(
33+
"Can't take screenshot because the root of the widget tree isn't a RenderBox. It's a ${renderObject.runtimeType}",
34+
);
35+
}
3936

40-
// TODO: Try the following approach. It probably doesn't work because we're
41-
// using a TestRecordingPaintingContext with a non-test version of Canvas.
42-
// But maybe it will work out.
43-
final pictureRecorder = PictureRecorder();
44-
final canvas = Canvas(pictureRecorder);
45-
final screenSize = renderObject.size;
37+
final pictureRecorder = PictureRecorder();
38+
final canvas = Canvas(pictureRecorder);
39+
final screenSize = renderObject.size;
4640

47-
final paintingContext = TestRecordingPaintingContext(canvas);
48-
renderObject.paint(paintingContext, Offset.zero);
41+
final paintingContext = TestRecordingPaintingContext(canvas);
42+
renderObject.paint(paintingContext, Offset.zero);
4943

50-
photo = await pictureRecorder.endRecording().toImage(
51-
screenSize.width.round(),
52-
screenSize.height.round(),
53-
);
54-
}
44+
photo = await pictureRecorder.endRecording().toImage(
45+
screenSize.width.round(),
46+
screenSize.height.round(),
47+
);
5548

5649
_photos.add(
5750
GoldenPhoto(description, photo),

0 commit comments

Comments
 (0)