Skip to content

Commit

Permalink
Merge branch 'master' into #66_landscape_mode
Browse files Browse the repository at this point in the history
# Conflicts:
#	lib/src/run.dart
#	lib/src/utils.dart
#	test/screenshots_test.dart
  • Loading branch information
mmcc007 committed Jul 17, 2019
2 parents 481298b + e0a5d13 commit a74d8d3
Show file tree
Hide file tree
Showing 33 changed files with 907 additions and 426 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ doc/api/
# screenshots
example/ios/fastlane
example/android/fastlane
**/**/*-diff.png

# mac
.DS_Store
4 changes: 1 addition & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,8 @@ jobs:
- pub global activate --source path .

script:
- cd example; screenshots
- cd example; screenshots -c screenshots_CI.yaml
# copy artifacts to cache for later deploy
- tar cvzf $HOME/screenshots/screenshots.tar.gz ios/fastlane/screenshots android/fastlane/metadata/android/*/images
- zip -r $HOME/screenshots/screenshots.zip ios/fastlane/screenshots android/fastlane/metadata/android/*/images

# deploy artifacts if tagged commit
Expand All @@ -103,6 +102,5 @@ jobs:
secure: wyPNNbjTFChWOGc/JiTpGhN490dRzz/qhU2T3CddZALjy4VN3LywennK3xnTOAq+FEYE9H/quP/SxkUX154al/lxeL6QuN5D0Ev2bL3lS9jyaoe0NOKx5GnNTzfv84taZPi768UF4rgYqzzdF8WJTCe0dlvDH7qKgH+dHIZGoB1dM/hhWMEXUv0uAZuFDkepxWHOLHsIABunkz428MEsSRCTdEWOsgdFiEl+DOC5ErmorgHazUWPpSwenz13kCLhU+wT2Fsek5tGBO6GT1Mvw8qrht3LUZBaBQJfx4yhdXQKtq0Dr+gI9a3sbF/3TKV0nRvDVA+KGmMLHT+fkRrz1xkGvrLnCDfkylDZlmn/IoQUkv4JwI+lJIXfUp40pMmSlFH1WKToWSjMsPSxv02fVYzxNZoxlno+qyKk4lfdROOSSYS5LjmMd+Lrvhmx7vNMCHl57fdXdKwgyJllxT/khMZTJv5IPQih1yi3m/hDw0s59IHYd22QHFoodcdAPy2xxeVh8VhzhucpesWAvoFZfgdTmPZXAzpMR4kEaeBb5f3Z/Eg3AypDPXg67kXwFqTRL+ZqDzOFynZYJML8RbsZd/nqU5TYc0Ocmh0YMA3v0Z43wuZMshXOXujl8z3zmnwzV/QmFP0U/phOGa9SmvKtRyGQoTGtIXoPWdXrRpgm3F4=
file:
- $HOME/screenshots/screenshots.zip
- $HOME/screenshots/screenshots.tar.gz
on:
tags: true
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
## 1.2.0
- Added archive feature to collect screenshots of all runs for reporting, etc... #77 #81
- Improved detection of adb path #79

## 1.1.1
- Fixed localization issue in test #19, #20
- Improved handling of locale for emulators and real devices

## 1.1.0
- Added record/compare feature to compare screenshots with previously recorded screenshots during a run. #65

## 1.0.2
- Fixed bug with parsing ios simulator info #73

## 1.0.1
- Fixed pedantic lint errors

Expand Down Expand Up @@ -46,7 +60,7 @@

- Bypasses changing locales if running in only one locale
- Issues warning about running flutter driver in multiple locales
See issue: https://github.com/flutter/flutter/issues/27785 for details.
See issue: <https://github.com/flutter/flutter/issues/27785> for details.

## 0.1.3

Expand Down
71 changes: 51 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Select the devices you want to run on, using a convenient config file. _Screensh
_Screenshots_ runs your tests on both iOS and Android in one run.
(as opposed to making separate Snapshots and Screengrab runs)
1. One run for multiple locales
If your app supports multiple locales, _Screenshots_ will optionally set the locales listed in the config file before running each test (see Limitations below).
If your app supports multiple locales, _Screenshots_ will optionally set the locales listed in the config file before running each test.
1. One run for frames
Optionally places images in device frames in same run.
(as opposed to making separate FrameIt runs... which supports iOS only)
Expand Down Expand Up @@ -86,6 +86,22 @@ Or, if using a config file other than the default 'screenshots.yaml':
````
$ screenshots -c <path to config file>
````
Other options:
```
$ screenshots -h
usage: screenshots [-h] [-c <config file>] [-m <normal|recording|comparison|archive>]
sample usage: screenshots
-c, --config=<screenshots.yaml> Path to config file.
(defaults to "screenshots.yaml")
-m, --mode=<normal|recording|comparison|archive> If mode is recording, screenshots will be saved for later comparison.
If mode is archive, screenshots will be archived and cannot be uploaded via fastlane.
[normal (default), recording, comparison, archive]
-h, --help Display this help information.
```

# Modifying your tests for _Screenshots_
A special function is provided in the _Screenshots_ package that is called by the test each time you want to capture a screenshot.
Expand All @@ -103,11 +119,11 @@ To capture screenshots in your tests:
````
2. Create the config at start of test
````dart
final config = Config().configInfo;
final configInfo = Config().configInfo;
````
3. Throughout the test make calls to capture screenshots
````dart
await screenshot(driver, config, 'myscreenshot1');
await screenshot(driver, configInfo, 'myscreenshot1');
````

Note: make sure your screenshot names are unique across all your tests.
Expand Down Expand Up @@ -169,6 +185,37 @@ Individual devices can be configured in `screenshots.yaml` by specifying per dev

Note: images generated for those devices where framing is disabled are probably not suitable for upload, but can be used for local review.

# Record/Compare Mode
_Screenshots_ can be used to monitor any unexpected changes to the UI by comparing the new screenshots to previously recorded screenshots. Any differences will be highlighted in a 'diff' image for review.

To use this feature:
1. Add the location of your recording directory to a `screenshots.yaml`
```yaml
recording: /tmp/screenshots_record
```
1. Run a recording to capture your screenshots:
```
screenshots -m recording
```
1. Run subsequent _Screenshots_ with:
```
screenshots -m comparison
```
_Screenshots_ will compare the new screenshots with the recorded screenshots and generate a 'diff' image for each screenshot that does not compare. The diff image highlights the differences in red.

# Archive Mode
To generate screenshots for local use, such as generating reports of changes to UI over time, etc... use 'archive' mode.

To enable this mode:
1. Add the location of your archive directory to screenshots.yaml:
```yaml
archive: /tmp/screenshots_archive
```
1. Run _Screenshots_ with:
````
$ screenshots -m archive
````

# Integration with Fastlane
Since _Screenshots_ is intended to be used with Fastlane, after _Screenshots_ completes, the images can be found in your project at:
````
Expand All @@ -191,7 +238,7 @@ To change the devices to run your tests on, just change the list of devices in s

Make sure each device you select has a supported screen and a
corresponding attached device or installed emulator/simulator. To bypass
this requirement use `frame: false` for each related device in your
the supported screen requirement use `frame: false` for each related device in your
screenshots.yaml.

For each selected device:
Expand Down Expand Up @@ -227,22 +274,6 @@ https://github.com/mmcc007/screenshots/releases/
* Running _Screenshots_ in the cloud is useful for automating the generation of your screenshots in a CI/CD environment.
* Running _Screenshots_ on macOS in the cloud can be used to generate your screenshots when developing on Linux and/or Windows (if not using locally attached iOS devices).

# Limitations

Due to a Flutter issue ([flutter/issues/27785](https://github.com/flutter/flutter/issues/27785)), running _Screenshots_ in multiple locales has limitations.

To raise priority of this Flutter issue, so it will be fixed sooner rather than later, please give a thumbs-up on [flutter/issues/27785](https://github.com/flutter/flutter/issues/27785).

Priority of this limitation in Flutter project:

| Date | `flutter driver` | `internationalization` | `test` |
| --- | --- | --- | --- |
| 4/26/2019 | [#1](https://github.com/flutter/flutter/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22t%3A+flutter+driver%22+) | [#5](https://github.com/flutter/flutter/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22a%3A+internationalization%22+) | [#7](https://github.com/flutter/flutter/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22a%3A+tests%22+) |
| 5/25/2019 | [#1](https://github.com/flutter/flutter/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22t%3A+flutter+driver%22+) | [#3](https://github.com/flutter/flutter/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22a%3A+internationalization%22+) | [#6](https://github.com/flutter/flutter/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22a%3A+tests%22+) |
| 6/29/2019 | [#1](https://github.com/flutter/flutter/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22t%3A+flutter+driver%22+) | [#1](https://github.com/flutter/flutter/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22a%3A+internationalization%22+) | [#3](https://github.com/flutter/flutter/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A%22a%3A+tests%22+) |

(This limitation is being tracked by _screenshots_ in [screenshots/issues/20](https://github.com/mmcc007/screenshots/issues/20)).

# Issues and Pull Requests
[Issues](https://github.com/mmcc007/screenshots/issues) and
[pull requests](https://github.com/mmcc007/screenshots/pulls) are welcome.
Expand Down
65 changes: 46 additions & 19 deletions bin/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,45 @@ import 'dart:io';

import 'package:args/args.dart';
import 'package:screenshots/screenshots.dart';
import 'package:path/path.dart' as path;

const usage = 'usage: screenshots [--help] [--config <config file>]';
const usage =
'usage: screenshots [-h] [-c <config file>] [-m <normal|recording|comparison|archive>]';
const sampleUsage = 'sample usage: screenshots';

void main(List<String> arguments) async {
ArgResults argResults;

final configArg = 'config';
final modeArg = 'mode';
final helpArg = 'help';
final ArgParser argParser = ArgParser(allowTrailingOptions: false)
..addOption(configArg,
abbr: 'c',
defaultsTo: 'screenshots.yaml',
help: 'Path to config file.',
valueHelp: 'screenshots.yaml')
..addOption(modeArg,
abbr: 'm',
defaultsTo: 'normal',
help:
'If mode is recording, screenshots will be saved for later comparison. \nIf mode is archive, screenshots will be archived and cannot be uploaded via fastlane.',
allowed: ['normal', 'recording', 'comparison', 'archive'],
valueHelp: 'normal|recording|comparison|archive')
..addFlag(helpArg,
help: 'Display this help information.', negatable: false);
abbr: 'h', help: 'Display this help information.', negatable: false);
try {
argResults = argParser.parse(arguments);
} on ArgParserException catch (e) {
_handleError(argParser, e.toString());
}

// show help
if (argResults[helpArg]) {
_showUsage(argParser);
exit(0);
}

// confirm os
switch (Platform.operatingSystem) {
case 'windows':
Expand Down Expand Up @@ -55,28 +71,15 @@ void main(List<String> arguments) async {
exit(1);
}

// check adb is in path
if (!cmd('sh', ['-c', 'which adb && echo adb || echo not installed'], '.',
true)
.toString()
.contains('adb')) {
stderr.write(
'#############################################################\n');
stderr.write("# 'adb' must be in the PATH to use Screenshots\n");
stderr.write("# You can usually add it to the PATH using\n"
"# export PATH='~/Library/Android/sdk/platform-tools:\$PATH' \n");
stderr.write(
'#############################################################\n');
exit(1);
}
// check adb is found
getAdbPath();

// validate args
final file = File(argResults[configArg]);
if (!await file.exists()) {
if (!await File(argResults[configArg]).exists()) {
_handleError(argParser, "File not found: ${argResults[configArg]}");
}

await run(argResults[configArg]);
await run(argResults[configArg], argResults[modeArg]);
}

void _handleError(ArgParser argParser, String msg) {
Expand All @@ -90,3 +93,27 @@ void _showUsage(ArgParser argParser) {
print(argParser.usage);
exit(2);
}

/// Path to the `adb` executable.
String getAdbPath() {
final String androidHome = Platform.environment['ANDROID_HOME'] ??
Platform.environment['ANDROID_SDK_ROOT'];
if (androidHome == null) {
throw 'The ANDROID_SDK_ROOT and ANDROID_HOME environment variables are '
'missing. At least one of these variables must point to the Android '
'SDK directory containing platform-tools.';
}
final String adbPath = path.join(androidHome, 'platform-tools/adb');
final absPath = path.absolute(adbPath);
if (!File(adbPath).existsSync()) {
stderr.write(
'#############################################################\n');
stderr.write("# 'adb' must be in the PATH to use Screenshots\n");
stderr.write("# You can usually add it to the PATH using\n"
"# export PATH='\$HOME/Library/Android/sdk/platform-tools:\$PATH' \n");
stderr.write(
'#############################################################\n');
exit(1);
}
return absPath;
}
17 changes: 12 additions & 5 deletions example/screenshots.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@ tests:
staging: /tmp/screenshots

# A list of locales supported in app
# Note: while support for multiple locales has been implemented in `screenshots`,
# non-default locales currently do not work due to flutter bug.
# See open issue: https://github.com/flutter/flutter/issues/27785 for details.
locales:
# - fr-CA
- fr-CA
- en-US

# A list of devices to run tests on
Expand All @@ -29,4 +26,14 @@ devices:
orientation: LandscapeRight

# Frame screenshots
frame: true
frame: true

# Run mode can be one of 'normal' (default), 'recording', 'comparison' or 'archive'.

# If run mode is 'recording' or 'comparison', a directory is required for recorded images.
recording: /tmp/screenshots_record

# If not intending to upload screenshots, images can be stored in an archive dir.
# This over-rides output to fastlane dirs.
# If run mode is 'archive', a directory is required for archived images.
archive: /tmp/screenshots_archive
24 changes: 24 additions & 0 deletions example/screenshots_CI.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Screen capture tests
# Note: flutter driver expects a pair of files eg, main.dart and main_test.dart
tests:
- test_driver/main.dart

# Interim location of screenshots from tests before processing
staging: /tmp/screenshots

# A list of locales supported in app
locales:
- fr-CA
- en-US

# A list of devices to run tests on
devices:
ios:
iPhone XS Max:
iPad Pro (12.9-inch) (2nd generation):
frame: false
android:
# Nexus 6P:

# Frame screenshots
frame: true
19 changes: 18 additions & 1 deletion example/test_driver/main.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
import 'dart:async';
import 'dart:convert' as c;
import 'dart:ui' as ui;

import 'package:example/main.dart';
import 'package:flutter/material.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'package:intl/intl.dart';

void main() {
final DataHandler handler = (_) async {
final localizations =
await ExampleLocalizations.load(Locale(ui.window.locale.languageCode));
final response = {
'counterIncrementButtonTooltip':
localizations.counterIncrementButtonTooltip,
'counterText': localizations.counterText,
'title': localizations.title,
'locale': Intl.defaultLocale
};
return Future.value(c.jsonEncode(response));
};
// Enable integration testing with the Flutter Driver extension.
// See https://flutter.io/testing/ for more info.
enableFlutterDriverExtension();
enableFlutterDriverExtension(handler: handler);
WidgetsApp.debugAllowBannerOverride = false; // remove debug banner
runApp(MyApp());
}
8 changes: 7 additions & 1 deletion example/test_driver/main_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,20 @@
import 'package:flutter_driver/flutter_driver.dart';
import 'package:screenshots/screenshots.dart';
import 'package:test/test.dart';
import 'dart:convert' as c;

void main() {
group('end-to-end test', () {
FlutterDriver driver;
Map localizations;
final config = Config().configInfo;

setUpAll(() async {
// Connect to a running Flutter application instance.
driver = await FlutterDriver.connect();
// get the localizations for the current locale
localizations = c.jsonDecode(await driver.requestData(null));
print('localizations=$localizations');
});

tearDownAll(() async {
Expand All @@ -24,7 +29,8 @@ void main() {

test('tap on the floating action button; verify counter', () async {
// Finds the floating action button (fab) to tap on
SerializableFinder fab = find.byTooltip('Increment');
SerializableFinder fab =
find.byTooltip(localizations['counterIncrementButtonTooltip']);

// Wait for the floating action button to appear
await driver.waitFor(fab);
Expand Down
Loading

0 comments on commit a74d8d3

Please sign in to comment.