diff --git a/src/exceptions/loggerRequired.js b/src/exceptions/loggerRequired.js new file mode 100644 index 0000000..ca312fe --- /dev/null +++ b/src/exceptions/loggerRequired.js @@ -0,0 +1,12 @@ +define(function(require) { + "use strict"; + + function LoggerRequiredException() { + this.message = 'This mogwai requires a logger to run. Please call logger(loggerObject) before executing the mogwai'; + this.toString = function() { + return this.message; + }; + } + + return LoggerRequiredException; +}); diff --git a/src/exceptions/randomizerRequired.js b/src/exceptions/randomizerRequired.js new file mode 100644 index 0000000..6044628 --- /dev/null +++ b/src/exceptions/randomizerRequired.js @@ -0,0 +1,12 @@ +define(function(require) { + "use strict"; + + function RandomizerRequiredException() { + this.message = 'This gremlin requires a randomizer to run. Please call randomizer(randomizerObject) before executing the gremlin'; + this.toString = function() { + return this.message; + }; + } + + return RandomizerRequiredException; +}); diff --git a/src/main.js b/src/main.js index 405df57..c2640eb 100644 --- a/src/main.js +++ b/src/main.js @@ -472,7 +472,7 @@ define(function(require) { function inject(services, objects) { for (var i = 0, count = objects.length; i < count; i++) { for (var name in services) { - if (typeof objects[i][name] === "function") { + if (typeof objects[i][name] === "function" && !objects[i][name]()) { objects[i][name](services[name]); } } diff --git a/src/mogwais/alert.js b/src/mogwais/alert.js index 36af0b4..d7a6b12 100644 --- a/src/mogwais/alert.js +++ b/src/mogwais/alert.js @@ -29,22 +29,21 @@ define(function(require) { var configurable = require('../utils/configurable'); var Chance = require('../vendor/chance'); + var LoggerRequiredException = require('../exceptions/loggerRequired'); return function() { var defaultWatchEvents = ['alert', 'confirm', 'prompt']; - var defaultConfirmResponse = function() { + function defaultConfirmResponse() { // Random OK or cancel return config.randomizer.bool(); - }; + } - var defaultPromptResponse = function() { + function defaultPromptResponse() { // Return a random string return config.randomizer.sentence(); - }; - - var defaultLogger = { warn: function() {} }; + } /** * @mixin @@ -53,8 +52,8 @@ define(function(require) { watchEvents: defaultWatchEvents, confirmResponse: defaultConfirmResponse, promptResponse: defaultPromptResponse, - logger: defaultLogger, - randomizer: new Chance() + logger: null, + randomizer: null }; var alert = window.alert; @@ -65,6 +64,11 @@ define(function(require) { * @mixes config */ function alertMogwai() { + + if (!config.logger) { + throw new LoggerRequiredException(); + } + if (config.watchEvents.indexOf('alert') !== -1) { window.alert = function (msg) { config.logger.warn('mogwai ', 'alert ', msg, 'alert'); diff --git a/src/mogwais/fps.js b/src/mogwais/fps.js index 8ae9074..dbddc86 100644 --- a/src/mogwais/fps.js +++ b/src/mogwais/fps.js @@ -30,20 +30,15 @@ define(function(require) { "use strict"; var configurable = require('../utils/configurable'); + var LoggerRequiredException = require('../exceptions/loggerRequired'); return function() { - var defaultLogger = { - log: function() {}, - warn: function() {}, - error: function() {} - }; - - var defaultLevelSelector = function(fps) { + function defaultLevelSelector(fps) { if (fps < 10) return 'error'; if (fps < 20) return 'warn'; return 'log'; - }; + } /** * @mixin @@ -51,7 +46,7 @@ define(function(require) { var config = { delay: 500, // how often should the fps be measured levelSelector: defaultLevelSelector, - logger: defaultLogger + logger: null }; var initialTime = -Infinity; // force initial measure @@ -84,6 +79,9 @@ define(function(require) { * @mixes config */ function fpsMogwai() { + if (!config.logger) { + throw new LoggerRequiredException(); + } enabled = true; window.requestAnimationFrame(loop); } diff --git a/src/mogwais/gizmo.js b/src/mogwais/gizmo.js index e10a582..3a5c9a7 100644 --- a/src/mogwais/gizmo.js +++ b/src/mogwais/gizmo.js @@ -26,14 +26,12 @@ define(function(require) { return function() { - var defaultLogger = { warn: function() {} }; - /** * @mixin */ var config = { maxErrors: 10, - logger: defaultLogger + logger: null }; var realOnError, realLoggerError; @@ -44,10 +42,11 @@ define(function(require) { function gizmoMogwai() { var nbErrors = 0; var horde = this; // this is exceptional - don't use 'this' for mogwais in general - function incrementNbErrors(){ + function incrementNbErrors() { nbErrors++; if (nbErrors == config.maxErrors) { horde.stop(); + if (!config.logger) return; window.setTimeout(function() { // display the mogwai error after the caught error config.logger.warn('mogwai ', 'gizmo ', 'stopped test execution after ', config.maxErrors, 'errors'); @@ -62,17 +61,17 @@ define(function(require) { return realOnError ? realOnError(message, url, linenumber) : false; }; - // console (or logger) errors - realLoggerError = config.logger.error; - config.logger.error = function() { + // console errors + realLoggerError = console.error; + console.error = function() { incrementNbErrors(); - realLoggerError.apply(config.logger, arguments); + realLoggerError.apply(console, arguments); }; } gizmoMogwai.cleanUp = function() { window.onerror = realOnError; - config.logger.error = realLoggerError.bind(config.logger); + console.error = realLoggerError.bind(console); return gizmoMogwai; }; diff --git a/src/species/clicker.js b/src/species/clicker.js index 0e0093e..141f2e5 100644 --- a/src/species/clicker.js +++ b/src/species/clicker.js @@ -49,6 +49,7 @@ define(function(require) { var configurable = require('../utils/configurable'); var Chance = require('../vendor/chance'); + var RandomizerRequiredException = require('../exceptions/randomizerRequired'); return function() { @@ -57,14 +58,14 @@ define(function(require) { var defaultClickTypes = ['click', 'click', 'click', 'click', 'click', 'click', 'dblclick', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseover', 'mouseover', 'mousemove', 'mouseout']; - var defaultPositionSelector = function() { + function defaultPositionSelector() { return [ config.randomizer.natural({ max: document.documentElement.clientWidth - 1 }), config.randomizer.natural({ max: document.documentElement.clientHeight - 1 }) ]; - }; + } - var defaultShowAction = function(x, y) { + function defaultShowAction(x, y) { var clickSignal = document.createElement('div'); clickSignal.style.border = "3px solid red"; clickSignal.style['border-radius'] = '50%'; // Chrome @@ -85,9 +86,11 @@ define(function(require) { setTimeout(function() { element.style.opacity = 0; }, 50); - }; + } - var defaultCanClick = function() { return true; }; + function defaultCanClick() { + return true; + } /** * @mixin @@ -98,14 +101,17 @@ define(function(require) { showAction: defaultShowAction, canClick: defaultCanClick, maxNbTries: 10, - logger: {}, - randomizer: new Chance() + logger: null, + randomizer: null }; /** * @mixes config */ function clickerGremlin() { + if (!config.randomizer) { + throw new RandomizerRequiredException(); + } var position, posX, posY, targetElement, nbTries = 0; do { position = config.positionSelector(); @@ -125,7 +131,7 @@ define(function(require) { config.showAction(posX, posY, clickType); } - if (typeof config.logger.log == 'function') { + if (config.logger && typeof config.logger.log == 'function') { config.logger.log('gremlin', 'clicker ', clickType, 'at', posX, posY); } } diff --git a/src/species/formFiller.js b/src/species/formFiller.js index 6a2a486..2e37142 100644 --- a/src/species/formFiller.js +++ b/src/species/formFiller.js @@ -24,6 +24,7 @@ define(function(require) { var configurable = require('../utils/configurable'); var Chance = require('../vendor/chance'); + var RandomizerRequiredException = require('../exceptions/randomizerRequired'); return function() { @@ -41,7 +42,7 @@ define(function(require) { 'input:not([type])': fillTextElement }; - var defaultShowAction = function(element) { + function defaultShowAction(element) { if(typeof element.attributes['data-old-border'] === 'undefined') { element.attributes['data-old-border'] = element.style.border; } @@ -52,9 +53,11 @@ define(function(require) { setTimeout(function() { element.style.border = oldBorder; }, 500); - }; + } - var defaultCanFillElement = function() { return true; }; + function defaultCanFillElement() { + return true; + } /** * @mixin @@ -64,18 +67,22 @@ define(function(require) { showAction: defaultShowAction, canFillElement: defaultCanFillElement, maxNbTries: 10, - logger: {}, - randomizer: new Chance() + logger: null, + randomizer: null }; /** * @mixes config */ function formFillerGremlin() { + if (!config.randomizer) { + throw new RandomizerRequiredException(); + } + // Retrieve all selectors var elementTypes = []; - for(var key in config.elementMapTypes) { + for (var key in config.elementMapTypes) { if(config.elementMapTypes.hasOwnProperty(key)) { elementTypes.push(key); } @@ -107,7 +114,7 @@ define(function(require) { config.showAction(element); } - if (typeof config.logger.log == 'function') { + if (config.logger && typeof config.logger.log == 'function') { config.logger.log('gremlin', 'formFiller', 'input', value, 'in', element); } } diff --git a/src/species/scroller.js b/src/species/scroller.js index 4225cbd..64413ca 100644 --- a/src/species/scroller.js +++ b/src/species/scroller.js @@ -30,6 +30,7 @@ define(function(require) { var configurable = require('../utils/configurable'); var Chance = require('../vendor/chance'); + var RandomizerRequiredException = require('../exceptions/randomizerRequired'); return function() { @@ -37,7 +38,7 @@ define(function(require) { documentElement = document.documentElement, body = document.body; - var defaultPositionSelector = function() { + function defaultPositionSelector() { var documentWidth = Math.max(body.scrollWidth, body.offsetWidth, documentElement.scrollWidth, documentElement.offsetWidth, documentElement.clientWidth), documentHeight = Math.max(body.scrollHeight, body.offsetHeight, documentElement.scrollHeight, documentElement.offsetHeight, documentElement.clientHeight); @@ -45,9 +46,9 @@ define(function(require) { config.randomizer.natural({ max: documentWidth - documentElement.clientWidth }), config.randomizer.natural({ max: documentHeight - documentElement.clientHeight }) ]; - }; + } - var defaultShowAction = function(scrollX, scrollY) { + function defaultShowAction(scrollX, scrollY) { var clickSignal = document.createElement('div'); clickSignal.style.border = "3px solid red"; clickSignal.style.width = (documentElement.clientWidth - 25) + "px"; @@ -65,7 +66,7 @@ define(function(require) { setTimeout(function() { element.style.opacity = 0; }, 50); - }; + } /** * @mixin @@ -73,14 +74,18 @@ define(function(require) { var config = { positionSelector: defaultPositionSelector, showAction: defaultShowAction, - logger: {}, - randomizer: new Chance() + logger: null, + randomizer: null }; /** * @mixes config */ function scrollerGremlin() { + if (!config.randomizer) { + throw new RandomizerRequiredException(); + } + var position = config.positionSelector(), scrollX = position[0], scrollY = position[1]; diff --git a/src/species/toucher.js b/src/species/toucher.js index 3cd0590..50f52a5 100644 --- a/src/species/toucher.js +++ b/src/species/toucher.js @@ -42,6 +42,7 @@ define(function(require) { var configurable = require('../utils/configurable'); var Chance = require('../vendor/chance'); + var RandomizerRequiredException = require('../exceptions/randomizerRequired'); return function() { @@ -50,14 +51,14 @@ define(function(require) { var defaultTouchTypes = ['tap', 'tap', 'tap', 'doubletap', 'gesture', 'gesture', 'gesture', 'multitouch', 'multitouch']; - var defaultPositionSelector = function() { + function defaultPositionSelector() { return [ config.randomizer.natural({ max: document.documentElement.clientWidth - 1 }), config.randomizer.natural({ max: document.documentElement.clientHeight - 1 }) ]; - }; + } - var defaultShowAction = function(touches) { + function defaultShowAction(touches) { var fragment = document.createDocumentFragment(); touches.forEach(function(touch) { var touchSignal = document.createElement('div'); @@ -82,12 +83,11 @@ define(function(require) { }, 50); }); document.body.appendChild(fragment); - }; + } - var defaultCanTouch = function() { + function defaultCanTouch() { return true; - }; - + } /** * @mixin @@ -98,12 +98,11 @@ define(function(require) { showAction: defaultShowAction, canTouch: defaultCanTouch, maxNbTries: 10, - logger: {}, - randomizer: new Chance(), + logger: null, + randomizer: null, maxTouches: 2 }; - /** * generate a list of x/y around the center * @param center @@ -176,8 +175,6 @@ define(function(require) { config.showAction(touches); } - - /** * trigger a gesture * @param element @@ -227,7 +224,7 @@ define(function(require) { var touchTypes = { // tap, like a click event, only 1 touch // could also be a slow tap, that could turn out to be a hold - tap: function(position, element, done) { + tap: function tap(position, element, done) { var touches = getTouches(position, 1); var gesture = { duration: config.randomizer.integer({ min: 20, max: 700 }) @@ -243,7 +240,7 @@ define(function(require) { // doubletap, like a dblclick event, only 1 touch // could also be a slow doubletap, that could turn out to be a hold - doubletap: function(position, element, done) { + doubletap: function doubletap(position, element, done) { touchTypes.tap(position, element, function() { setTimeout(function() { touchTypes.tap(position, element, done); @@ -252,7 +249,7 @@ define(function(require) { }, // single touch gesture, could be a drag and swipe, with 1 points - gesture: function(position, element, done) { + gesture: function gesture(position, element, done) { var gesture = { distanceX: config.randomizer.integer({ min: -100, max: 200 }), distanceY: config.randomizer.integer({ min: -100, max: 200 }), @@ -266,7 +263,7 @@ define(function(require) { }, // multitouch gesture, could be a drag, swipe, pinch and rotate, with 2 or more points - multitouch: function(position, element, done) { + multitouch: function multitouch(position, element, done) { var points = config.randomizer.integer({ min: 2, max: config.maxTouches}); var gesture = { scale: config.randomizer.floating({ min: 0, max: 2 }), @@ -289,6 +286,10 @@ define(function(require) { * @mixes config */ function toucherGremlin(done) { + if (!config.randomizer) { + throw new RandomizerRequiredException(); + } + var position, posX, posY, targetElement, @@ -310,7 +311,7 @@ define(function(require) { if (typeof config.showAction == 'function') { config.showAction(touches); } - if (typeof config.logger.log == 'function') { + if (config.logger && typeof config.logger.log == 'function') { config.logger.log('gremlin', 'toucher ', touchType, 'at', posX, posY, details); } done(); diff --git a/src/species/typer.js b/src/species/typer.js index 1ed55ad..c253d00 100644 --- a/src/species/typer.js +++ b/src/species/typer.js @@ -23,6 +23,7 @@ define(function(require) { var configurable = require('../utils/configurable'); var Chance = require('../vendor/chance'); + var RandomizerRequiredException = require('../exceptions/randomizerRequired'); return function() { @@ -32,15 +33,15 @@ define(function(require) { var defaultEventTypes = ['keypress', 'keyup', 'keydown']; - var defaultKeyGenerator = function() { - return this.randomizer.natural({ max: 360}); - }; + function defaultKeyGenerator() { + return config.randomizer.natural({ max: 360}); + } - var defaultTargetElement = function(x, y) { + function defaultTargetElement(x, y) { return document.elementFromPoint(x, y); - }; + } - var defaultShowAction = function (targetElement, x, y, key) { + function defaultShowAction(targetElement, x, y, key) { var typeSignal = document.createElement('div'); typeSignal.style.border = "3px solid orange"; typeSignal.style['border-radius'] = '50%'; // Chrome @@ -65,7 +66,7 @@ define(function(require) { setTimeout(function () { element.style.opacity = 0; }, 50); - }; + } /** * @mixin @@ -75,14 +76,18 @@ define(function(require) { showAction: defaultShowAction, keyGenerator: defaultKeyGenerator, targetElement: defaultTargetElement, - logger: {}, - randomizer: new Chance() + logger: null, + randomizer: null }; /** * @mixes config */ function typerGremlin() { + if (!config.randomizer) { + throw new RandomizerRequiredException(); + } + var keyboardEvent = document.createEventObject ? document.createEventObject() : document.createEvent("Events"), eventType = config.randomizer.pick(config.eventTypes), key = config.keyGenerator(), @@ -104,7 +109,7 @@ define(function(require) { config.showAction(targetElement, posX, posY, key); } - if (typeof config.logger.log == 'function') { + if (config.logger && typeof config.logger.log == 'function') { config.logger.log('gremlin', 'typer type', key, 'at', posX, posY); } }