Skip to content

Commit a8fd027

Browse files
author
Piyush Ranjan
committed
Added mocha and jasmine support
1 parent d56410e commit a8fd027

File tree

5 files changed

+290
-1
lines changed

5 files changed

+290
-1
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ If nothing is provided as `preset` **default** is used.
3535
- *test_path*: Path to the which will execute the tests when opened
3636
in a browser.
3737

38+
- *test_framework*: Specify test framework which will execute the tests.
39+
We support qunit, jasmine and mocha.
40+
3841
- *browsers*: A list of browsers on which tests are to be run.
3942

4043
A sample configuration file:
@@ -43,6 +46,7 @@ A sample configuration file:
4346
"username": "<username>",
4447
"key": "<key>",
4548
"test_path": "relative/path/to/test/page",
49+
"test_framework": "qunit/jasmine/mocha",
4650
"browsers": [{
4751
"browser": "firefox",
4852
"browser_version": "15.0",

lib/_patch/jasmine-jsreporter.js

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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, [email protected]
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+

lib/_patch/jasmine-plugin.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
(function(){
2+
function countSpecs(suite, results){
3+
suite.specs.forEach(function(s){
4+
if(s.passed){
5+
results.passed++;
6+
}else{
7+
results.tracebacks.push(s.description);
8+
results.failed++;
9+
}
10+
});
11+
suite.suites.forEach(function(s){
12+
results = countSpecs(s, results);
13+
});
14+
return(results);
15+
}
16+
17+
var checker = setInterval(function(){
18+
if(!jasmine.running){
19+
var results = {}
20+
var report = jasmine.getJSReport()
21+
var errors = [];
22+
results.runtime = report.durationSec * 1000;
23+
results.total=0;
24+
results.passed=0;
25+
results.failed=0;
26+
results.tracebacks=[];
27+
28+
jasmine.getJSReport().suites.forEach(function(suite){
29+
results = countSpecs(suite, results);
30+
});
31+
results.total = results.passed + results.failed;
32+
33+
results.url = window.location.pathname;
34+
BrowserStack.post("/_report", results, function(){});
35+
}
36+
clearInterval(checker);
37+
}, 1000);
38+
})();
39+

lib/_patch/mocha-plugin.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
(function(){
2+
function stack(err) {
3+
var str = err.stack || err.toString();
4+
5+
if (!~str.indexOf(err.message)) {
6+
str = err.message + '\n' + str;
7+
}
8+
9+
if ('[object Error]' == str) {
10+
str = err.message;
11+
}
12+
13+
if (!err.stack && err.sourceURL && err.line !== undefined) {
14+
str += '\n(' + err.sourceURL + ':' + err.line + ')';
15+
}
16+
return str.replace(/^/gm, ' ');
17+
}
18+
19+
function title(test) {
20+
return test.fullTitle().replace(/#/g, '');
21+
}
22+
23+
return Mocha.BrowserStack = function (runner, root) {
24+
Mocha.reporters.HTML.call(this, runner, root);
25+
26+
var count = 1,
27+
that = this,
28+
failures = 0,
29+
passes = 0,
30+
start = 0,
31+
tracebacks = [];
32+
33+
runner.on('start', function () {
34+
start = (new Date).getTime();
35+
});
36+
37+
runner.on('test end', function (test) {
38+
count += 1;
39+
});
40+
41+
runner.on('pass', function (test) {
42+
passes += 1;
43+
});
44+
45+
runner.on('fail', function (test, err) {
46+
failures += 1;
47+
48+
if (err) {
49+
tracebacks.push(err);
50+
}
51+
});
52+
53+
runner.on('end', function () {
54+
results = {}
55+
results.runtime = ((new Date).getTime() - start);
56+
results.total = passes + failures;
57+
results.passed = passes;
58+
results.failed = failures;
59+
results.tracebacks = tracebacks;
60+
results.url = window.location.pathname;
61+
BrowserStack.post("/_report", results, function(){});
62+
});
63+
};
64+
})();

lib/server.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,36 @@ exports.Server = function Server(bsClient, workers) {
5252
scripts = [
5353
'json2.js',
5454
'browserstack.js',
55-
'qunit-plugin.js'
5655
]
5756

57+
framework_scripts = {'qunit': ['qunit-plugin.js'],
58+
'jasmine': ['jasmine-jsreporter.js', 'jasmine-plugin.js'],
59+
'mocha': ['mocha-plugin.js']
60+
}
61+
5862
if (mimeType === 'text/html') {
5963
var matcher = /(.*)<\/body>/;
6064
var patch = "$1";
6165
scripts.forEach(function (script) {
6266
patch += "<script type='text/javascript' src='/_patch/" + script + "'></script>\n";
6367
});
68+
69+
// adding framework scripts
70+
if(config['test_framework'] && config['test_framework']=="jasmine"){
71+
framework_scripts['jasmine'].forEach(function (script) {
72+
patch += "<script type='text/javascript' src='/_patch/" + script + "'></script>\n";
73+
});
74+
patch +="<script type='text/javascript'>jasmine.getEnv().addReporter(new jasmine.JSReporter());</script>\n";
75+
}else if(config['test_framework'] && config['test_framework']=="mocha"){
76+
framework_scripts['mocha'].forEach(function (script) {
77+
patch += "<script type='text/javascript' src='/_patch/" + script + "'></script>\n";
78+
});
79+
patch +="<script type='text/javascript'>mocha.reporter(Mocha.BrowserStack);</script>\n";
80+
}else{
81+
framework_scripts['qunit'].forEach(function (script) {
82+
patch += "<script type='text/javascript' src='/_patch/" + script + "'></script>\n";
83+
});
84+
}
6485
patch += "</body>";
6586

6687
file = file.replace(matcher, patch);

0 commit comments

Comments
 (0)