@samitouri / QOS-React-2 / commits / 3df6942cde

SauceLabs Browser testing via Travis

Thomas Aylott committed Oct 29, 2013 at 18:21 UTC 3df6942cdee2a9b095663f270e7c2fb4a750c5ae
8 files changed +250 -7
.travis.yml
+2
@@ -13,3 +13,5 @@ env:
13 - secure: qPvsJ46XzGrdIuPA70b55xQNGF8jcK7N1LN5CCQYYocXLa+fBrl+fTE77QvehOPhqwJXcj6kOxI+sY0KrVwV7gmq2XY2HZGWUSCxTN0SZlNIzqPA80Y7G/yOjA4PUt8LKgP+8tptyhTAY56qf+hgW8BoLiKOdztYF2p+3zXOLuA=
14 # SECRET_TOKEN
15 - secure: dkpPW+VnoqC/okhRdV90m36NcyBFhcwEKL3bNFExAwi0dXnFao8RoFlvnwiPlA23h2faROkMIetXlti6Aju08BgUFV+f9aL6vLyU7gUent4Nd3413zf2fwDtXIWIETg6uLnOpSykGKgCAT/hY3Q2oPLqOoY0OxfgnbqwxkxljrE=
16 + - secure: EOPQOI/kPyv6Yw4prbFnmH/zexDMyTm9800iiItU8U287pIhD6r5xRqmShJ5astrSNsOMsogfSMGO85HvAkyhOSykmbeQe61V5vjzfcWXd8pR3cCGAS1/7ajBXmkI2CPD3UFNQAAXSQDIipgR5CC6yeuk3kubsVbVc2c3TIlAi4=
17 + - secure: X8EKc78pIGcaIzAz11VYVZdMHqpg18ykDthtuxwcKsE3N60TBSTqYRA0ptR5QaqfYHm9VElXkWsUNiTZjqQiIjI6JCP7d3EpjmJJF4RjwQDhOFm9jgIqShJdk8RbftkrzPVx4sIaBTJQXoKfVK0CvNWrVHkWnIlUOS79xc7L2ZE=
Gruntfile.js
+12 -6
@@ -17,6 +17,8 @@ module.exports = function(grunt) {
17 browserify: require('./grunt/config/browserify'),
18 populist: require('./grunt/config/populist'),
19 phantom: require('./grunt/config/phantom'),
20 + connect: require('./grunt/config/server'),
21 + "saucelabs-jasmine": require('./grunt/config/saucelabs-jasmine'),
22 npm: require('./grunt/config/npm'),
23 clean: ['./build', './*.gem', './docs/_site', './examples/shared/*.js'],
24 jshint: require('./grunt/config/jshint'),
@@ -25,11 +27,9 @@ module.exports = function(grunt) {
27
28 grunt.config.set('compress', require('./grunt/config/compress'));
29
28 - grunt.loadNpmTasks('grunt-contrib-jshint');
29 - grunt.loadNpmTasks('grunt-contrib-copy');
30 - grunt.loadNpmTasks('grunt-contrib-clean');
31 - grunt.loadNpmTasks('grunt-compare-size');
32 - grunt.loadNpmTasks('grunt-contrib-compress');
30 + for (var key in grunt.file.readJSON("package.json").devDependencies) {
31 + if (key !== "grunt" && key.indexOf("grunt") === 0) grunt.loadNpmTasks(key);
32 + }
33
34 // Alias 'jshint' to 'lint' to better match the workflow we know
35 grunt.registerTask('lint', ['jshint']);
@@ -74,7 +74,13 @@ module.exports = function(grunt) {
74 'populist:test'
75 ]);
76
77 - grunt.registerTask('test', ['build:test', 'build:basic', 'phantom:run']);
77 + grunt.registerTask('test', [
78 + 'build:test',
79 + 'build:basic',
80 + 'phantom:run',
81 + 'connect',
82 + 'saucelabs-jasmine'
83 + ]);
84 grunt.registerTask('npm:test', ['build', 'npm:pack']);
85
86 // Optimized build task that does all of our builds. The subtasks will be run
grunt/config/saucelabs-jasmine.js new
+42
@@ -0,0 +1,42 @@
1 +// https://saucelabs.com/docs/platforms
2 +
3 +var browsers = [
4 + { browserName: 'chrome', platform: 'linux' },
5 +
6 + { browserName: 'android', platform: 'Linux', version: '4.0', 'device-type': 'tablet', 'device-orientation': 'portrait' },
7 + { browserName: 'android', platform: 'Linux', version: '4.0' },
8 +
9 + { browserName: 'ipad', platform: 'OS X 10.6', version: '4' },
10 + { browserName: 'ipad', platform: 'OS X 10.8', version: '5.1' },
11 + { browserName: 'iphone', platform: 'OS X 10.8', version: '6.1' },
12 +
13 + { browserName: 'firefox', version: '24', platform: 'Windows 7' },
14 + { browserName: 'firefox', version: '19', platform: 'Windows XP' },
15 + { browserName: 'firefox', version: '3', platform: 'Linux' },
16 +
17 + { browserName: 'opera', platform: 'Windows 2008', version: '12' },
18 +
19 + { browserName: 'internet explorer', platform: 'Windows 8', version: '10' },
20 + { browserName: 'internet explorer', platform: 'Windows 7', version: '9' },
21 + { browserName: 'internet explorer', platform: 'Windows 7', version: '8' },
22 + { browserName: 'internet explorer', platform: 'Windows XP', version: '8' },
23 + { browserName: 'internet explorer', platform: 'Windows XP', version: '7' },
24 + { browserName: 'internet explorer', platform: 'Windows XP', version: '6' },
25 +
26 + { browserName: 'safari', platform: 'OS X 10.8', version: '6' },
27 + { browserName: 'safari', platform: 'OS X 10.6', version: '5' },
28 +];
29 +
30 +module.exports = {
31 + all: {
32 + options: {
33 + urls: ["http://127.0.0.1:9999/test/sauce-harness.html"],
34 + tunnelTimeout: 5,
35 + build: process.env.TRAVIS_JOB_ID || 'dev' + Date.now(),
36 + concurrency: 3,
37 + browsers: browsers,
38 + testname: "React",
39 + tags: ["master"]
40 + }
41 + }
42 +}
grunt/config/server.js new
+8
@@ -0,0 +1,8 @@
1 +module.exports = {
2 + server: {
3 + options: {
4 + base: "",
5 + port: 9999
6 + }
7 + }
8 +}
package.json
+3 -1
@@ -81,7 +81,9 @@
81 "gzip-js": "~0.3.2",
82 "tmp": "~0.0.18",
83 "grunt-contrib-compress": "~0.5.1",
84 - "jasmine-tapreporter": "~0.2.2"
84 + "jasmine-tapreporter": "~0.2.2",
85 + "grunt-saucelabs": "~4.1.2",
86 + "grunt-contrib-connect": "~0.5.0"
87 },
88 "engines": {
89 "node": ">=0.10.0"
test/jasmine-execute.js
+1
@@ -1,5 +1,6 @@
1 ;(function(env){
2 env.addReporter(new TAPReporter(console.log.bind(console)));
3 + env.addReporter(new jasmine.JSReporter());
4
5 // Clean up any nodes the previous test might have added.
6 env.afterEach(function() {
test/sauce-harness.html new
+21
@@ -0,0 +1,21 @@
1 +<!doctype html>
2 +<meta charset=utf-8>
3 +
4 +<link rel="stylesheet" href="../vendor/jasmine/jasmine.css">
5 +<script>
6 +
7 +var __filename = location.protocol + '//' + location.hostname + ':' + location.port + location.pathname.replace(/^\/?/,'/');
8 +var __dirname = __filename.split('/').reverse().slice(1).reverse().join('/');
9 +
10 +var cacheBust = '?_=' + Date.now().toString(36);
11 +
12 +window.ReactWebWorker_URL = __dirname + '/../src/test/worker.js' + cacheBust;
13 +
14 +</script>
15 +<script src='../build/jasmine.js'></script>
16 +<script src='../build/react.js'></script>
17 +<script src='../build/react-test.js'></script>
18 +<script src='../node_modules/jasmine-tapreporter/src/tapreporter.js'></script>
19 +<script src='../test/the-files-to-test.generated.js'></script>
20 +<script src="../vendor/jasmine-jsreporter/jasmine-jsreporter.js"></script>
21 +<script src='../test/jasmine-execute.js'></script>
vendor/jasmine-jsreporter/jasmine-jsreporter.js new
+161
@@ -0,0 +1,161 @@
1 +/*
2 + This file is part of the Jasmine JSReporter project from Ivan De Marino.
3 +
4 + Copyright (C) 2011 Ivan De Marino (aka detro, aka detronizator), http://blog.ivandemarino.me, ivan.de.marino@gmail.com
5 +
6 + Redistribution and use in source and binary forms, with or without
7 + modification, are permitted provided that the following conditions are met:
8 +
9 + * Redistributions of source code must retain the above copyright
10 + notice, this list of conditions and the following disclaimer.
11 + * Redistributions in binary form must reproduce the above copyright
12 + notice, this list of conditions and the following disclaimer in the
13 + documentation and/or other materials provided with the distribution.
14 + * Neither the name of the <organization> nor the
15 + names of its contributors may be used to endorse or promote products
16 + derived from this software without specific prior written permission.
17 +
18 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 + ARE DISCLAIMED. IN NO EVENT SHALL IVAN DE MARINO BE LIABLE FOR ANY
22 + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 +*/
29 +
30 +(function () {
31 + // Ensure that Jasmine library is loaded first
32 + if (typeof jasmine === "undefined") {
33 + throw new Error("[Jasmine JSReporter] 'Jasmine' library not found");
34 + }
35 +
36 + /**
37 + * Calculate elapsed time, in Seconds.
38 + * @param startMs Start time in Milliseconds
39 + * @param finishMs Finish time in Milliseconds
40 + * @return Elapsed time in Seconds */
41 + function elapsedSec (startMs, finishMs) {
42 + return (finishMs - startMs) / 1000;
43 + }
44 +
45 + /**
46 + * Round an amount to the given number of Digits.
47 + * If no number of digits is given, than '2' is assumed.
48 + * @param amount Amount to round
49 + * @param numOfDecDigits Number of Digits to round to. Default value is '2'.
50 + * @return Rounded amount */
51 + function round (amount, numOfDecDigits) {
52 + numOfDecDigits = numOfDecDigits || 2;
53 + return Math.round(amount * Math.pow(10, numOfDecDigits)) / Math.pow(10, numOfDecDigits);
54 + }
55 +
56 + /**
57 + * Collect information about a Suite, recursively, and return a JSON result.
58 + * @param suite The Jasmine Suite to get data from
59 + */
60 + function getSuiteData (suite) {
61 + var suiteData = {
62 + description : suite.description,
63 + durationSec : 0,
64 + specs: [],
65 + suites: [],
66 + passed: true
67 + },
68 + specs = suite.specs(),
69 + suites = suite.suites(),
70 + i, ilen;
71 +
72 + // Loop over all the Suite's Specs
73 + for (i = 0, ilen = specs.length; i < ilen; ++i) {
74 + suiteData.specs[i] = {
75 + description : specs[i].description,
76 + durationSec : specs[i].durationSec,
77 + passed : specs[i].results().passedCount === specs[i].results().totalCount,
78 + skipped : specs[i].results().skipped,
79 + passedCount : specs[i].results().passedCount,
80 + failedCount : specs[i].results().failedCount,
81 + totalCount : specs[i].results().totalCount
82 + };
83 + suiteData.passed = !suiteData.specs[i].passed ? false : suiteData.passed;
84 + suiteData.durationSec += suiteData.specs[i].durationSec;
85 + }
86 +
87 + // Loop over all the Suite's sub-Suites
88 + for (i = 0, ilen = suites.length; i < ilen; ++i) {
89 + suiteData.suites[i] = getSuiteData(suites[i]); //< recursive population
90 + suiteData.passed = !suiteData.suites[i].passed ? false : suiteData.passed;
91 + suiteData.durationSec += suiteData.suites[i].durationSec;
92 + }
93 +
94 + // Rounding duration numbers to 3 decimal digits
95 + suiteData.durationSec = round(suiteData.durationSec, 4);
96 +
97 + return suiteData;
98 + }
99 +
100 + var JSReporter = function () {
101 + };
102 +
103 + JSReporter.prototype = {
104 + reportRunnerStarting: function (runner) {
105 + // Nothing to do
106 + },
107 +
108 + reportSpecStarting: function (spec) {
109 + // Start timing this spec
110 + spec.startedAt = new Date();
111 + },
112 +
113 + reportSpecResults: function (spec) {
114 + // Finish timing this spec and calculate duration/delta (in sec)
115 + spec.finishedAt = new Date();
116 + spec.durationSec = elapsedSec(spec.startedAt.getTime(), spec.finishedAt.getTime());
117 + },
118 +
119 + reportSuiteResults: function (suite) {
120 + // Nothing to do
121 + },
122 +
123 + reportRunnerResults: function (runner) {
124 + var suites = runner.suites(),
125 + i, ilen;
126 +
127 + // Attach results to the "jasmine" object to make those results easy to scrap/find
128 + jasmine.runnerResults = {
129 + suites: [],
130 + durationSec : 0,
131 + passed : true
132 + };
133 +
134 + // Loop over all the Suites
135 + for (i = 0, ilen = suites.length; i < ilen; ++i) {
136 + if (suites[i].parentSuite === null) {
137 + jasmine.runnerResults.suites[i] = getSuiteData(suites[i]);
138 + // If 1 suite fails, the whole runner fails
139 + jasmine.runnerResults.passed = !jasmine.runnerResults.suites[i].passed ? false : jasmine.runnerResults.passed;
140 + // Add up all the durations
141 + jasmine.runnerResults.durationSec += jasmine.runnerResults.suites[i].durationSec;
142 + }
143 + }
144 +
145 + // Decorate the 'jasmine' object with getters
146 + jasmine.getJSReport = function () {
147 + if (jasmine.runnerResults) {
148 + return jasmine.runnerResults;
149 + }
150 + return null;
151 + };
152 + jasmine.getJSReportAsString = function () {
153 + return JSON.stringify(jasmine.getJSReport());
154 + };
155 + }
156 + };
157 +
158 + // export public
159 + jasmine.JSReporter = JSReporter;
160 +})();
161 +