Commit ab1ee319 ab1ee319d3f268e34819a5703bde51a2bca6f6ea by Nicolas Perriault

fixed unability to handle event errors in tests

1 parent 0c39e151
......@@ -2086,13 +2086,13 @@ function createPage(casper) {
casper.emit('load.finished', status);
casper.loadInProgress = false;
};
page.onNavigationRequested = function onNavigationRequested(url, navigationType, navigationLocked, isMainFrame) {
page.onNavigationRequested = function onNavigationRequested(url, type, lock, isMainFrame) {
casper.log(f('Navigation requested: url=%s, type=%s, lock=%s, isMainFrame=%s',
url, navigationType, navigationLocked, isMainFrame), "debug");
if(isMainFrame) {
url, type, lock, isMainFrame), "debug");
if (isMainFrame) {
casper.navigationRequested = true;
}
casper.emit('navigation.requested', url, navigationType, navigationLocked, isMainFrame);
casper.emit('navigation.requested', url, type, lock, isMainFrame);
};
page.onPageCreated = function onPageCreated(popupPage) {
casper.emit('popup.created', popupPage);
......
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
/*!
* Casper is a navigation utility for PhantomJS.
*
* Documentation: http://casperjs.org/
* Repository: http://github.com/n1k0/casperjs
*
* Copyright (c) 2011-2012 Nicolas Perriault
*
* Part of source code is Copyright Joyent, Inc. and other Node contributors.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/*global CasperError*/
......@@ -41,7 +50,7 @@ EventEmitter.prototype.setMaxListeners = function(n) {
};
EventEmitter.prototype.emit = function() {
EventEmitter.prototype.emit = function emit() {
var type = arguments[0];
// If there is no 'error' event listener then throw.
if (type === 'error') {
......@@ -60,24 +69,28 @@ EventEmitter.prototype.emit = function() {
var handler = this._events[type];
if (!handler) return false;
if (typeof handler == 'function') {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
var l = arguments.length;
var args = new Array(l - 1);
for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
handler.apply(this, args);
if (typeof handler === 'function') {
try {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
var l = arguments.length;
var args = new Array(l - 1);
for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
handler.apply(this, args);
}
} catch (err) {
this.emit('event.error', err);
}
return true;
......@@ -99,7 +112,7 @@ EventEmitter.prototype.emit = function() {
// EventEmitter is defined in src/node_events.cc
// EventEmitter.prototype.emit() is also defined there.
EventEmitter.prototype.addListener = function(type, listener) {
EventEmitter.prototype.addListener = function addListener(type, listener) {
if ('function' !== typeof listener) {
throw new CasperError('addListener only takes instances of Function');
}
......@@ -146,7 +159,7 @@ EventEmitter.prototype.addListener = function(type, listener) {
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
EventEmitter.prototype.once = function once(type, listener) {
if ('function' !== typeof listener) {
throw new CasperError('.once only takes instances of Function');
}
......@@ -155,7 +168,7 @@ EventEmitter.prototype.once = function(type, listener) {
function g() {
self.removeListener(type, g);
listener.apply(this, arguments);
};
}
g.listener = listener;
self.on(type, g);
......@@ -163,7 +176,7 @@ EventEmitter.prototype.once = function(type, listener) {
return this;
};
EventEmitter.prototype.removeListener = function(type, listener) {
EventEmitter.prototype.removeListener = function removeListener(type, listener) {
if ('function' !== typeof listener) {
throw new CasperError('removeListener only takes instances of Function');
}
......@@ -186,7 +199,7 @@ EventEmitter.prototype.removeListener = function(type, listener) {
if (position < 0) return this;
list.splice(position, 1);
if (list.length == 0)
if (list.length === 0)
delete this._events[type];
} else if (list === listener ||
(list.listener && list.listener === listener))
......@@ -197,7 +210,7 @@ EventEmitter.prototype.removeListener = function(type, listener) {
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) {
if (arguments.length === 0) {
this._events = {};
return this;
......@@ -208,7 +221,7 @@ EventEmitter.prototype.removeAllListeners = function(type) {
return this;
};
EventEmitter.prototype.listeners = function(type) {
EventEmitter.prototype.listeners = function listeners(type) {
if (!this._events) this._events = {};
if (!this._events[type]) this._events[type] = [];
if (!isArray(this._events[type])) {
......@@ -218,21 +231,21 @@ EventEmitter.prototype.listeners = function(type) {
};
// Added for CasperJS: filters a value attached to an event
EventEmitter.prototype.filter = function() {
EventEmitter.prototype.filter = function filter() {
var type = arguments[0];
if (!this._filters) {
this._filters = {};
return;
}
var filter = this._filters[type];
if (typeof filter !== 'function') {
var _filter = this._filters[type];
if (typeof _filter !== 'function') {
return;
}
return filter.apply(this, Array.prototype.splice.call(arguments, 1));
return _filter.apply(this, Array.prototype.splice.call(arguments, 1));
};
EventEmitter.prototype.removeAllFilters = function(type) {
EventEmitter.prototype.removeAllFilters = function removeAllFilters(type) {
if (arguments.length === 0) {
this._filters = {};
return this;
......@@ -243,7 +256,7 @@ EventEmitter.prototype.removeAllFilters = function(type) {
return this;
};
EventEmitter.prototype.setFilter = function(type, filterFn) {
EventEmitter.prototype.setFilter = function setFilter(type, filterFn) {
if (!this._filters) {
this._filters = {};
}
......
......@@ -74,7 +74,7 @@ exports.create = function create(casper, options) {
*/
var Tester = function Tester(casper, options) {
"use strict";
/*jshint maxstatements:30*/
/*jshint maxstatements:99*/
if (!utils.isCasperObject(casper)) {
throw new CasperError("Tester needs a Casper instance");
......@@ -143,32 +143,37 @@ var Tester = function Tester(casper, options) {
// casper events
this.casper.on('error', function onCasperError(msg, backtrace) {
var line = 0;
if (msg.indexOf('AssertionError') === 0) {
});
function errorHandler(error, backtrace) {
if (error instanceof Error) {
if (error instanceof AssertionError) {
self.processAssertionError(error);
} else if (error.message !== self.SKIP_MESSAGE) {
self.uncaughtError(error, self.currentTestFile, error.line);
}
return self.done();
}
if (error.indexOf('AssertionError') === 0) {
return;
}
if (msg === self.SKIP_MESSAGE) {
this.warn(f('--fail-fast: aborted remaining tests in "%s"', self.currentTestFile));
if (error === self.SKIP_MESSAGE) {
casper.warn(f('--fail-fast: aborted remaining tests in "%s"', self.currentTestFile));
self.aborted = true;
return self.done();
}
var line = 0;
try {
line = backtrace.filter(function(entry) {
line = (backtrace || []).filter(function(entry) {
return self.currentTestFile === entry.file;
})[0].line;
} catch (e) {}
self.uncaughtError(msg, self.currentTestFile, line, backtrace);
self.uncaughtError(error, self.currentTestFile, line, backtrace);
self.done();
});
this.casper.on('step.error', function onStepError(error) {
if (error instanceof AssertionError) {
self.processAssertionError(error);
} else if (error.message !== self.SKIP_MESSAGE) {
self.uncaughtError(error, self.currentTestFile);
}
self.done();
});
}
this.casper.on('event.error', errorHandler);
this.casper.on('step.error', errorHandler);
this.casper.on('warn', function(warning) {
if (self.currentSuite) {
......@@ -935,7 +940,7 @@ Tester.prototype.exec = function exec(file) {
file = this.filter('exec.file', file) || file;
if (!fs.isFile(file) || !utils.isJsFile(file)) {
var e = new CasperError(f("Cannot exec %s: can only exec() files with .js or .coffee extensions", file));
e.fileName = file;
e.fileName = e.file = e.sourceURL = file;
throw e;
}
this.currentTestFile = file;
......@@ -1038,8 +1043,7 @@ Tester.prototype.processAssertionError = function(error) {
result.line = stackEntry.line;
try {
result.lineContents = fs.read(this.currentTestFile).split('\n')[result.line - 1].trim();
} catch (e) {
}
} catch (e) {}
}
return this.processAssertionResult(result);
};
......@@ -1049,7 +1053,7 @@ Tester.prototype.processAssertionError = function(error) {
* printing result onto the console.
*
* @param Object result An assertion result object
* @return Object The passed assertion result Object
* @return Object The passed assertion result Object
*/
Tester.prototype.processAssertionResult = function processAssertionResult(result) {
"use strict";
......
......@@ -12,12 +12,12 @@ function fetchUA(request) {
}).pop().value, /plop/);
}
casper.test.begin('userAgent() tests', 3, function(test) {
casper.test.begin('userAgent() tests', 2, function(test) {
testUA(casper.options.pageSettings.userAgent, /CasperJS/);
casper.start();
casper.userAgent('plop').on('resource.requested', fetchUA);
casper.thenOpen('tests/site/index.html').run(function() {
this.removeListener('resource.requested', fetchUA);
casper.userAgent('plop').once('resource.requested', fetchUA);
casper.thenOpen('tests/site/index.html');
casper.run(function() {
test.done();
});
});
......
......@@ -2,11 +2,13 @@
/*jshint strict:false*/
casper.test.begin('alert events', 1, function(test) {
var ok = false;
casper.on('remote.alert', function(message) {
casper.once('remote.alert', function(message) {
ok = message === 'plop';
});
casper.start('tests/site/alert.html').run(function() {
this.test.assert(ok, 'alert event has been intercepted');
casper.start('tests/site/alert.html', function() {
test.assert(ok, 'alert event has been intercepted');
});
casper.run(function() {
this.removeAllListeners('remote.alert');
test.done();
});
......
......@@ -2,7 +2,7 @@
/*jshint strict:false*/
casper.test.begin('events', 2, function(test) {
casper.plopped = false;
casper.on("plop", function() {
casper.once("plop", function() {
this.plopped = true;
});
test.assert(Object.keys(casper._events).some(function(i) {
......
......@@ -2,7 +2,7 @@
/*jshint strict:false*/
casper.test.begin('page.error event tests', 2, function(test) {
var error = {};
casper.on("page.error", function onError(msg, trace) {
casper.once("page.error", function onError(msg, trace) {
error.msg = msg;
error.trace = trace;
});
......
......@@ -3,14 +3,14 @@
var utils = require('utils');
var x = require('casper').selectXPath;
casper.test.begin('popup tests', 25, function(test) {
casper.on('popup.created', function(popup) {
casper.test.begin('popup tests', 20, function(test) {
casper.once('popup.created', function(popup) {
test.pass('"popup.created" event is fired');
test.assert(utils.isWebPage(popup),
'"popup.created" event callback get a popup page instance');
});
casper.on('popup.loaded', function(popup) {
casper.once('popup.loaded', function(popup) {
test.pass('"popup.loaded" event is fired');
test.assertEquals(popup.evaluate(function() {
return document.title;
......@@ -18,7 +18,7 @@ casper.test.begin('popup tests', 25, function(test) {
'"popup.loaded" is triggered when popup content is actually loaded');
});
casper.on('popup.closed', function(popup) {
casper.once('popup.closed', function(popup) {
test.assertEquals(this.popups.length, 0, '"popup.closed" event is fired');
});
......