Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 38d8eba

Browse files
author
nturgut
authored
E2e screenshot tests2 (#21383)
* carrying code * more changes for carrying the code * rebase changes onto ios-screenshot tests * adding screenshot capability to text_editing e2e test * address some comments * change enable flag for isUnitTestsScreenshotsAvailable * addressing the reviewer comments * change the dependency for path * add to licencense file * changing goldens commit no. the new commit has the screenshot goldens * update readme file * firefox tests needs LUCI changes * change to release mode since screenshots were taken in release mode * change window size * some argument changes * small comment change * test the chrome linux tests again * use roboto font instead of default font * addressing reviewer comments * change commit for goldens
1 parent 931a046 commit 38d8eba

19 files changed

+670
-204
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,10 @@ FILE: ../../../flutter/vulkan/vulkan_window.cc
15141514
FILE: ../../../flutter/vulkan/vulkan_window.h
15151515
FILE: ../../../flutter/web_sdk/libraries.json
15161516
FILE: ../../../flutter/web_sdk/sdk_rewriter.dart
1517+
FILE: ../../../flutter/web_sdk/web_test_utils/lib/environment.dart
1518+
FILE: ../../../flutter/web_sdk/web_test_utils/lib/exceptions.dart
1519+
FILE: ../../../flutter/web_sdk/web_test_utils/lib/goldens.dart
1520+
FILE: ../../../flutter/web_sdk/web_test_utils/lib/image_compare.dart
15171521
----------------------------------------------------------------------------------------------------
15181522
Copyright 2013 The Flutter Authors. All rights reserved.
15191523

e2etests/web/regular_integration_tests/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,34 @@ flutter drive -v --target=test_driver/text_editing_integration.dart -d web-serve
3737
```
3838

3939
More details for "Running Flutter Driver tests with Web" can be found in [wiki](https://github.com/flutter/flutter/wiki/Running-Flutter-Driver-tests-with-Web).
40+
41+
## Adding screenshot tests
42+
43+
In order to test screenshot tests the tests on the driver side needs to call the `integration_test` package with an `onScreenshot` callback which can do a comparison between the `screenshotBytes` taken during the test and a golden file. We added a utility method that can do this comparison by using a golden in `flutter/goldens` repository.
44+
45+
In order to use screenshot testing first, import `screenshot_support.dart` from the driver side test (example: `text_editing_integration_test.dart`). Default value for `diffRateFailure` is 0.5.
46+
47+
```
48+
import 'package:regular_integration_tests/screenshot_support.dart' as test;
49+
50+
Future<void> main() async {
51+
final double kMaxDiffRateFailure = 0.1;
52+
await test.runTestWithScreenshots(diffRateFailure = kMaxDiffRateFailure);
53+
}
54+
```
55+
56+
In order to run the tests follow these steps:
57+
58+
1. You can use two different approaches, using [felt](https://github.com/flutter/engine/blob/master/lib/web_ui/dev/README.md) tool will run all the tests, an update all the goldens. For running individual tests, we need to set UPDATE_GOLDENS environment variable.
59+
60+
```
61+
felt test --integration-tests-only --update-screenshot-goldens
62+
```
63+
64+
```
65+
UPDATE_GOLDENS=true flutter drive -v --target=test_driver/text_editing_integration.dart -d web-server --release --local-engine=host_debug_unopt
66+
```
67+
68+
2. The golden will be under `engine/src/flutter/lib/web_ui/.dart_tool/goldens/engine/web/` directory, you should create a PR for that file and merge it to `flutter/goldens`.
69+
70+
3. Get the commit SHA and replace the `revision` in this file: `engine/src/flutter/lib/web_ui/dev/goldens_lock.yaml`
Binary file not shown.
Binary file not shown.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:io' as io;
6+
import 'dart:math';
7+
8+
import 'package:flutter_driver/flutter_driver.dart';
9+
import 'package:integration_test/integration_test_driver_extended.dart' as test;
10+
11+
import 'package:web_test_utils/goldens.dart';
12+
import 'package:web_test_utils/image_compare.dart';
13+
import 'package:webdriver/src/async/window.dart';
14+
15+
import 'package:image/image.dart';
16+
17+
/// Tolerable pixel difference ratio between the goldens and the screenshots.
18+
///
19+
/// We are allowing a higher difference rate compared to the unit tests (where
20+
/// this rate is set to 0.28), since during the end to end tests there are
21+
/// more components on the screen which are not related to the functionality
22+
/// under test ex: a blinking cursor.
23+
const double kMaxDiffRateFailure = 0.5 / 100; // 0.5%
24+
25+
/// SBrowser screen dimensions for the Flutter Driver test.
26+
const int _kScreenshotWidth = 1024;
27+
const int _kScreenshotHeight = 1024;
28+
29+
/// Used for calling `integration_test` package.
30+
///
31+
/// Compared to other similar classes which only included the following call:
32+
/// ```
33+
/// Future<void> main() async => test.integrationDriver();
34+
/// ```
35+
///
36+
/// this method is able to take screenshot.
37+
///
38+
/// It provides an `onScreenshot` callback to the `integrationDriver` method.
39+
/// It also includes options for updating the golden files.
40+
Future<void> runTestWithScreenshots(
41+
{double diffRateFailure = kMaxDiffRateFailure,
42+
int browserWidth = _kScreenshotWidth,
43+
int browserHeight = _kScreenshotHeight}) async {
44+
final WebFlutterDriver driver =
45+
await FlutterDriver.connect() as WebFlutterDriver;
46+
47+
// Learn the browser in use from the webDriver.
48+
final String browser = driver.webDriver.capabilities['browserName'] as String;
49+
50+
final Window window = await driver.webDriver.window;
51+
window.setSize(Rectangle<int>(0, 0, browserWidth, browserHeight));
52+
53+
bool updateGoldens = false;
54+
// We are using an environment variable instead of an argument, since
55+
// this code is not invoked from the shell but from the `flutter drive`
56+
// tool itself. Therefore we do not have control on the command line
57+
// arguments.
58+
// Please read the README, further info on how to update the goldens.
59+
final String updateGoldensFlag = io.Platform.environment['UPDATE_GOLDENS'];
60+
// Validate if the environment variable is set correctly.
61+
if (updateGoldensFlag != null &&
62+
!(updateGoldensFlag.toLowerCase() == 'true' ||
63+
updateGoldensFlag.toLowerCase() == 'false')) {
64+
throw StateError(
65+
'UPDATE_GOLDENS environment variable is not set correctly');
66+
}
67+
if (updateGoldensFlag != null && updateGoldensFlag.toLowerCase() == 'true') {
68+
updateGoldens = true;
69+
}
70+
71+
test.integrationDriver(
72+
driver: driver,
73+
onScreenshot: (String screenshotName, List<int> screenshotBytes) async {
74+
if (browser == 'chrome') {
75+
final Image screenshot = decodePng(screenshotBytes);
76+
final String result = compareImage(
77+
screenshot,
78+
updateGoldens,
79+
'$screenshotName-$browser.png',
80+
PixelComparison.fuzzy,
81+
diffRateFailure,
82+
forIntegrationTests: true,
83+
write: updateGoldens,
84+
);
85+
if (result == 'OK') {
86+
return true;
87+
} else {
88+
io.stderr.writeln('ERROR: $result');
89+
return false;
90+
}
91+
} else {
92+
return true;
93+
}
94+
},
95+
);
96+
}

e2etests/web/regular_integration_tests/lib/text_editing_main.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class MyApp extends StatelessWidget {
1111
Widget build(BuildContext context) {
1212
return MaterialApp(
1313
key: const Key('mainapp'),
14+
theme: ThemeData(fontFamily: 'RobotoMono'),
1415
title: 'Integration Test App',
1516
home: MyHomePage(title: 'Integration Test App'),
1617
);
@@ -56,6 +57,7 @@ class _MyHomePageState extends State<MyHomePage> {
5657
enabled: true,
5758
controller: _emptyController,
5859
decoration: const InputDecoration(
60+
contentPadding: EdgeInsets.all(10.0),
5961
labelText: 'Empty Input Field:',
6062
),
6163
),
@@ -67,6 +69,7 @@ class _MyHomePageState extends State<MyHomePage> {
6769
enabled: true,
6870
controller: _controller,
6971
decoration: const InputDecoration(
72+
contentPadding: EdgeInsets.all(10.0),
7073
labelText: 'Text Input Field:',
7174
),
7275
),
@@ -78,6 +81,7 @@ class _MyHomePageState extends State<MyHomePage> {
7881
enabled: true,
7982
controller: _controller2,
8083
decoration: const InputDecoration(
84+
contentPadding: EdgeInsets.all(10.0),
8185
labelText: 'Text Input Field 2:',
8286
),
8387
onFieldSubmitted: (String str) {
@@ -94,7 +98,7 @@ class _MyHomePageState extends State<MyHomePage> {
9498
child: SelectableText(
9599
'Lorem ipsum dolor sit amet',
96100
key: Key('selectable'),
97-
style: TextStyle(fontFamily: 'Roboto', fontSize: 20.0),
101+
style: TextStyle(fontFamily: 'RobotoMono', fontSize: 20.0),
98102
),
99103
),
100104
],

e2etests/web/regular_integration_tests/pubspec.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@ dev_dependencies:
1515
sdk: flutter
1616
integration_test: 0.9.0
1717
http: 0.12.0+2
18-
test: any
18+
web_test_utils:
19+
path: ../../../web_sdk/web_test_utils
1920

2021
flutter:
2122
assets:
2223
- assets/images/
24+
fonts:
25+
- family: RobotoMono
26+
fonts:
27+
- asset: fonts/RobotoMono-Bold.ttf
28+
- asset: fonts/RobotoMono-Regular.ttf

e2etests/web/regular_integration_tests/test_driver/text_editing_integration.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import 'package:flutter/material.dart';
1313
import 'package:integration_test/integration_test.dart';
1414

1515
void main() {
16-
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
16+
final IntegrationTestWidgetsFlutterBinding binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized() as IntegrationTestWidgetsFlutterBinding;
1717

1818
testWidgets('Focused text field creates a native input element',
1919
(WidgetTester tester) async {
@@ -41,6 +41,8 @@ void main() {
4141
textFormField.controller.text = 'New Value';
4242
// DOM element's value also changes.
4343
expect(input.value, 'New Value');
44+
45+
await binding.takeScreenshot('focused_text_field');
4446
});
4547

4648
testWidgets('Input field with no initial value works',

e2etests/web/regular_integration_tests/test_driver/text_editing_integration_test.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'package:integration_test/integration_test_driver.dart' as test;
5+
import 'package:regular_integration_tests/screenshot_support.dart' as test;
66

7-
Future<void> main() async => test.integrationDriver();
7+
Future<void> main() async {
8+
await test.runTestWithScreenshots();
9+
}

lib/web_ui/dev/goldens_lock.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
repository: https://github.com/flutter/goldens.git
2-
revision: 1a4722227af42c3f51450266016b1a07ae459e73
2+
revision: da3fef0c0eb849dfbb14b09a088c5f7916677482

0 commit comments

Comments
 (0)