Skip to content

Commit df1cb66

Browse files
author
Robert Messerle
committed
test(e2e): initial setup for screenshot tests
1 parent 3781943 commit df1cb66

13 files changed

+170
-10
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Files ending with `.screenshot.png` will be stored using `git-lfs` rather than stored in the git repository
2+
*.screenshot.png filter=lfs diff=lfs merge=lfs -text

.travis.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ language: node_js
55
sudo: false
66

77
node_js:
8-
- '4.2.3'
8+
- '5.6.0'
9+
10+
addons:
11+
apt:
12+
sources:
13+
- ubuntu-toolchain-r-test
14+
packages:
15+
- libstdc++6
916

1017
env:
1118
global:
@@ -33,6 +40,7 @@ env:
3340
- MODE=dart_required DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
3441
- MODE=saucelabs_optional
3542
- MODE=browserstack_optional
43+
- MODE=e2e
3644

3745
matrix:
3846
allow_failures:

e2e/_screenshot.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"use strict";
2+
3+
const path = require('path');
4+
const child_process = require('child_process');
5+
const mapnik = require('mapnik');
6+
7+
const SHA = process.env.TRAVIS_COMMIT;
8+
const LFS_BASE_URL = 'https://media.githubusercontent.com/media/angular/material2';
9+
10+
/**
11+
* Generates a screenshot from the current state of the Protractor test and compares it to the
12+
* previous stored screenshot. If the screenshots do not match or if no existing screenshot is
13+
* found, an error will be thrown. In both cases, the new screenshot will be stored so that it can
14+
* be added to git.
15+
*/
16+
class Screenshot {
17+
/**
18+
* @param {string} id A unique identifier used for the screenshot
19+
*/
20+
constructor(id) {
21+
this.id = id;
22+
this.path = path.resolve(__dirname, '..', 'screenshots', id + '.screenshot.png');
23+
this.url = `${LFS_BASE_URL}/${SHA}/screenshots/${encodeURIComponent(id)}.screenshot.png`;
24+
browser.takeScreenshot().then(png => this.storeScreenshot(png));
25+
}
26+
27+
/**
28+
* Stores a local copy of the screenshot for future comparison
29+
* @param {string} png The base64-encoded screenshot generated from the current browser state
30+
*/
31+
storeScreenshot(png) {
32+
console.info(`[STATUS] Generated new screenshot for "${this.id}"`);
33+
this.png = mapnik.Image.fromBytes(new Buffer(png, 'base64'));
34+
if (SHA) {
35+
this.downloadFromGithub();
36+
} else {
37+
this.compareScreenshots();
38+
}
39+
}
40+
41+
/**
42+
* Since we are using `git-lfs`, screenshots are not necessarily available within our local
43+
* directory. To get around this, we download the latest screenshot from Github.
44+
*/
45+
downloadFromGithub() {
46+
console.info(`[STATUS] Downloading screenshot from Github: ${this.url} => ${this.path}`);
47+
child_process.execSync(`curl ${this.url} > "${this.path}"`);
48+
this.compareScreenshots();
49+
}
50+
51+
/**
52+
* Compares the generated screenshot to the existing screenshot. If it does not match, an error
53+
* will be thrown.
54+
*/
55+
compareScreenshots() {
56+
console.info(`[STATUS] Comparing screenshots`);
57+
try {
58+
let referenceScreenshot = mapnik.Image.open(this.path);
59+
this.overwriteExistingScreenshot();
60+
if (referenceScreenshot.compare(this.png)) {
61+
throw new Error(`screenshot "${this.id}" has changed.`);
62+
} else {
63+
console.info('[STATUS] Screenshot has not changed');
64+
}
65+
} catch (e) {
66+
console.info(`[STATUS] No reference screenshot found`);
67+
this.overwriteExistingScreenshot();
68+
throw new Error(`screenshot "${this.id}" was not found.`);
69+
}
70+
}
71+
72+
/**
73+
* Replaces the existing screenshot with the newly generated one.
74+
*/
75+
overwriteExistingScreenshot() {
76+
console.info(`[STATUS] Saving new screenshot`);
77+
this.png.save(this.path);
78+
}
79+
}
80+
81+
module.exports = (id) => new Screenshot(id);

e2e/index.e2e.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const screenshot = require('./_screenshot.js');
2+
3+
describe('hello, protractor', function () {
4+
describe('index', function () {
5+
browser.get('/');
6+
it('should have a title', function () {
7+
expect(browser.getTitle()).toBe('Material2');
8+
screenshot('initial state');
9+
});
10+
});
11+
});
12+

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
"scripts": {
1111
"build": "ng build",
1212
"dartanalyzer": "cd dist/dart && pub install && cd ../.. && ts-node scripts/ci/dart_analyzer",
13-
"demo-app": "cd src && ng serve",
13+
"demo-app": "ng serve",
1414
"test": "karma start test/karma.conf.js",
1515
"tslint" : "tslint -c tslint.json 'src/**/*.ts'",
16-
"typings": "typings install --ambient"
16+
"typings": "typings install --ambient",
17+
"e2e": "protractor ./protractor.conf.js"
1718
},
1819
"version": "2.0.0-alpha.0",
1920
"license": "MIT",
@@ -24,6 +25,8 @@
2425
"angular2": "2.0.0-beta.8",
2526
"es6-promise": "^3.0.2",
2627
"es6-shim": "^0.33.3",
28+
"mapnik": "^3.5.2",
29+
"protractor": "^3.1.1",
2730
"reflect-metadata": "0.1.2",
2831
"rxjs": "5.0.0-beta.2",
2932
"systemjs": "0.19.4",

protractor.conf.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
var key = require('./scripts/sauce/sauce_config.js');
2+
3+
exports.config = {
4+
useAllAngular2AppRoots: true,
5+
specs: [ './e2e/**/*.e2e.js' ],
6+
baseUrl: 'http://localhost:4200',
7+
sauceUser: process.env.SAUCE_USERNAME,
8+
sauceKey: key,
9+
capabilities: {
10+
'browserName': 'chrome',
11+
'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER,
12+
'build': process.env.TRAVIS_JOB_NUMBER,
13+
'name': 'Material 2 E2E Tests'
14+
}
15+
};
Lines changed: 3 additions & 0 deletions
Loading

scripts/ci/build-and-test.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@ is_dart && source scripts/ci/sources/env_dart.sh
1515

1616
start_tunnel
1717
npm run build
18+
echo
1819
is_dart && pub install
1920

2021
wait_for_tunnel
2122
if is_dart; then
2223
npm run dartanalyzer
24+
elif [[ "$MODE" = e2e* ]]; then
25+
ng serve &
26+
sleep 20
27+
npm run e2e
2328
else
2429
karma start test/karma.conf.js --single-run --no-auto-watch --reporters='dots'
2530
fi
2631
teardown_tunnel
27-

scripts/ci/sources/tunnel.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
start_tunnel() {
55
case "$MODE" in
6-
saucelabs*)
6+
e2e*|saucelabs*)
77
./scripts/sauce/sauce_connect_setup.sh
88
;;
99
browserstack*)
@@ -16,7 +16,7 @@ start_tunnel() {
1616

1717
wait_for_tunnel() {
1818
case "$MODE" in
19-
saucelabs*)
19+
e2e*|saucelabs*)
2020
./scripts/sauce/sauce_connect_block.sh
2121
;;
2222
browserstack*)
@@ -30,7 +30,7 @@ wait_for_tunnel() {
3030

3131
teardown_tunnel() {
3232
case "$MODE" in
33-
saucelabs*)
33+
e2e*|saucelabs*)
3434
./scripts/sauce/sauce_connect_teardown.sh
3535
;;
3636
browserstack*)

scripts/e2e.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/usr/bin/env bash
2+
3+
export MODE=e2e
4+
export LOGS_DIR=/tmp/angular-material2-build/logs
5+
export BROWSER_PROVIDER_READY_FILE=$LOGS_DIR/sauce-connect-readyfile
6+
export SAUCE_USERNAME=angular-ci
7+
export SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
8+
export TRAVIS_JOB_NUMBER=12345
9+
10+
mkdir -p $LOGS_DIR
11+
rm -f $BROWSER_PROVIDER_READY_FILE
12+
13+
# Force cleanup (shouldn't be necessary)
14+
killall angular-cli
15+
./scripts/sauce/sauce_connect_teardown.sh
16+
# Run the script
17+
./scripts/ci/build-and-test.sh
18+
# Actual cleanup
19+
./scripts/sauce/sauce_connect_teardown.sh
20+
killall angular-cli

scripts/sauce/sauce_config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = process.env.SAUCE_ACCESS_KEY.split('').reverse().join('');

scripts/sauce/sauce_connect_block.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#!/bin/bash
22

33
# Wait for Connect to be ready before exiting
4-
printf "Connecting to Sauce."
4+
echo "Connecting to Sauce Labs"
55
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
66
printf "."
77
#dart2js takes longer than the travis 10 min timeout to complete
88
sleep .5
99
done
10+
echo
1011
echo "Connected"

scripts/sauce/sauce_connect_setup.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,30 @@ set -e -o pipefail
1212
# before_script:
1313
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
1414

15-
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.11-linux.tar.gz"
1615
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
1716
CONNECT_DOWNLOAD="sc-latest-linux.tar.gz"
1817

1918
CONNECT_LOG="$LOGS_DIR/sauce-connect"
2019
CONNECT_STDOUT="$LOGS_DIR/sauce-connect.stdout"
2120
CONNECT_STDERR="$LOGS_DIR/sauce-connect.stderr"
2221

23-
# Get Connect and start it
22+
# Get the appropriate URL for downloading Sauce Connect
23+
if [ `uname -s` = "Darwin" ]; then
24+
# If the user is running Mac, download the OSX version
25+
# https://en.wikipedia.org/wiki/Darwin_(operating_system)
26+
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.11-osx.zip"
27+
else
28+
# Otherwise, default to Linux for Travis-CI
29+
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.11-linux.tar.gz"
30+
fi
2431
mkdir -p $CONNECT_DIR
2532
cd $CONNECT_DIR
2633
curl $CONNECT_URL -o $CONNECT_DOWNLOAD 2> /dev/null 1> /dev/null
2734
mkdir sauce-connect
2835
tar --extract --file=$CONNECT_DOWNLOAD --strip-components=1 --directory=sauce-connect > /dev/null
2936
rm $CONNECT_DOWNLOAD
3037

38+
3139
SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
3240

3341
ARGS=""
@@ -45,5 +53,7 @@ echo "Starting Sauce Connect in the background, logging into:"
4553
echo " $CONNECT_LOG"
4654
echo " $CONNECT_STDOUT"
4755
echo " $CONNECT_STDERR"
56+
echo " ---"
57+
echo " $ARGS"
4858
sauce-connect/bin/sc -u $SAUCE_USERNAME -k $SAUCE_ACCESS_KEY $ARGS \
4959
--logfile $CONNECT_LOG 2> $CONNECT_STDERR 1> $CONNECT_STDOUT &

0 commit comments

Comments
 (0)