Skip to content

Commit

Permalink
Initial commit - the files needed to get started writing functional t…
Browse files Browse the repository at this point in the history
…ests with Phantom Mochachino
  • Loading branch information
Thomas Clowes committed Sep 13, 2014
1 parent 6b20eec commit f0c8236
Show file tree
Hide file tree
Showing 7 changed files with 2,999 additions and 0 deletions.
136 changes: 136 additions & 0 deletions FunctionalTestRunner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*!
* Phantom Mochachino
* http://doublenegative.com/phantom-mochachino
*
* Copyright 2014 Thomas Clowes <[email protected]>
* Released under the MIT license
*/

var page = require("webpage").create();
var args = require('system').args;
var config = require('./config/phantom-mochachino-config.json');

//phantom - args immutable, so make a copy
var mochachinoArgs = args.slice();

var script = mochachinoArgs.shift();
var testFile = mochachinoArgs.shift();
var pageAddress = mochachinoArgs.shift();

var stateObj = [];
var argsToInject = mochachinoArgs;

var testStatus = 0;

if (typeof testFile === 'undefined') {
console.error("Did not specify a test file");
phantom.exit();
}

var injectTestDependencies = function() {
page.injectJs(config.paths.mocha);
page.injectJs(config.paths.mochachinoInterface);
page.injectJs(config.paths.assertionLibrary);

page.injectJs(config.paths.reporter);

page.injectJs(config.paths.helpers);
page.injectJs(config.paths.testBase + testFile);
}

page.open(config.siteUrl + pageAddress);

var pages = 0;

page.onCallback = function(data) {

if (typeof data.executedItems !== 'undefined') {
stateObj = data.executedItems;

if (typeof data.differentPath !== 'undefined') {
setTimeout(function() {
page.reload();
}, 1000);
}

} else if (typeof data.status !== 'undefined') {
testStatus = data.status;
} else if (typeof data.exit !== 'undefined') {
phantom.exit(testStatus);
} else {
data.message && console.log(data.message);
}
};

var hasNewUrl = true;

page.onUrlChanged = function(targetUrl) {
hasNewUrl = true;
};

page.onConsoleMessage = function(msg, lineNum, sourceId) {
if (config.debug) {
console.log('CONSOLE: ' + msg + ' (from line #' + lineNum + ' in "' + sourceId + '")');
}
};

page.onResourceRequested = function(requestData, networkRequest) {

};

page.onResourceError = function(resourceError) {
if (config.debug) {
console.log('Unable to load resource (#' + resourceError.id + 'URL:' + resourceError.url + ')');
console.log('Error code: ' + resourceError.errorCode + '. Description: ' + resourceError.errorString);
}
};

page.onResourceReceived = function(response) {
if (config.debug) {
console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + JSON.stringify(response));
}
};

page.onResourceTimeout = function(request) {
if (config.debug) {
console.log('Response (#' + request.id + '): ' + JSON.stringify(request));
}
};


page.onLoadStarted = function(status) {
};

page.onLoadFinished = function(status) {

if (hasNewUrl) {

pages++;

if (pages > 1) {
console.log('//////////////////////////////////');
console.log('///////// CHANGING PAGES /////////');
console.log('//////////////////////////////////');
}

if (status !== 'success') {
console.error("Failed to open", page.frameUrl);
phantom.exit();
}

page.injectJs("mochachino.js");

page.evaluate(function(stateObj, argsToInject) {
window.mochachino.setup(stateObj);
window.mochachino.injectArgs(argsToInject);
}, stateObj, argsToInject);

injectTestDependencies();

page.evaluate(function() {
window.mocha.run();
});

hasNewUrl = false;
}
};
71 changes: 71 additions & 0 deletions helpers/FunctionalTestHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*!
* Phantom Mochachino
* http://doublenegative.com/phantom-mochachino
*
* Copyright 2014 Thomas Clowes <[email protected]>
* Released under the MIT license
*/

//Helper for asynchronous tests
//Adapted from the example within the PhantomJS source code
//https://github.com/ariya/phantomjs/blob/master/examples/waitfor.js
function waitFor(testFx, onReady, timeOutMillis, onTimeout) {
var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< 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 = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
} else {
if(!condition) {
// If condition still not fulfilled (timeout but condition is 'false')
console.log("'waitFor()' timeout");
typeof(onTimeout) === "string" ? eval(onTimeout) : onTimeout();
clearInterval(interval);
//phantom.exit(1);
} else {
clearInterval(interval); //< Stop this interval
// Condition fulfilled (timeout and/or condition is 'true')
console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
}
}
}, 250); //< repeat check every 250ms
};


// Phantom has issues with jQuery for some things.
// You can dispatch your own click event using this.
function click(el){
var ev = document.createEvent("MouseEvent");
ev.initMouseEvent(
"click",
true /* bubble */, true /* cancelable */,
window, null,
0, 0, 0, 0, /* coordinates */
false, false, false, false, /* modifier keys */
0 /*left*/, null
);
el.dispatchEvent(ev);
}

//Random string helper
function randomString() { var s=Math.random().toString(36).slice(2); return s.length===16 ? s : randomString(); }

//Helpers for manipulating React components
function changeReactiveInput(elementId, newValue) {
var TestUtils = PJLib.React.addons.TestUtils;

var input = TestUtils.findRenderedDOMComponentWithProp(r, 'id', elementId);

$("#" + elementId).val(newValue);
TestUtils.Simulate.change(input);
}

function clickReactiveButton(elementId) {
var TestUtils = PJLib.React.addons.TestUtils;
var button = TestUtils.findRenderedDOMComponentWithProp(r, 'id', elementId);

TestUtils.Simulate.click(button);
}
7 changes: 7 additions & 0 deletions interfaces/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Phantom Mochachino runs in the browser - in the PhantomJS browser.

The interface was browserified from src using browserify and the following command:

browserify src/mochachino-bss.js -o mochachino-bdd.js

Make sure that you update the require paths within src/mochachino-bdd.js to point to the respective mocha files if you wish to take this route.
Loading

0 comments on commit f0c8236

Please sign in to comment.