Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added scripts to run the unit tests with phantomjs.

  • Loading branch information...
commit 7e2b24cf7fcba72ef8a6dc2d1b31cfd7236e09d6 1 parent c05600a
@winhamwr winhamwr authored
View
6 README.md
@@ -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:
View
4 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
View
81 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
+ );
+ }
+});
View
8 src/test/unit/index.html
@@ -55,6 +55,7 @@
"../../wymeditor/plugins/table/jquery.wymeditor.table.js",
"qunit.js",
+ "qunit-tap.js",
// Test files
"utils.js",
@@ -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>
View
188 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;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.