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 {