New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement screenshot test for flutter web. #45530
Implement screenshot test for flutter web. #45530
Conversation
|
||
@override | ||
Future<bool> compare(Element element, Size size, Uri golden) { | ||
throw UnsupportedError('DefaultWebGoldenComparator is noonly supported on the web.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw UnsupportedError('DefaultWebGoldenComparator is noonly supported on the web.'); | |
throw UnsupportedError('DefaultWebGoldenComparator is not supported on the web.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should read "only supported on the web".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated. It's actually only supported
instead of `not supported though.
|
||
@override | ||
Future<void> update(Uri golden, Element element, Size size) { | ||
throw UnsupportedError('DefaultWebGoldenComparator is noonly supported on the web.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw UnsupportedError('DefaultWebGoldenComparator is noonly supported on the web.'); | |
throw UnsupportedError('DefaultWebGoldenComparator is not supported on the web.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
final num height = body['height']; | ||
final Runtime browser = Runtime.chrome; | ||
final BrowserManager browserManager = await _browserManagerFor(browser); | ||
final ChromeTab chromeTab = await browserManager._browser.chromeConnection.getTab((ChromeTab tab) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code should handle the errors thrown by WIP, like WIPError (there might be some more). probably printError and move on if possible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, I've handled it by catching WIPError and returning the error to the caller.
/// be executed in a `flutter_tester` environment. This helper class generates a | ||
/// Dart file configured with flutter_test_config.dart to perform the comparison | ||
/// of golden files. | ||
class _TestGoldenComparator { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a really interesting approach. i think this PR should have at least one end to end test that goes through this path, if possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added tests for TestGoldenComparator
and TestGoldenComparatorProcess
, PTAL, thanks.
@@ -371,6 +372,8 @@ class SkiaGoldClient { | |||
return json.encode( | |||
<String, dynamic>{ | |||
'Platform' : platform.operatingSystem, | |||
if (platform.environment[_kTestBrowserKey] != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation above will need to be updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
538e2ed
to
a824f84
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM if LGT @Piinks and @jonahwilliams
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this appears to be breaking the current pre-submit workflow, see test failure in the framework-misc shards.
#44474 has landed. If you update your branch, you should see the results of pre-submit checks on the Flutter Gold dashboard under Changelists, where you can approve them ahead of time. |
8fc7d4c
to
96c0ff8
Compare
Thanks Kate! Just rebased and updated my branch, waiting for the tests to run :) |
8592f28
to
d0c9f64
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious, does this enable golden file testing for web for everyone?
d0c9f64
to
77b14eb
Compare
Yes. This PR only enabled that for a single test, and we plan to enable all the other tests in a later PR. |
The tests now passed with the new images all approved on skia-gold. @Piinks @jonahwilliams PTAL, thanks. |
}); | ||
final WipConnection connection = await chromeTab.connect(); | ||
final WipResponse response = await connection.sendCommand('Page.captureScreenshot', <String, Object>{ | ||
// Clip the screenshot to include only the element. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this actually clip the screenshot in anyway? What if it is offset from the origin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are calling window.render()
before taking the screenshot (in _matchers_web.dart
), so the element is supposed to be at the origin.
https://github.com/flutter/flutter/pull/45530/files#diff-a337fbcec47632d587865bec77ec07ddR88
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you document that here and where the render is done for posterity?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment here, and in _matches_web.dart
as well.
} | ||
}); | ||
bytes = base64.decode(response.result['data'] as String); | ||
} on WipError catch (ex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
catch FormatException from decoding
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
final String bootstrap = TestGoldenComparatorProcess.generateBootstrap(testUri); | ||
final Process process = await _startProcess(bootstrap); | ||
unawaited(_previousComparator?.close()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this work in the presence of test concurrency? Or does that not work for golden files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that we have --concurrency=1
for web tests on cirrus so I didn't take that into account when writing this.
Do we actually run tests concurrently for web? If so I can try to fix this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just talked to @yjbanov , the test runner actually uses the same browser to run multiple tests in multiple iframes, so screenshot taking doesn't work in this case.
printTrace('<<< $line'); | ||
return line.isNotEmpty && line[0] == '{'; | ||
}) | ||
.map<dynamic>((String line) => jsonDecode(line)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.map<dynamic>((String line) => jsonDecode(line)) | |
.map<dynamic>(jsonDecode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
// Configure package:test to use the Flutter engine for child processes. | ||
final String shellPath = artifacts.getArtifactPath(Artifact.flutterTester); | ||
if (!processManager.canRun(shellPath)) { | ||
throwToolExit('Cannot find Flutter shell at $shellPath'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe something like "Cannot execute tester at $shellPath"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I actually copied this text from below, in the same file :)
}); | ||
}); | ||
|
||
test('succeed when goldem comparison succeed', () => testbed.run(() async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test('succeed when goldem comparison succeed', () => testbed.run(() async { | |
test('succeed when golden comparison succeed', () => testbed.run(() async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
expect(result, null); | ||
})); | ||
|
||
test('fail with error message when goldem comparison failed', () => testbed.run(() async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test('fail with error message when goldem comparison failed', () => testbed.run(() async { | |
test('fail with error message when golden comparison failed', () => testbed.run(() async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
verify(mockProcessManager.start(any, environment: anyNamed('environment'))).called(1); | ||
})); | ||
|
||
test('does not reuse the process for differnt test file', () => testbed.run(() async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test('does not reuse the process for differnt test file', () => testbed.run(() async { | |
test('does not reuse the process for different test file', () => testbed.run(() async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some small nits, overall LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! 🎉 📸
Thank you everyone who has reviewed and given feedback to this PR! |
Description
WebGoldenComparator
(corresponds toGoldenFileComparator
for non-web), with default implementation beingDefaultWebGoldenComparator
.DefaultWebGoldenComparator
will issue a web request to the test server for taking and comparing the screenshot._matchers_io.dart
and_matcher_web.dart
, that contain the implementation ofMatchesGoldenFile
. On web, this matcher will first render the requested Element on screen, and defer the screenshot taking to the test server.flutter_test_platform.dart
, add aflutter_golden
handler for the test server, which does two things: screenshot taking and image comparison.flutter_tester
process that loadsflutter_test_config.dart
file and uses the defaultgoldenFileComparator
to compare the golden images.FLUTTER_TEST_BROWSER
environment variable is set when starting theflutter_tester
for image comparison.SkiaClient
is also updated to include this as one of the parameters.Related Issues
#40297