Skip to content
This repository has been archived by the owner on Apr 2, 2021. It is now read-only.

Commit

Permalink
Added scripts to run the unit tests with phantomjs.
Browse files Browse the repository at this point in the history
  • Loading branch information
winhamwr committed Jan 26, 2012
1 parent c05600a commit 7e2b24c
Show file tree
Hide file tree
Showing 5 changed files with 287 additions and 0 deletions.
6 changes: 6 additions & 0 deletions README.md
Expand Up @@ -120,6 +120,12 @@ the python instructions, open up your browser to

All green means you're good to go.

4. Want to run the tests from the command line? You can do that to! Just install
[PhantomJS](http://www.phantomjs.org/) and then (if you used the http server
from step 2) call:

$ build/phantomjs_test.sh localhost:8000/test/unit

### Building WYMeditor

1. Get a copy of the source using git:
Expand Down
4 changes: 4 additions & 0 deletions build/phantomjs_test.sh
@@ -0,0 +1,4 @@
#!/bin/sh
UNIT_TEST_URL=http://$1/index.html?tapOutput=true;
BUILD_DIR="`dirname \"$0\"`"
phantomjs $BUILD_DIR/run_qunit.js $UNIT_TEST_URL
81 changes: 81 additions & 0 deletions build/run_qunit.js
@@ -0,0 +1,81 @@
/**
* Wait until the test condition is true or a timeout occurs. Useful for waiting
* on a server response or for a ui change (fadeIn, etc.) to occur.
*
* @param testFx Callback that evaluates to a boolean,
* @param onReady Callback to execute on succesful completion
* @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
*/
function waitFor(testFx, onReady, timeOutMillis) {
var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< Default Max Timout is 3s
start = new Date().getTime(),
condition = false,
interval = setInterval(function() {
if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
// If not time-out yet and condition not yet fulfilled
condition = testFx();
} else {
if(!condition) {
// If condition still not fulfilled (timeout but condition is 'false')
console.log("# 'waitFor()' timeout");
phantom.exit(1);
} else {
// Condition fulfilled (timeout and/or condition is 'true')
// console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
onReady(); //< Do what it's supposed to do once the condition is fulfilled
clearInterval(interval); //< Stop this interval
}
}
}, 100); //< repeat check every 100ms
}


if (phantom.args.length === 0 || phantom.args.length > 2) {
console.log('Usage: run-qunit.js URL');
phantom.exit(1);
}

var page = new WebPage();

// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = function(msg) {
console.log(msg);
};

// Open the URL of the first argument, wait for the results to finish and then output a summary.
// Exists with 0 on success, 1 with failures, 2 with a phantomjs error
page.open(phantom.args[0], function(status){
if (status !== "success") {
console.log("Unable to access network");
phantom.exit(2);
} else {
waitFor(
function(){
return page.evaluate(function(){
var el = document.getElementById('qunit-testresult');
if (el && el.innerText.match('completed')) {
return true;
}
return false;
});
},
function(){
// Output the summary and return 1 if it was an all-pass
var returnCode = page.evaluate(function() {
var failString = '';
var results = document.getElementById('qunit-testresult');
console.log(results.innerText);
try {
failString = el.getElementsByClassName('failed')[0].innerHTML;
} catch (e) { }
if (parseInt(failString, 10) > 0) {
return 1; // Failures
}
return 0; // All pass
});
phantom.exit(returnCode);
},
15000 // 15 seconds timeout
);
}
});
8 changes: 8 additions & 0 deletions src/test/unit/index.html
Expand Up @@ -55,6 +55,7 @@
"../../wymeditor/plugins/table/jquery.wymeditor.table.js",

"qunit.js",
"qunit-tap.js",

// Test files
"utils.js",
Expand All @@ -67,6 +68,13 @@
urlParams['jquery']
);
</script>
<script>
if (urlParams.tapOutput) {
// Only provide tap output when ?tapOutput=true
// When running via phantomJS, use that URL
qunitTap(QUnit, function() { console.log.apply(console, arguments); }, {noPlan: true});
}
</script>
</head>

<body>
Expand Down
188 changes: 188 additions & 0 deletions src/test/unit/qunit-tap.js
@@ -0,0 +1,188 @@
/**
* QUnit-TAP - A TAP Output Producer Plugin for QUnit
*
* http://github.com/twada/qunit-tap
* version: 1.0.9
*
* Copyright (c) 2010, 2011, 2012 Takuto Wada
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPLv2 (GPL-LICENSE.txt) licenses.
*
* @param qunitObject QUnit object reference.
* @param printLikeFunction print-like function for TAP output (assumes line-separator is added by this function for each call).
* @param options configuration options to customize default behavior.
*/
var qunitTap = function qunitTap(qunitObject, printLikeFunction, options) {
var qunitTapVersion = '1.0.9',
initialCount,
multipleLoggingCallbacksSupported,
qu = qunitObject;

if (!qu) {
throw new Error('should pass QUnit object reference');
}
if (typeof printLikeFunction !== 'function') {
throw new Error('should pass print-like function');
}
if (typeof qu.tap !== 'undefined') {
return;
}

// borrowed from qunit.js
var extend = function (a, b) {
var prop;
for (prop in b) {
if (b.hasOwnProperty(prop)) {
if (typeof b[prop] === 'undefined') {
delete a[prop];
} else {
a[prop] = b[prop];
}
}
}
return a;
};

// using QUnit.tap as namespace.
qu.tap = extend(
{
count: 0,
noPlan: false,
showDetailsOnFailure: true
},
options
);
qu.tap.puts = printLikeFunction;
qu.tap.VERSION = qunitTapVersion;
initialCount = qu.tap.count || 0;

// detect QUnit's multipleCallbacks feature. see jquery/qunit@34f6bc1
multipleLoggingCallbacksSupported =
(typeof qu.config !== 'undefined'
&& typeof qu.config.log !== 'undefined'
&& typeof qu.config.done !== 'undefined'
&& typeof qu.config.moduleStart !== 'undefined'
&& typeof qu.config.testStart !== 'undefined');

// borrowed from prototype.js
// not required since QUnit.log receives raw data (details). see jquery/qunit@c2cde34
var stripTags = function (str) {
if (!str) {
return str;
}
return str.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
};

var commentAfterLineEnd = function (str) {
return str.replace(/(\r?\n)/g, '$&# ');
};

var formDescription = function (str) {
if (!str) {
return str;
}
return commentAfterLineEnd(' - ' + str);
};

var appendDetailsTo = function (desc, details) {
if (!qu.tap.showDetailsOnFailure || details.result) {
return desc;
}
if (typeof details.expected !== 'undefined') {
if (desc) {
desc += ', ';
}
desc += 'expected: \'';
desc += details.expected;
desc += '\' got: \'';
desc += details.actual;
desc += '\'';
}
return desc;
};

qu.tap.explain = function explain (str) {
if (typeof qu.jsDump !== 'undefined' && typeof qu.jsDump.parse === 'function') {
return qu.jsDump.parse(str);
} else {
return str;
}
};

qu.tap.note = function note (str) {
qu.tap.puts(commentAfterLineEnd('# ' + str));
};

qu.tap.diag = function diag (str) {
qu.tap.note(str);
return false;
};

qu.tap.moduleStart = function (arg) {
var name = (typeof arg === 'string') ? arg : arg.name;
qu.tap.note('module: ' + name);
};

qu.tap.testStart = function (arg) {
var name = (typeof arg === 'string') ? arg : arg.name;
qu.tap.note('test: ' + name);
};

qu.tap.log = function () {
var details, desc, testLine = '';
switch (arguments.length) {
case 1: // details
details = arguments[0];
break;
case 2: // result, message(with tags)
details = {result: arguments[0], message: stripTags(arguments[1])};
break;
case 3: // result, message, details
details = arguments[2];
break;
default:
throw new Error('QUnit-TAP does not support QUnit#log arguments like this.');
}
if (!details.result) {
testLine += 'not ';
}
testLine += 'ok ' + (qu.tap.count += 1);
if (details.result && !details.message) {
qu.tap.puts(testLine);
return;
}
desc = appendDetailsTo((details.message || ''), details);
qu.tap.puts(testLine + formDescription(desc));
};

// prop in arg: failed,passed,total,runtime
qu.tap.done = function (arg) {
if (!qu.tap.noPlan) {
return;
}
qu.tap.puts((initialCount + 1) + '..' + qu.tap.count);
};

var addListener = function (target, name, listener) {
var originalLoggingCallback = target[name];
if (multipleLoggingCallbacksSupported) {
originalLoggingCallback(listener);
} else if (typeof originalLoggingCallback === 'function') {
// add listener, not replacing former ones.
target[name] = function () {
var args = Array.prototype.slice.apply(arguments);
originalLoggingCallback.apply(target, args);
listener.apply(target, args);
};
}
};
addListener(qu, 'moduleStart', qu.tap.moduleStart);
addListener(qu, 'testStart', qu.tap.testStart);
addListener(qu, 'log', qu.tap.log);
addListener(qu, 'done', qu.tap.done);
};

if (typeof exports !== 'undefined' || typeof require !== 'undefined') {
// exports qunitTap function to CommonJS world
exports.qunitTap = qunitTap;
}

0 comments on commit 7e2b24c

Please sign in to comment.