Skip to content

Commit a4999c2

Browse files
[Docs] - Added page about loading images in golden tests
1 parent 4467a03 commit a4999c2

File tree

7 files changed

+137
-0
lines changed

7 files changed

+137
-0
lines changed
File renamed without changes.
File renamed without changes.
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
---
2+
title: Display Images
3+
navOrder: 35
4+
---
5+
Displaying images in a Flutter golden test is an especially annoying and tedious
6+
process. The root cause is that Flutter's test system manually controls the passage
7+
of time, which is important for inspecting UI frames, but prevents all real
8+
asynchronous behavior from executing, including loading images.
9+
10+
There are three non-standard image loading scenarios in a golden test:
11+
* Loading from the network
12+
* Loading from a file
13+
* Loading from memory
14+
15+
## Display an Image from the Network
16+
Apps often load images from the network. To load and display these images in a
17+
golden test, you need to tell Flutter to allow network requests, and you need to
18+
explicitly pre-cache the network image.
19+
20+
By default, Flutter forcibly prevents HTTP calls through an `HttpClient`. Fortunately,
21+
there's a mechanism to tell Flutter to mind its own business.
22+
23+
The following code is a minimal sample for loading images from the network within
24+
a test.
25+
26+
```dart
27+
void testWidgets("load a file image", (tester) async {
28+
// Normally, Flutter forcibly prevents HTTP calls. Turn that off by null'ing out
29+
// the HttpOverrides.
30+
final testOverride = HttpOverrides.current;
31+
HttpOverrides.global = null;
32+
addTearDown(() => HttpOverrides.global = testOverride);
33+
34+
const imageUrl = "https://upload.wikimedia.org/wikipedia/commons/b/b3/Vista_Satelital_de_Nohyaxch%C3%A9_y_Edzn%C3%A1%2C_Campeche.png";
35+
36+
// Load the image from the internet. This must be done in `runAsync` because
37+
// network communication is a real asynchronous behavior.
38+
await tester.runAsync(() async {
39+
await precacheImage(NetworkImage(imageUrl), tester.binding.rootElement!);
40+
});
41+
42+
// Display the image in the widget tree.
43+
await tester.pumpWidget(
44+
MyApp(
45+
// Network images are globally key'd on their URL, so you don't have to
46+
// pass the same `ImageProvider` that you used to load the image.
47+
child: Image.network(imageUrl),
48+
),
49+
);
50+
});
51+
```
52+
53+
The first thing you'll notice in the network image example is that we have to mess
54+
with Flutter's `HttpOverrides`. This is where Flutter's test system installs its
55+
own `HttpClient` that rejects every request. We turn that off, and we also setup
56+
a test teardown method that restores it - we don't want to turn it off for all tests.
57+
58+
The one nice detail about using network images is that the image URL `String` can
59+
be used to refer to that image anywhere. We don't have to pass the `ImageProvider`
60+
into our widget tree, which means this is an approach that might actually work for
61+
real-world apps.
62+
63+
If you use this approach, be mindful that images can disappear from the internet at any
64+
time. Also, network conditions can change at any time. Network images introduce a
65+
source of flakiness that you might need to deal with from time to time.
66+
67+
## Display an Image from File
68+
Though less common than network images, an app might want to load an image from
69+
the local file system. This load path only requires image pre-caching.
70+
71+
The following code is a minimal sample for loading images from a file within a test.
72+
73+
```dart
74+
void testWidgets("load a file image", (tester) async {
75+
await tester.runAsync(() async {
76+
await precacheImage(FileImage(File("path/to/my_image.png")), tester.binding.rootElement!);
77+
});
78+
79+
// Display the image in the widget tree.
80+
await tester.pumpWidget(
81+
MyApp(
82+
// File images are globally key'd on their `File`, so you don't have to
83+
// pass the same `ImageProvider` that you used to load the image.
84+
child: Image.network(imageUrl),
85+
),
86+
);
87+
});
88+
```
89+
90+
Loading images from file is probably the easiest load path to orchestrate in a
91+
golden test. However, it's only useful if your app happens to load images from
92+
the local file system. As a result, this load path is probably only useful for
93+
some desktop apps.
94+
95+
## Display an Image from Memory
96+
In rare situations, you might want to load an image into a widget tree based on
97+
an in-memory representation. This would probably only happen if an image were
98+
generated or altered within a test. However, we cover this load path for completeness.
99+
100+
Using an in-memory image in a test requires the same pre-caching as other loading
101+
methods. This approach also requires that you use the same instance of your `ImageProvider`
102+
both to load the image, as well as to display the image.
103+
104+
The following code is a minimal sample for displaying images from memory within a test.
105+
106+
```dart
107+
void testWidgets("load an in-memory image", (tester) async {
108+
// Load or create your image data.
109+
final imageProvider = MemoryImage(
110+
// We use a File for code brevity, but if you want to load from a File
111+
// then use the File loading path.
112+
File("path/to/my_image.png").readAsBytesSync(),
113+
);
114+
115+
// Use Flutter's `runAsync()` method so that you can run a real
116+
// asynchronous call from a test. Use this opportunity to call
117+
// Flutter's `precacheImage()` method to load your `ImageProvider`.
118+
await tester.runAsync(() async {
119+
await precacheImage(imageProvider, tester.binding.rootElement!);
120+
});
121+
122+
await tester.pumpWidget(
123+
MyApp(
124+
child: Image(
125+
// Use the same `ImageProvider` in your widget tree.
126+
image: imageProvider,
127+
),
128+
),
129+
);
130+
});
131+
```
132+
133+
The biggest drawback of this load path, compared to other load paths, is that
134+
you need to somehow get your `ImageProvider` from the test into your widget tree.
135+
This is easy for an example where the entire tree is assembled in the test. However,
136+
real tests use widget trees that don't expose inner `ImageProvider`s.
137+
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)