diff --git a/gulpfile.js b/gulpfile.js
index 3e401a9e02..2086dff30a 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -20,6 +20,7 @@ var sass = require('gulp-sass');
var shell = require('gulp-shell');
var traceur = require('gulp-traceur');
var wrap = require('gulp-wrap');
+var argv = require('yargs').argv;
gulp.task('default', ['js', 'html', 'sass', 'libs', 'playgroundJs', 'playgroundFiles']);
@@ -47,10 +48,6 @@ gulp.task('karma-watch', function() {
return karma.start({ configFile: __dirname + '/scripts/test/karma-watch.conf.js' });
});
-gulp.task('sass-watch', ['sass'], function () {
- gulp.watch('src/**/*.scss', ['sass']);
-});
-
gulp.task('sass', function(done) {
gulp.src('src/components/app/ionic.scss')
.pipe(sass({
@@ -137,12 +134,18 @@ gulp.task('angular2', function () {
});
gulp.task('examples', ['sass'], function() {
- return gulp.src('src/components/**/examples/**/*')
+ var examplesSrc = path.join(__dirname, 'src/components/**/examples/**/*');
+ var templateSrc = path.join(__dirname, 'scripts/examples/index.template.html');
+ var examplesDest = path.join(__dirname, 'dist/examples/');
+
+ return gulp.src(examplesSrc)
.pipe(gulpif(/index.html/, wrap({
- src: 'scripts/examples/index.template.html'
+ src: templateSrc
})))
.pipe(rename(function(file) {
file.dirname = file.dirname.replace('/examples/', '/');
}))
- .pipe(gulp.dest('dist/examples/'));
+ .pipe(gulp.dest(examplesDest));
});
+
+require('./scripts/snapshot/snapshot.task')(gulp, argv, buildConfig);
diff --git a/package.json b/package.json
index 4fa77c2961..74c28af288 100644
--- a/package.json
+++ b/package.json
@@ -2,6 +2,7 @@
"name": "ionic2",
"version": "0.0.0",
"devDependencies": {
+ "canonical-path": "0.0.2",
"connect": "^3.3.4",
"del": "~1.1.1",
"gulp": "~3.8.10",
@@ -16,11 +17,18 @@
"gulp-sass": "^1.3.3",
"gulp-shell": "^0.4.0",
"gulp-traceur": "0.16.*",
+ "gulp-util": "^3.0.4",
"gulp-wrap": "^0.11.0",
"karma": "^0.12.31",
+ "lodash": "^2.4.1",
+ "lodash.template": "^2.4.1",
+ "node-uuid": "^1.4.1",
+ "q": "^1.2.0",
+ "request": "^2.53.0",
"serve-static": "~1.8.1",
"systemjs": "^0.11.3",
- "through2": "~0.6.3"
+ "through2": "~0.6.3",
+ "yargs": "^3.6.0"
},
"dependencies": {
"angular2": "2.0.0-alpha.13",
diff --git a/scripts/build/config.js b/scripts/build/config.js
index 639c2bc9a7..b2508fcb96 100644
--- a/scripts/build/config.js
+++ b/scripts/build/config.js
@@ -15,5 +15,6 @@ module.exports = {
'node_modules/systemjs/lib/extension-register.js',
'node_modules/angular2/node_modules/zone.js/zone.js',
'node_modules/hammerjs/hammer.js'
- ]
+ ],
+ protractorPort: 8876
};
diff --git a/scripts/examples/index.template.html b/scripts/examples/index.template.html
index cd4c6ef815..5337ec7079 100644
--- a/scripts/examples/index.template.html
+++ b/scripts/examples/index.template.html
@@ -4,7 +4,7 @@
-
+
diff --git a/scripts/snapshot/ionic.snapshot.js b/scripts/snapshot/ionic.snapshot.js
new file mode 100644
index 0000000000..fb5ccb1147
--- /dev/null
+++ b/scripts/snapshot/ionic.snapshot.js
@@ -0,0 +1,140 @@
+var q = require('q');
+
+var IonicSnapshot = function(options) {
+
+ // modules
+ var _ = require('lodash');
+ var request = require('request');
+ var colors = require('gulp-util').colors;
+ var log = console.log.bind(console, '[' + colors.cyan('IonicReporter') + ']');
+
+ var IonicReporter = function(options) {
+ var self = this;
+
+ // set options and defaults
+ self.domain = options.domain || 'ionic-snapshot-go.appspot.com';
+ self.groupId = options.groupId || 'test_group';
+ self.appId = options.appId || 'test_app';
+ self.testId = browser.params.test_id || 'test_id';
+ self.platformId = browser.params.platform_id;
+ self.platformIndex = browser.params.platform_index;
+ self.platformCount = browser.params.platform_count;
+ self.sleepBetweenSpecs = options.sleepBetweenSpecs || 400;
+ self.width = browser.params.width || -1;
+ self.height = browser.params.height || -1;
+ self.highestMismatch = 0;
+ self.screenshotRequestPromises = [];
+
+ self.flow = protractor.promise.controlFlow();
+
+ if(self.width > 0 && self.height > 0) {
+ self.flow.execute(function(){
+ return browser.driver.manage().window().setSize(self.width, self.height);
+ });
+ }
+ self.flow.execute(function(){
+ return browser.getCapabilities().then(function (capabilities) {
+ self.testData = {
+ group_id: self.groupId,
+ app_id: self.appId,
+ test_id: self.testId,
+ platform_id: self.platformId,
+ platform_index: self.platformIndex,
+ platform_count: self.platformCount,
+ width: self.width,
+ height: self.height,
+ browser: capabilities.get('browserName'),
+ platform: capabilities.get('platform'),
+ version: capabilities.get('version'),
+ access_key: options.accessKey
+ };
+ });
+ });
+ process.on('exit', function() {
+ log(colors.green('Highest Mismatch:'), self.highestMismatch, '%');
+ });
+
+ log('init:', _.pick(self, ['testId', 'appId', 'width', 'height', 'platformId']));
+ };
+
+ IonicReporter.prototype.reportSpecResults = function(spec) {
+ var self = this;
+
+ if(!self.testData.total_specs) {
+ self.testData.total_specs = 0;
+ var allSpecs = jasmine.getEnv().currentRunner().specs();
+ for(var sId in allSpecs) {
+ self.testData.total_specs++;
+ }
+ }
+
+ self.flow.execute(function(){
+ var d = protractor.promise.defer();
+
+ browser.waitForAngular().then(function(){
+
+ browser.getCurrentUrl().then(function(currentUrl) {
+
+ browser.sleep(self.sleepBetweenSpecs).then(function(){
+
+ browser.takeScreenshot().then(function(pngBase64){
+ var specIdString = '[' + (spec.id+1) + '/' + self.testData.total_specs + ']';
+ log(specIdString, spec.getFullName());
+
+ self.testData.spec_index = spec.id;
+ self.testData.description = spec.getFullName();
+ self.testData.highest_mismatch = self.highestMismatch;
+ self.testData.png_base64 = pngBase64;
+ self.testData.url = currentUrl;
+ pngBase64 = null;
+
+ var requestDeferred = q.defer();
+ self.screenshotRequestPromises.push(requestDeferred.promise);
+
+ request.post(
+ 'http://' + self.domain + '/screenshot',
+ { form: self.testData },
+ function (error, response, body) {
+ log(specIdString, 'reportSpecResults:', body);
+ try {
+ var rspData = JSON.parse(body);
+ self.highestMismatch = Math.max(self.highestMismatch, rspData.Mismatch);
+ } catch(e) {
+ log(specIdString, colors.red('reportSpecResults', 'error posting screenshot:'), e);
+ }
+ requestDeferred.resolve();
+ }
+ );
+ d.fulfill();
+ });
+ });
+
+ });
+
+ });
+
+ return d.promise;
+ });
+ };
+
+ IonicReporter.prototype.reportRunnerResults = function() {
+ var self = this;
+
+ self.flow.execute(function() {
+ var d = protractor.promise.defer();
+ log('Waiting for all screenshots to be posted...');
+ // allSettled waits until all the promises are done, whether they are rejected or resolved
+ q.allSettled(self.screenshotRequestPromises).then(function(all) {
+ d.fulfill();
+ log('Finished!');
+ });
+ });
+ };
+
+
+
+ this.jasmine.getEnv().addReporter( new IonicReporter(options) );
+
+};
+
+module.exports = IonicSnapshot;
diff --git a/scripts/snapshot/protractor.config.js b/scripts/snapshot/protractor.config.js
new file mode 100644
index 0000000000..909cad15b6
--- /dev/null
+++ b/scripts/snapshot/protractor.config.js
@@ -0,0 +1,32 @@
+
+var buildConfig = require('../build/config');
+var path = require('canonical-path');
+var projectRoot = path.resolve(__dirname, '../..');
+
+exports.config = {
+
+ // Spec patterns are relative to the location of the spec file. They may
+ // include glob patterns.
+ specs: [
+ path.resolve(projectRoot, 'dist/examples/**/*.scenario.js'),
+ ],
+
+ // Options to be passed to Jasmine-node.
+ jasmineNodeOpts: {
+ showColors: true, // Use colors in the command line report.
+ defaultTimeoutInterval: 120000,
+ isVerbose: true
+ },
+
+ baseUrl: 'http://localhost:' + buildConfig.protractorPort,
+
+ onPrepare: function() {
+ var ionicSnapshot = require('./ionic.snapshot.js');
+ ionicSnapshot({
+ groupId: 'ionic2',
+ appId: 'snapshots',
+ accessKey: process.env.IONIC_SNAPSHOT_KEY
+ });
+ }
+
+};
diff --git a/scripts/snapshot/snapshot.task.js b/scripts/snapshot/snapshot.task.js
new file mode 100644
index 0000000000..dfee2be7e2
--- /dev/null
+++ b/scripts/snapshot/snapshot.task.js
@@ -0,0 +1,75 @@
+var _ = require('lodash');
+var http = require('http');
+var connect = require('connect');
+var serveStatic = require('serve-static');
+var cp = require('child_process');
+var path = require('canonical-path');
+var uuid = require('node-uuid');
+
+var projectRoot = path.resolve(__dirname, '../..');
+
+
+module.exports = function(gulp, argv, buildConfig) {
+
+ var protractorHttpServer;
+ gulp.task('protractor-server', function() {
+ var app = connect().use(serveStatic(projectRoot + '/' + buildConfig.dist)); // serve everything that is static
+ protractorHttpServer = http.createServer(app).listen(buildConfig.protractorPort);
+ console.log('Serving `dist` on http://localhost:' + buildConfig.protractorPort);
+ });
+
+ gulp.task('snapshot', ['examples', 'protractor-server'], function(done) {
+ var configFile = path.resolve(projectRoot, 'scripts/snapshot/protractor.config.js');
+ snapshot(done, configFile);
+ });
+
+ var snapshotValues = _.merge({
+ browser: 'chrome',
+ platform: 'linux',
+ params: {
+ platform_id: 'chrome_local_test',
+ platform_index: 0,
+ platform_count: 1,
+ width: 400,
+ height: 800,
+ test_id: uuid.v4()
+ }
+ }, argv);
+
+ function snapshot(done, configFile) {
+ var protractorArgs = [
+ '--browser <%= browser %>',
+ '--platform <%= platform %>',
+ '--params.platform_id=<%= params.platform_id %>',
+ '--params.platform_index=<%= params.platform_index %>',
+ '--params.platform_count=<%= params.platform_count %>',
+ '--params.width=<%= params.width %>',
+ '--params.height=<%= params.height %>',
+ '--params.test_id=<%= params.test_id %>',
+ ].map(function(argument) {
+ return _.template(argument, snapshotValues);
+ });
+
+ return protractor(done, [configFile].concat(protractorArgs));
+ }
+
+ function protractor(done, args) {
+ console.log('Start protractor');
+
+ var child = cp.spawn('protractor', args, {
+ stdio: [process.stdin, process.stdout, 'pipe']
+ });
+
+ var finish = _.once(function(err) {
+ err && done(err) || done();
+ protractorHttpServer.close();
+ });
+
+ child.stderr.on('data', function(data) {
+ finish('Protractor tests failed. Error:', data.toString());
+ });
+ child.on('exit', function() {
+ finish();
+ });
+ }
+};
diff --git a/src/components/button/examples/button-block/test.scenario.js b/src/components/button/examples/button-block/test.scenario.js
new file mode 100644
index 0000000000..86300719ab
--- /dev/null
+++ b/src/components/button/examples/button-block/test.scenario.js
@@ -0,0 +1,6 @@
+
+describe('Protractor Demo App', function() {
+ it('should just be', function() {
+ browser.get('http://localhost:8876/examples/button/button-block/');
+ });
+});