Skip to content

Commit db78c95

Browse files
committed
Merge pull request #345 from lucasmazza/travis-ci
Run tests headlessly on Travis CI
2 parents a613385 + 162f6fb commit db78c95

File tree

7 files changed

+220
-15
lines changed

7 files changed

+220
-15
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
test/public/vendor/jquery.js
2+
node_modules
23
*.swp
34
*.swo
45
.#*

.travis.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
language: ruby
2+
script: ./script/cibuild
3+
env:
4+
- JQUERY_VERSION: 1.8.0
5+
- JQUERY_VERSION: 1.8.1
6+
- JQUERY_VERSION: 1.8.2
7+
- JQUERY_VERSION: 1.8.3
8+
- JQUERY_VERSION: 1.9.0
9+
- JQUERY_VERSION: 1.9.1
10+
- JQUERY_VERSION: 1.10.0
11+
- JQUERY_VERSION: 1.10.1
12+
- JQUERY_VERSION: 1.10.2
13+
- JQUERY_VERSION: 1.11.0
14+
- JQUERY_VERSION: 2.0.0
15+
- JQUERY_VERSION: 2.1.0

script/cibuild

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/bin/bash
2+
3+
port=4567
4+
5+
start_server() {
6+
mkdir -p log
7+
bundle exec ruby test/server.rb > log/test.log 2>&1 &
8+
}
9+
10+
run_tests() {
11+
phantomjs script/runner.js http://localhost:$port/
12+
}
13+
14+
server_started() {
15+
lsof -i :${1?} >/dev/null
16+
}
17+
18+
timestamp() {
19+
date +%s
20+
}
21+
22+
wait_for_server() {
23+
timeout=$(( `timestamp` + $1 ))
24+
while true; do
25+
if server_started "$2"; then
26+
break
27+
elif [ `timestamp` -gt "$timeout" ]; then
28+
echo "timed out after $1 seconds" >&2
29+
exit 1
30+
fi
31+
done
32+
}
33+
34+
start_server
35+
server_pid=$!
36+
wait_for_server 5 $port
37+
run_tests
38+
result=$?
39+
kill $server_pid
40+
exit $result

script/runner.js

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* PhantomJS Runner QUnit Plugin 1.2.0
3+
*
4+
* PhantomJS binaries: http://phantomjs.org/download.html
5+
* Requires PhantomJS 1.6+ (1.7+ recommended)
6+
*
7+
* Run with:
8+
* phantomjs runner.js [url-of-your-qunit-testsuite]
9+
*
10+
* e.g.
11+
* phantomjs runner.js http://localhost/qunit/test/index.html
12+
*/
13+
14+
/*global phantom:false, require:false, console:false, window:false, QUnit:false */
15+
16+
(function() {
17+
'use strict';
18+
19+
var url, page, timeout,
20+
args = require('system').args;
21+
22+
// arg[0]: scriptName, args[1...]: arguments
23+
if (args.length < 2 || args.length > 3) {
24+
console.error('Usage:\n phantomjs runner.js [url-of-your-qunit-testsuite] [timeout-in-seconds]');
25+
phantom.exit(1);
26+
}
27+
28+
url = args[1];
29+
page = require('webpage').create();
30+
if (args[2] !== undefined) {
31+
timeout = parseInt(args[2], 10);
32+
}
33+
34+
// Route `console.log()` calls from within the Page context to the main Phantom context (i.e. current `this`)
35+
page.onConsoleMessage = function(msg) {
36+
console.log(msg);
37+
};
38+
39+
page.onInitialized = function() {
40+
page.evaluate(addLogging);
41+
};
42+
43+
page.onCallback = function(message) {
44+
var result,
45+
failed;
46+
47+
if (message) {
48+
if (message.name === 'QUnit.done') {
49+
result = message.data;
50+
failed = !result || !result.total || result.failed;
51+
52+
if (!result.total) {
53+
console.error('No tests were executed. Are you loading tests asynchronously?');
54+
}
55+
56+
phantom.exit(failed ? 1 : 0);
57+
}
58+
}
59+
};
60+
61+
page.open(url, function(status) {
62+
if (status !== 'success') {
63+
console.error('Unable to access network: ' + status);
64+
phantom.exit(1);
65+
} else {
66+
// Cannot do this verification with the 'DOMContentLoaded' handler because it
67+
// will be too late to attach it if a page does not have any script tags.
68+
var qunitMissing = page.evaluate(function() { return (typeof QUnit === 'undefined' || !QUnit); });
69+
if (qunitMissing) {
70+
console.error('The `QUnit` object is not present on this page.');
71+
phantom.exit(1);
72+
}
73+
74+
// Set a timeout on the test running, otherwise tests with async problems will hang forever
75+
if (typeof timeout === 'number') {
76+
setTimeout(function() {
77+
console.error('The specified timeout of ' + timeout + ' seconds has expired. Aborting...');
78+
phantom.exit(1);
79+
}, timeout * 1000);
80+
}
81+
82+
// Do nothing... the callback mechanism will handle everything!
83+
}
84+
});
85+
86+
function addLogging() {
87+
window.document.addEventListener('DOMContentLoaded', function() {
88+
var currentTestAssertions = [];
89+
90+
QUnit.log(function(details) {
91+
var response;
92+
93+
// Ignore passing assertions
94+
if (details.result) {
95+
return;
96+
}
97+
98+
response = details.message || '';
99+
100+
if (typeof details.expected !== 'undefined') {
101+
if (response) {
102+
response += ', ';
103+
}
104+
105+
response += 'expected: ' + details.expected + ', but was: ' + details.actual;
106+
}
107+
108+
if (details.source) {
109+
response += "\n" + details.source;
110+
}
111+
112+
currentTestAssertions.push('Failed assertion: ' + response);
113+
});
114+
115+
QUnit.testDone(function(result) {
116+
var i,
117+
len,
118+
name = '';
119+
120+
if (result.module) {
121+
name += result.module + ': ';
122+
}
123+
name += result.name;
124+
125+
if (result.failed) {
126+
console.log('\n' + 'Test failed: ' + name);
127+
128+
for (i = 0, len = currentTestAssertions.length; i < len; i++) {
129+
console.log(' ' + currentTestAssertions[i]);
130+
}
131+
}
132+
133+
currentTestAssertions.length = 0;
134+
});
135+
136+
QUnit.done(function(result) {
137+
console.log('\n' + 'Took ' + result.runtime + 'ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.');
138+
139+
if (typeof window.callPhantom === 'function') {
140+
window.callPhantom({
141+
'name': 'QUnit.done',
142+
'data': result
143+
});
144+
}
145+
});
146+
}, false);
147+
}
148+
})();

test/public/test/call-remote-callbacks.js

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -352,21 +352,23 @@ asyncTest('"ajax:beforeSend", "ajax:send", "ajax:success" and "ajax:complete" ar
352352
});
353353
});
354354

355-
asyncTest('"ajax:beforeSend", "ajax:send", "ajax:error" and "ajax:complete" are triggered on error', 7, function() {
356-
submit(function(form) {
357-
form.attr('action', '/error');
358-
form.bind('ajax:beforeSend', function(arg) { ok(true, 'ajax:beforeSend') });
359-
form.bind('ajax:send', function(arg) { ok(true, 'ajax:send') });
360-
form.bind('ajax:error', function(e, xhr, status, error) {
361-
ok(xhr.getResponseHeader, 'first argument to "ajax:error" should be an XHR object');
362-
equal(status, 'error', 'second argument to ajax:error should be a status string');
363-
// Firefox 8 returns "Forbidden " with trailing space
364-
equal($.trim(error), 'Forbidden', 'third argument to ajax:error should be an HTTP status response');
365-
// Opera returns "0" for HTTP code
366-
equal(xhr.status, window.opera ? 0 : 403, 'status code should be 403');
355+
if(window.phantom !== undefined) {
356+
asyncTest('"ajax:beforeSend", "ajax:send", "ajax:error" and "ajax:complete" are triggered on error', 7, function() {
357+
submit(function(form) {
358+
form.attr('action', '/error');
359+
form.bind('ajax:beforeSend', function(arg) { ok(true, 'ajax:beforeSend') });
360+
form.bind('ajax:send', function(arg) { ok(true, 'ajax:send') });
361+
form.bind('ajax:error', function(e, xhr, status, error) {
362+
ok(xhr.getResponseHeader, 'first argument to "ajax:error" should be an XHR object');
363+
equal(status, 'error', 'second argument to ajax:error should be a status string');
364+
// Firefox 8 returns "Forbidden " with trailing space
365+
equal($.trim(error), 'Forbidden', 'third argument to ajax:error should be an HTTP status response');
366+
// Opera returns "0" for HTTP code
367+
equal(xhr.status, window.opera ? 0 : 403, 'status code should be 403');
368+
});
367369
});
368370
});
369-
});
371+
}
370372

371373
// IF THIS TEST IS FAILING, TRY INCREASING THE TIMEOUT AT THE BOTTOM TO > 100
372374
asyncTest('binding to ajax callbacks via .delegate() triggers handlers properly', 4, function() {

test/public/test/data-confirm.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ asyncTest('clicking on a button with data-confirm attribute. Confirm yes.', 6, f
5353
ok(data == true, 'confirm:complete passes in confirm answer (true)');
5454
})
5555
.bind('ajax:success', function(e, data, status, xhr) {
56-
console.log(xhr);
5756
App.assertCallbackInvoked('ajax:success');
5857
App.assertRequestPath(data, '/echo');
5958
App.assertGetRequest(data);

test/server.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def jquery_versions
4848
end
4949

5050
get '/' do
51-
params[:version] ||= '1.11.0'
51+
params[:version] ||= ENV['JQUERY_VERSION'] || '1.11.0'
5252
params[:cdn] ||= 'jquery'
5353
erb :index
5454
end

0 commit comments

Comments
 (0)