From c881808ed2ffa57af8f9957178d6dcd24d76e900 Mon Sep 17 00:00:00 2001 From: "auto-submit[bot]" <98614782+auto-submit[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 02:20:19 +0000 Subject: [PATCH] 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. --- .../flutter_test/lib/src/_goldens_io.dart | 10 --- .../flutter_test/lib/src/_goldens_web.dart | 26 ------- .../flutter_test/lib/src/_matchers_web.dart | 72 +++++-------------- packages/flutter_test/lib/src/goldens.dart | 54 ++------------ .../lib/src/test/flutter_web_platform.dart | 64 ++++++++--------- 5 files changed, 54 insertions(+), 172 deletions(-) diff --git a/packages/flutter_test/lib/src/_goldens_io.dart b/packages/flutter_test/lib/src/_goldens_io.dart index 9a8481c92a..371458d053 100644 --- a/packages/flutter_test/lib/src/_goldens_io.dart +++ b/packages/flutter_test/lib/src/_goldens_io.dart @@ -299,16 +299,6 @@ class DefaultWebGoldenComparator extends WebGoldenComparator { Future update(double width, double height, Uri golden) { throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.'); } - - @override - Future compareBytes(Uint8List bytes, Uri golden) { - throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.'); - } - - @override - Future updateBytes(Uint8List bytes, Uri golden) { - throw UnsupportedError('DefaultWebGoldenComparator is only supported on the web.'); - } } /// Reads the red value out of a 32 bit rgba pixel. diff --git a/packages/flutter_test/lib/src/_goldens_web.dart b/packages/flutter_test/lib/src/_goldens_web.dart index b29f9ccdca..4053e4d22d 100644 --- a/packages/flutter_test/lib/src/_goldens_web.dart +++ b/packages/flutter_test/lib/src/_goldens_web.dart @@ -80,30 +80,4 @@ class DefaultWebGoldenComparator extends WebGoldenComparator { // Update is handled on the server side, just use the same logic here await compare(width, height, golden); } - - @override - Future compareBytes(Uint8List bytes, Uri golden) async { - final String key = golden.toString(); - final String bytesEncoded = base64.encode(bytes); - final html.HttpRequest request = await html.HttpRequest.request( - 'flutter_goldens', - method: 'POST', - sendData: json.encode({ - 'testUri': testUri.toString(), - 'key': key, - 'bytes': bytesEncoded, - }), - ); - final String response = request.response as String; - if (response == 'true') { - return true; - } - fail(response); - } - - @override - Future updateBytes(Uint8List bytes, Uri golden) async { - // Update is handled on the server side, just use the same logic here - await compareBytes(bytes, golden); - } } diff --git a/packages/flutter_test/lib/src/_matchers_web.dart b/packages/flutter_test/lib/src/_matchers_web.dart index bb40a8ebd0..7f54720eb2 100644 --- a/packages/flutter_test/lib/src/_matchers_web.dart +++ b/packages/flutter_test/lib/src/_matchers_web.dart @@ -4,7 +4,6 @@ import 'dart:ui' as ui; -import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:matcher/expect.dart'; @@ -62,58 +61,25 @@ class MatchesGoldenFile extends AsyncMatcher { final ui.FlutterView view = binding.platformDispatcher.implicitView!; final RenderView renderView = binding.renderViews.firstWhere((RenderView r) => r.flutterView == view); - if (isCanvasKit) { - // In CanvasKit, use Layer.toImage to generate the screenshot. - final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.instance; - return binding.runAsync(() async { - assert(element.renderObject != null); - RenderObject renderObject = element.renderObject!; - while (!renderObject.isRepaintBoundary) { - renderObject = renderObject.parent!; - } - assert(!renderObject.debugNeedsPaint); - final OffsetLayer layer = renderObject.debugLayer! as OffsetLayer; - final ui.Image image = await layer.toImage(renderObject.paintBounds); - try { - final ByteData? bytes = await image.toByteData(format: ui.ImageByteFormat.png); - if (bytes == null) { - return 'could not encode screenshot.'; - } - if (autoUpdateGoldenFiles) { - await webGoldenComparator.updateBytes(bytes.buffer.asUint8List(), key); - return null; - } - try { - final bool success = await webGoldenComparator.compareBytes(bytes.buffer.asUint8List(), key); - return success ? null : 'does not match'; - } on TestFailure catch (ex) { - return ex.message; - } - } finally { - image.dispose(); - } - }); - } else { - // In the HTML renderer, we don't have the ability to render an element - // to an image directly. Instead, we will use `window.render()` to render - // only the element being requested, and send a request to the test server - // requesting it to take a screenshot through the browser's debug interface. - _renderElement(view, renderObject); - final String? result = await binding.runAsync(() async { - if (autoUpdateGoldenFiles) { - await webGoldenComparator.update(size.width, size.height, key); - return null; - } - try { - final bool success = await webGoldenComparator.compare(size.width, size.height, key); - return success ? null : 'does not match'; - } on TestFailure catch (ex) { - return ex.message; - } - }); - _renderElement(view, renderView); - return result; - } + // Unlike `flutter_tester`, we don't have the ability to render an element + // to an image directly. Instead, we will use `window.render()` to render + // only the element being requested, and send a request to the test server + // requesting it to take a screenshot through the browser's debug interface. + _renderElement(view, renderObject); + final String? result = await binding.runAsync(() async { + if (autoUpdateGoldenFiles) { + await webGoldenComparator.update(size.width, size.height, key); + return null; + } + try { + final bool success = await webGoldenComparator.compare(size.width, size.height, key); + return success ? null : 'does not match'; + } on TestFailure catch (ex) { + return ex.message; + } + }); + _renderElement(view, renderView); + return result; } @override diff --git a/packages/flutter_test/lib/src/goldens.dart b/packages/flutter_test/lib/src/goldens.dart index 0f83ac832e..721952bf4c 100644 --- a/packages/flutter_test/lib/src/goldens.dart +++ b/packages/flutter_test/lib/src/goldens.dart @@ -185,34 +185,6 @@ abstract class WebGoldenComparator { /// is left up to the implementation class. Future update(double width, double height, Uri golden); - /// Compares the pixels of decoded png [bytes] against the golden file - /// identified by [golden]. - /// - /// The returned future completes with a boolean value that indicates whether - /// the pixels rendered on screen match the golden file's pixels. - /// - /// In the case of comparison mismatch, the comparator may choose to throw a - /// [TestFailure] if it wants to control the failure message, often in the - /// form of a [ComparisonResult] that provides detailed information about the - /// mismatch. - /// - /// The method by which [golden] is located and by which its bytes are loaded - /// is left up to the implementation class. For instance, some implementations - /// may load files from the local file system, whereas others may load files - /// over the network or from a remote repository. - Future compareBytes(Uint8List bytes, Uri golden); - - /// Compares the pixels of decoded png [bytes] against the golden file - /// identified by [golden]. - /// - /// This will be invoked in lieu of [compareBytes] when [autoUpdateGoldenFiles] - /// is `true` (which gets set automatically by the test framework when the - /// user runs `flutter test --update-goldens --platform=chrome`). - /// - /// The method by which [golden] is located and by which its bytes are written - /// is left up to the implementation class. - Future updateBytes(Uint8List bytes, Uri golden); - /// Returns a new golden file [Uri] to incorporate any [version] number with /// the [key]. /// @@ -326,7 +298,12 @@ class _TrivialWebGoldenComparator implements WebGoldenComparator { @override Future compare(double width, double height, Uri golden) { - return _warnAboutSkipping(golden); + // Ideally we would use markTestSkipped here but in some situations, + // comparators are called outside of tests. + // See also: https://github.com/flutter/flutter/issues/91285 + // ignore: avoid_print + print('Golden comparison requested for "$golden"; skipping...'); + return Future.value(true); } @override @@ -338,25 +315,6 @@ class _TrivialWebGoldenComparator implements WebGoldenComparator { Uri getTestUri(Uri key, int? version) { return key; } - - @override - Future compareBytes(Uint8List bytes, Uri golden) { - return _warnAboutSkipping(golden); - } - - @override - Future updateBytes(Uint8List bytes, Uri golden) { - throw StateError('webGoldenComparator has not been initialized'); - } - - Future _warnAboutSkipping(Uri golden) { - // Ideally we would use markTestSkipped here but in some situations, - // comparators are called outside of tests. - // See also: https://github.com/flutter/flutter/issues/91285 - // ignore: avoid_print - print('Golden comparison requested for "$golden"; skipping...'); - return Future.value(true); - } } /// The result of a pixel comparison test. diff --git a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart index 5a2fc29ab4..6400b7a059 100644 --- a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart @@ -336,44 +336,38 @@ class FlutterWebPlatform extends PlatformPlugin { final Map body = json.decode(await request.readAsString()) as Map; final Uri goldenKey = Uri.parse(body['key']! as String); final Uri testUri = Uri.parse(body['testUri']! as String); - final num? width = body['width'] as num?; - final num? height = body['height'] as num?; + final num width = body['width']! as num; + final num height = body['height']! as num; Uint8List bytes; - if (body.containsKey('bytes')) { - bytes = base64.decode(body['bytes']! as String); - } else { - // TODO(hterkelsen): Do not use browser screenshots for testing on the - // web once we transition off the HTML renderer. See: - // https://github.com/flutter/flutter/issues/135700 - try { - final ChromeTab chromeTab = (await _browserManager!._browser.chromeConnection.getTab((ChromeTab tab) { - return tab.url.contains(_browserManager!._browser.url!); - }))!; - final WipConnection connection = await chromeTab.connect(); - final WipResponse response = await connection.sendCommand('Page.captureScreenshot', { - // Clip the screenshot to include only the element. - // Prior to taking a screenshot, we are calling `window.render()` in - // `_matchers_web.dart` to only render the element on screen. That - // will make sure that the element will always be displayed on the - // origin of the screen. - 'clip': { - 'x': 0.0, - 'y': 0.0, - 'width': width!.toDouble(), - 'height': height!.toDouble(), - 'scale': 1.0, - }, - }); - bytes = base64.decode(response.result!['data'] as String); - } on WipError catch (ex) { - _logger.printError('Caught WIPError: $ex'); - return shelf.Response.ok('WIP error: $ex'); - } on FormatException catch (ex) { - _logger.printError('Caught FormatException: $ex'); - return shelf.Response.ok('Caught exception: $ex'); - } + try { + final ChromeTab chromeTab = (await _browserManager!._browser.chromeConnection.getTab((ChromeTab tab) { + return tab.url.contains(_browserManager!._browser.url!); + }))!; + final WipConnection connection = await chromeTab.connect(); + final WipResponse response = await connection.sendCommand('Page.captureScreenshot', { + // Clip the screenshot to include only the element. + // Prior to taking a screenshot, we are calling `window.render()` in + // `_matchers_web.dart` to only render the element on screen. That + // will make sure that the element will always be displayed on the + // origin of the screen. + 'clip': { + 'x': 0.0, + 'y': 0.0, + 'width': width.toDouble(), + 'height': height.toDouble(), + 'scale': 1.0, + }, + }); + bytes = base64.decode(response.result!['data'] as String); + } on WipError catch (ex) { + _logger.printError('Caught WIPError: $ex'); + return shelf.Response.ok('WIP error: $ex'); + } on FormatException catch (ex) { + _logger.printError('Caught FormatException: $ex'); + return shelf.Response.ok('Caught exception: $ex'); } + final String? errorMessage = await _testGoldenComparator.compareGoldens(testUri, bytes, goldenKey, updateGoldens); return shelf.Response.ok(errorMessage ?? 'true'); } else {