33// found in the LICENSE file.
44
55// @dart = 2.6
6- import 'dart:html' show ProgressEvent ;
6+ import 'dart:html' as html ;
77import 'dart:typed_data' ;
88
99import 'package:test/bootstrap/browser.dart' ;
@@ -23,8 +23,12 @@ void testMain() {
2323 group ('CanvasKit image' , () {
2424 setUpCanvasKitTest ();
2525
26+ tearDown (() {
27+ debugRestoreHttpRequestFactory ();
28+ });
29+
2630 test ('CkAnimatedImage can be explicitly disposed of' , () {
27- final CkAnimatedImage image = CkAnimatedImage .decodeFromBytes (kTransparentImage);
31+ final CkAnimatedImage image = CkAnimatedImage .decodeFromBytes (kTransparentImage, 'test' );
2832 expect (image.debugDisposed, false );
2933 image.dispose ();
3034 expect (image.debugDisposed, true );
@@ -99,13 +103,6 @@ void testMain() {
99103 testCollector.collectNow ();
100104 });
101105
102- test ('skiaInstantiateWebImageCodec throws exception if given invalid URL' ,
103- () async {
104- expect (skiaInstantiateWebImageCodec ('invalid-url' , null ),
105- throwsA (isA <ProgressEvent >()));
106- testCollector.collectNow ();
107- });
108-
109106 test ('CkImage toByteData' , () async {
110107 final SkImage skImage =
111108 canvasKit.MakeAnimatedImageFromEncoded (kTransparentImage)
@@ -116,14 +113,210 @@ void testMain() {
116113 testCollector.collectNow ();
117114 });
118115
119- test ('Reports error when failing to decode image' , () async {
116+ test ('skiaInstantiateWebImageCodec loads an image from the network' ,
117+ () async {
118+ httpRequestFactory = () {
119+ return TestHttpRequest ()
120+ ..status = 200
121+ ..onLoad = Stream <html.ProgressEvent >.fromIterable (< html.ProgressEvent > [
122+ html.ProgressEvent ('test error' ),
123+ ])
124+ ..response = kTransparentImage.buffer;
125+ };
126+ final ui.Codec codec = await skiaInstantiateWebImageCodec ('http://image-server.com/picture.jpg' , null );
127+ expect (codec.frameCount, 1 );
128+ final ui.Image image = (await codec.getNextFrame ()).image;
129+ expect (image.height, 1 );
130+ expect (image.width, 1 );
131+ testCollector.collectNow ();
132+ });
133+
134+ test ('skiaInstantiateWebImageCodec throws exception on request error' ,
135+ () async {
136+ httpRequestFactory = () {
137+ return TestHttpRequest ()
138+ ..onError = Stream <html.ProgressEvent >.fromIterable (< html.ProgressEvent > [
139+ html.ProgressEvent ('test error' ),
140+ ]);
141+ };
142+ try {
143+ await skiaInstantiateWebImageCodec ('url-does-not-matter' , null );
144+ fail ('Expected to throw' );
145+ } on ImageCodecException catch (exception) {
146+ expect (
147+ exception.toString (),
148+ 'ImageCodecException: Failed to load network image.\n '
149+ 'Image URL: url-does-not-matter\n '
150+ 'Trying to load an image from another domain? Find answers at:\n '
151+ 'https://flutter.dev/docs/development/platform-integration/web-images' ,
152+ );
153+ }
154+ testCollector.collectNow ();
155+ });
156+
157+ test ('skiaInstantiateWebImageCodec throws exception on HTTP error' ,
158+ () async {
159+ try {
160+ await skiaInstantiateWebImageCodec ('/does-not-exist.jpg' , null );
161+ fail ('Expected to throw' );
162+ } on ImageCodecException catch (exception) {
163+ expect (
164+ exception.toString (),
165+ 'ImageCodecException: Failed to load network image.\n '
166+ 'Image URL: /does-not-exist.jpg\n '
167+ 'Server response code: 404' ,
168+ );
169+ }
170+ testCollector.collectNow ();
171+ });
172+
173+ test ('skiaInstantiateWebImageCodec includes URL in the error for malformed image' ,
174+ () async {
175+ httpRequestFactory = () {
176+ return TestHttpRequest ()
177+ ..status = 200
178+ ..onLoad = Stream <html.ProgressEvent >.fromIterable (< html.ProgressEvent > [
179+ html.ProgressEvent ('test error' ),
180+ ])
181+ ..response = Uint8List (0 ).buffer;
182+ };
183+ try {
184+ await skiaInstantiateWebImageCodec ('http://image-server.com/picture.jpg' , null );
185+ fail ('Expected to throw' );
186+ } on ImageCodecException catch (exception) {
187+ expect (
188+ exception.toString (),
189+ 'ImageCodecException: Failed to decode image data.\n '
190+ 'Image source: http://image-server.com/picture.jpg' ,
191+ );
192+ }
193+ testCollector.collectNow ();
194+ });
195+
196+ test ('Reports error when failing to decode image data' , () async {
120197 try {
121198 await ui.instantiateImageCodec (Uint8List (0 ));
122199 fail ('Expected to throw' );
123- } on Exception catch (exception) {
124- expect (exception.toString (), 'Exception: Failed to decode image' );
200+ } on ImageCodecException catch (exception) {
201+ expect (
202+ exception.toString (),
203+ 'ImageCodecException: Failed to decode image data.\n '
204+ 'Image source: encoded image bytes'
205+ );
125206 }
126207 });
127208 // TODO: https://github.com/flutter/flutter/issues/60040
128209 }, skip: isIosSafari);
129210}
211+
212+ class TestHttpRequest implements html.HttpRequest {
213+ @override
214+ String responseType;
215+
216+ @override
217+ int timeout = 10 ;
218+
219+ @override
220+ bool withCredentials = false ;
221+
222+ @override
223+ void abort () {
224+ throw UnimplementedError ();
225+ }
226+
227+ @override
228+ void addEventListener (String type, listener, [bool useCapture]) {
229+ throw UnimplementedError ();
230+ }
231+
232+ @override
233+ bool dispatchEvent (html.Event event) {
234+ throw UnimplementedError ();
235+ }
236+
237+ @override
238+ String getAllResponseHeaders () {
239+ throw UnimplementedError ();
240+ }
241+
242+ @override
243+ String getResponseHeader (String name) {
244+ throw UnimplementedError ();
245+ }
246+
247+ @override
248+ html.Events get on => throw UnimplementedError ();
249+
250+ @override
251+ Stream <html.ProgressEvent > get onAbort => throw UnimplementedError ();
252+
253+ @override
254+ Stream <html.ProgressEvent > onError = Stream <html.ProgressEvent >.fromIterable (< html.ProgressEvent > []);
255+
256+ @override
257+ Stream <html.ProgressEvent > onLoad = Stream <html.ProgressEvent >.fromIterable (< html.ProgressEvent > []);
258+
259+ @override
260+ Stream <html.ProgressEvent > get onLoadEnd => throw UnimplementedError ();
261+
262+ @override
263+ Stream <html.ProgressEvent > get onLoadStart => throw UnimplementedError ();
264+
265+ @override
266+ Stream <html.ProgressEvent > get onProgress => throw UnimplementedError ();
267+
268+ @override
269+ Stream <html.Event > get onReadyStateChange => throw UnimplementedError ();
270+
271+ @override
272+ Stream <html.ProgressEvent > get onTimeout => throw UnimplementedError ();
273+
274+ @override
275+ void open (String method, String url, {bool async , String user, String password}) {}
276+
277+ @override
278+ void overrideMimeType (String mime) {
279+ throw UnimplementedError ();
280+ }
281+
282+ @override
283+ int get readyState => throw UnimplementedError ();
284+
285+ @override
286+ void removeEventListener (String type, listener, [bool useCapture]) {
287+ throw UnimplementedError ();
288+ }
289+
290+ @override
291+ dynamic response;
292+
293+ @override
294+ Map <String , String > get responseHeaders => throw UnimplementedError ();
295+
296+ @override
297+ String get responseText => throw UnimplementedError ();
298+
299+ @override
300+ String get responseUrl => throw UnimplementedError ();
301+
302+ @override
303+ html.Document get responseXml => throw UnimplementedError ();
304+
305+ @override
306+ void send ([dynamic bodyOrData]) {
307+ }
308+
309+ @override
310+ void setRequestHeader (String name, String value) {
311+ throw UnimplementedError ();
312+ }
313+
314+ @override
315+ int status = - 1 ;
316+
317+ @override
318+ String get statusText => throw UnimplementedError ();
319+
320+ @override
321+ html.HttpRequestUpload get upload => throw UnimplementedError ();
322+ }
0 commit comments