Skip to content

Commit c881808

Browse files
Reverts "Use Layer.toImage for golden tests on CanvasKit" (#136860)
Reverts flutter/flutter#135249 Initiated by: zanderso This change reverts the following previous change: Original Description: Changes golden tests on CanvasKit to use Layer.toImage instead of browser APIs for screenshots. This brings it more in line with other platforms and should also fix some async timing bugs with tests.
1 parent 571039f commit c881808

5 files changed

Lines changed: 54 additions & 172 deletions

File tree

packages/flutter_test/lib/src/_goldens_io.dart

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -299,16 +299,6 @@ class DefaultWebGoldenComparator extends WebGoldenComparator {
299299
Future<void> update(double width, double height, Uri golden) {
300300
throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.');
301301
}
302-
303-
@override
304-
Future<bool> compareBytes(Uint8List bytes, Uri golden) {
305-
throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.');
306-
}
307-
308-
@override
309-
Future<void> updateBytes(Uint8List bytes, Uri golden) {
310-
throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.');
311-
}
312302
}
313303

314304
/// Reads the red value out of a 32 bit rgba pixel.

packages/flutter_test/lib/src/_goldens_web.dart

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -80,30 +80,4 @@ class DefaultWebGoldenComparator extends WebGoldenComparator {
8080
// Update is handled on the server side, just use the same logic here
8181
await compare(width, height, golden);
8282
}
83-
84-
@override
85-
Future<bool> compareBytes(Uint8List bytes, Uri golden) async {
86-
final String key = golden.toString();
87-
final String bytesEncoded = base64.encode(bytes);
88-
final html.HttpRequest request = await html.HttpRequest.request(
89-
'flutter_goldens',
90-
method: 'POST',
91-
sendData: json.encode(<String, Object>{
92-
'testUri': testUri.toString(),
93-
'key': key,
94-
'bytes': bytesEncoded,
95-
}),
96-
);
97-
final String response = request.response as String;
98-
if (response == 'true') {
99-
return true;
100-
}
101-
fail(response);
102-
}
103-
104-
@override
105-
Future<void> updateBytes(Uint8List bytes, Uri golden) async {
106-
// Update is handled on the server side, just use the same logic here
107-
await compareBytes(bytes, golden);
108-
}
10983
}

packages/flutter_test/lib/src/_matchers_web.dart

Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import 'dart:ui' as ui;
66

7-
import 'package:flutter/foundation.dart';
87
import 'package:flutter/rendering.dart';
98
import 'package:flutter/widgets.dart';
109
import 'package:matcher/expect.dart';
@@ -62,58 +61,25 @@ class MatchesGoldenFile extends AsyncMatcher {
6261
final ui.FlutterView view = binding.platformDispatcher.implicitView!;
6362
final RenderView renderView = binding.renderViews.firstWhere((RenderView r) => r.flutterView == view);
6463

65-
if (isCanvasKit) {
66-
// In CanvasKit, use Layer.toImage to generate the screenshot.
67-
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.instance;
68-
return binding.runAsync<String?>(() async {
69-
assert(element.renderObject != null);
70-
RenderObject renderObject = element.renderObject!;
71-
while (!renderObject.isRepaintBoundary) {
72-
renderObject = renderObject.parent!;
73-
}
74-
assert(!renderObject.debugNeedsPaint);
75-
final OffsetLayer layer = renderObject.debugLayer! as OffsetLayer;
76-
final ui.Image image = await layer.toImage(renderObject.paintBounds);
77-
try {
78-
final ByteData? bytes = await image.toByteData(format: ui.ImageByteFormat.png);
79-
if (bytes == null) {
80-
return 'could not encode screenshot.';
81-
}
82-
if (autoUpdateGoldenFiles) {
83-
await webGoldenComparator.updateBytes(bytes.buffer.asUint8List(), key);
84-
return null;
85-
}
86-
try {
87-
final bool success = await webGoldenComparator.compareBytes(bytes.buffer.asUint8List(), key);
88-
return success ? null : 'does not match';
89-
} on TestFailure catch (ex) {
90-
return ex.message;
91-
}
92-
} finally {
93-
image.dispose();
94-
}
95-
});
96-
} else {
97-
// In the HTML renderer, we don't have the ability to render an element
98-
// to an image directly. Instead, we will use `window.render()` to render
99-
// only the element being requested, and send a request to the test server
100-
// requesting it to take a screenshot through the browser's debug interface.
101-
_renderElement(view, renderObject);
102-
final String? result = await binding.runAsync<String?>(() async {
103-
if (autoUpdateGoldenFiles) {
104-
await webGoldenComparator.update(size.width, size.height, key);
105-
return null;
106-
}
107-
try {
108-
final bool success = await webGoldenComparator.compare(size.width, size.height, key);
109-
return success ? null : 'does not match';
110-
} on TestFailure catch (ex) {
111-
return ex.message;
112-
}
113-
});
114-
_renderElement(view, renderView);
115-
return result;
116-
}
64+
// Unlike `flutter_tester`, we don't have the ability to render an element
65+
// to an image directly. Instead, we will use `window.render()` to render
66+
// only the element being requested, and send a request to the test server
67+
// requesting it to take a screenshot through the browser's debug interface.
68+
_renderElement(view, renderObject);
69+
final String? result = await binding.runAsync<String?>(() async {
70+
if (autoUpdateGoldenFiles) {
71+
await webGoldenComparator.update(size.width, size.height, key);
72+
return null;
73+
}
74+
try {
75+
final bool success = await webGoldenComparator.compare(size.width, size.height, key);
76+
return success ? null : 'does not match';
77+
} on TestFailure catch (ex) {
78+
return ex.message;
79+
}
80+
});
81+
_renderElement(view, renderView);
82+
return result;
11783
}
11884

11985
@override

packages/flutter_test/lib/src/goldens.dart

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -185,34 +185,6 @@ abstract class WebGoldenComparator {
185185
/// is left up to the implementation class.
186186
Future<void> update(double width, double height, Uri golden);
187187

188-
/// Compares the pixels of decoded png [bytes] against the golden file
189-
/// identified by [golden].
190-
///
191-
/// The returned future completes with a boolean value that indicates whether
192-
/// the pixels rendered on screen match the golden file's pixels.
193-
///
194-
/// In the case of comparison mismatch, the comparator may choose to throw a
195-
/// [TestFailure] if it wants to control the failure message, often in the
196-
/// form of a [ComparisonResult] that provides detailed information about the
197-
/// mismatch.
198-
///
199-
/// The method by which [golden] is located and by which its bytes are loaded
200-
/// is left up to the implementation class. For instance, some implementations
201-
/// may load files from the local file system, whereas others may load files
202-
/// over the network or from a remote repository.
203-
Future<bool> compareBytes(Uint8List bytes, Uri golden);
204-
205-
/// Compares the pixels of decoded png [bytes] against the golden file
206-
/// identified by [golden].
207-
///
208-
/// This will be invoked in lieu of [compareBytes] when [autoUpdateGoldenFiles]
209-
/// is `true` (which gets set automatically by the test framework when the
210-
/// user runs `flutter test --update-goldens --platform=chrome`).
211-
///
212-
/// The method by which [golden] is located and by which its bytes are written
213-
/// is left up to the implementation class.
214-
Future<void> updateBytes(Uint8List bytes, Uri golden);
215-
216188
/// Returns a new golden file [Uri] to incorporate any [version] number with
217189
/// the [key].
218190
///
@@ -326,7 +298,12 @@ class _TrivialWebGoldenComparator implements WebGoldenComparator {
326298

327299
@override
328300
Future<bool> compare(double width, double height, Uri golden) {
329-
return _warnAboutSkipping(golden);
301+
// Ideally we would use markTestSkipped here but in some situations,
302+
// comparators are called outside of tests.
303+
// See also: https://github.com/flutter/flutter/issues/91285
304+
// ignore: avoid_print
305+
print('Golden comparison requested for "$golden"; skipping...');
306+
return Future<bool>.value(true);
330307
}
331308

332309
@override
@@ -338,25 +315,6 @@ class _TrivialWebGoldenComparator implements WebGoldenComparator {
338315
Uri getTestUri(Uri key, int? version) {
339316
return key;
340317
}
341-
342-
@override
343-
Future<bool> compareBytes(Uint8List bytes, Uri golden) {
344-
return _warnAboutSkipping(golden);
345-
}
346-
347-
@override
348-
Future<void> updateBytes(Uint8List bytes, Uri golden) {
349-
throw StateError('webGoldenComparator has not been initialized');
350-
}
351-
352-
Future<bool> _warnAboutSkipping(Uri golden) {
353-
// Ideally we would use markTestSkipped here but in some situations,
354-
// comparators are called outside of tests.
355-
// See also: https://github.com/flutter/flutter/issues/91285
356-
// ignore: avoid_print
357-
print('Golden comparison requested for "$golden"; skipping...');
358-
return Future<bool>.value(true);
359-
}
360318
}
361319

362320
/// The result of a pixel comparison test.

packages/flutter_tools/lib/src/test/flutter_web_platform.dart

Lines changed: 29 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -336,44 +336,38 @@ class FlutterWebPlatform extends PlatformPlugin {
336336
final Map<String, Object?> body = json.decode(await request.readAsString()) as Map<String, Object?>;
337337
final Uri goldenKey = Uri.parse(body['key']! as String);
338338
final Uri testUri = Uri.parse(body['testUri']! as String);
339-
final num? width = body['width'] as num?;
340-
final num? height = body['height'] as num?;
339+
final num width = body['width']! as num;
340+
final num height = body['height']! as num;
341341
Uint8List bytes;
342342

343-
if (body.containsKey('bytes')) {
344-
bytes = base64.decode(body['bytes']! as String);
345-
} else {
346-
// TODO(hterkelsen): Do not use browser screenshots for testing on the
347-
// web once we transition off the HTML renderer. See:
348-
// https://github.com/flutter/flutter/issues/135700
349-
try {
350-
final ChromeTab chromeTab = (await _browserManager!._browser.chromeConnection.getTab((ChromeTab tab) {
351-
return tab.url.contains(_browserManager!._browser.url!);
352-
}))!;
353-
final WipConnection connection = await chromeTab.connect();
354-
final WipResponse response = await connection.sendCommand('Page.captureScreenshot', <String, Object>{
355-
// Clip the screenshot to include only the element.
356-
// Prior to taking a screenshot, we are calling `window.render()` in
357-
// `_matchers_web.dart` to only render the element on screen. That
358-
// will make sure that the element will always be displayed on the
359-
// origin of the screen.
360-
'clip': <String, Object>{
361-
'x': 0.0,
362-
'y': 0.0,
363-
'width': width!.toDouble(),
364-
'height': height!.toDouble(),
365-
'scale': 1.0,
366-
},
367-
});
368-
bytes = base64.decode(response.result!['data'] as String);
369-
} on WipError catch (ex) {
370-
_logger.printError('Caught WIPError: $ex');
371-
return shelf.Response.ok('WIP error: $ex');
372-
} on FormatException catch (ex) {
373-
_logger.printError('Caught FormatException: $ex');
374-
return shelf.Response.ok('Caught exception: $ex');
375-
}
343+
try {
344+
final ChromeTab chromeTab = (await _browserManager!._browser.chromeConnection.getTab((ChromeTab tab) {
345+
return tab.url.contains(_browserManager!._browser.url!);
346+
}))!;
347+
final WipConnection connection = await chromeTab.connect();
348+
final WipResponse response = await connection.sendCommand('Page.captureScreenshot', <String, Object>{
349+
// Clip the screenshot to include only the element.
350+
// Prior to taking a screenshot, we are calling `window.render()` in
351+
// `_matchers_web.dart` to only render the element on screen. That
352+
// will make sure that the element will always be displayed on the
353+
// origin of the screen.
354+
'clip': <String, Object>{
355+
'x': 0.0,
356+
'y': 0.0,
357+
'width': width.toDouble(),
358+
'height': height.toDouble(),
359+
'scale': 1.0,
360+
},
361+
});
362+
bytes = base64.decode(response.result!['data'] as String);
363+
} on WipError catch (ex) {
364+
_logger.printError('Caught WIPError: $ex');
365+
return shelf.Response.ok('WIP error: $ex');
366+
} on FormatException catch (ex) {
367+
_logger.printError('Caught FormatException: $ex');
368+
return shelf.Response.ok('Caught exception: $ex');
376369
}
370+
377371
final String? errorMessage = await _testGoldenComparator.compareGoldens(testUri, bytes, goldenKey, updateGoldens);
378372
return shelf.Response.ok(errorMessage ?? 'true');
379373
} else {

0 commit comments

Comments
 (0)