refactor app directory structure and add tests
This commit is contained in:
568
tests/node_modules/nightwatch/lib/core/api.js
generated
vendored
Normal file
568
tests/node_modules/nightwatch/lib/core/api.js
generated
vendored
Normal file
@@ -0,0 +1,568 @@
|
||||
/*!
|
||||
* Module dependencies.
|
||||
*/
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var util = require('util');
|
||||
var events = require('events');
|
||||
var assertModule = require('assert');
|
||||
var CommandQueue = require('./queue.js');
|
||||
var Assertion = require('./assertion.js');
|
||||
var Page = require('../page-object/page.js');
|
||||
|
||||
module.exports = new (function() {
|
||||
|
||||
var client;
|
||||
var custom_commands_path;
|
||||
var custom_assertions_path;
|
||||
var page_objects_path;
|
||||
var assertOperators = {
|
||||
ok : ['ok', 'ko'],
|
||||
equal : ['==', '!='],
|
||||
notEqual : ['!=', '=='],
|
||||
deepEqual : ['deepEqual', 'not deepEqual'],
|
||||
notDeepEqual : ['not deepEqual', 'deepEqual'],
|
||||
strictEqual : ['===', '!=='],
|
||||
notStrictEqual : ['!==', '==='],
|
||||
throws : ['throws', 'doesNotThrow'],
|
||||
doesNotThrow : ['doesNotThrow', 'throws'],
|
||||
fail : 'fail',
|
||||
ifError : 'ifError'
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Assertions
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Extends the node.js assert module
|
||||
*
|
||||
* @param prop
|
||||
* @param abortOnFailure
|
||||
* @returns {Function}
|
||||
*/
|
||||
function makeAssertion(prop, abortOnFailure) {
|
||||
return function() {
|
||||
var passed;
|
||||
var expected = null;
|
||||
var actual = null;
|
||||
var lastArgument = arguments[arguments.length-1];
|
||||
var isLastArgString = typeof lastArgument === 'string';
|
||||
var message = isLastArgString &&
|
||||
(arguments.length > 2 || typeof arguments[0] === 'boolean') &&
|
||||
lastArgument || (typeof arguments[0] === 'function' && '[Function]');
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
|
||||
try {
|
||||
assertModule[prop].apply(null, arguments);
|
||||
passed = true;
|
||||
message = 'Passed [' + prop + ']: ' + (message || getAssertMessage(prop, args, passed));
|
||||
} catch (ex) {
|
||||
passed = false;
|
||||
message = 'Failed [' + prop + ']: ' + ('(' + ex.message + ')' || message || getAssertMessage(prop, args, passed));
|
||||
actual = ex.actual;
|
||||
expected = ex.expected;
|
||||
}
|
||||
|
||||
return Assertion.assert(passed, actual, expected, message, abortOnFailure);
|
||||
};
|
||||
}
|
||||
|
||||
function getAssertMessage(prop, args, passed) {
|
||||
if (!Array.isArray(assertOperators[prop])) {
|
||||
return assertOperators[prop] || '';
|
||||
}
|
||||
|
||||
var operator = passed ? assertOperators[prop][0] : assertOperators[prop][1];
|
||||
|
||||
if (args.length === 2) {
|
||||
args.splice(1, 0, operator);
|
||||
} else {
|
||||
args.push(operator);
|
||||
}
|
||||
args = args.map(function(argument) {
|
||||
if (argument && typeof argument == 'object') {
|
||||
argument = util.inspect(argument);
|
||||
}
|
||||
return argument;
|
||||
});
|
||||
return args.join(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the available assertions
|
||||
*/
|
||||
function loadAssertions(parent) {
|
||||
parent = parent || client.api;
|
||||
parent.assert = {};
|
||||
if (client.options.start_session) {
|
||||
parent.verify = {};
|
||||
}
|
||||
for (var prop in assertModule) {
|
||||
if (assertModule.hasOwnProperty(prop)) {
|
||||
parent.assert[prop] = (function(prop) {
|
||||
return makeAssertion(prop, true);
|
||||
})(prop);
|
||||
if (client.options.start_session) {
|
||||
parent.verify[prop] = (function (prop) {
|
||||
return makeAssertion(prop, false);
|
||||
})(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (client.options.start_session) {
|
||||
var dirPath = path.join(__dirname, './../api/assertions/');
|
||||
|
||||
loadAssertionFiles(dirPath, parent.assert, true);
|
||||
loadAssertionFiles(dirPath, parent.verify, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of an assertion
|
||||
*
|
||||
* @param {string} commandName
|
||||
* @param {function} assertionFn
|
||||
* @param {boolean} abortOnFailure
|
||||
* @param {object} parent
|
||||
* @returns {AssertionInstance}
|
||||
*/
|
||||
function createAssertion(commandName, assertionFn, abortOnFailure, parent) {
|
||||
var assertion;
|
||||
if (typeof assertionFn === 'object' && assertionFn.assertion) {
|
||||
assertion = Assertion.factory(assertionFn.assertion, abortOnFailure, client);
|
||||
addCommand(commandName, assertion._commandFn, assertion, parent);
|
||||
return assertion;
|
||||
}
|
||||
|
||||
// backwards compatibility
|
||||
var module = loadCommandModule(assertionFn, client.api, {
|
||||
abortOnFailure : abortOnFailure
|
||||
});
|
||||
|
||||
addCommand(commandName, module.command, module.context, parent);
|
||||
return assertion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the actual assertion files.
|
||||
*
|
||||
* @param {String} dirPath
|
||||
* @param {Object} parent
|
||||
* @param {Boolean} abortOnFailure
|
||||
*/
|
||||
function loadAssertionFiles(dirPath, parent, abortOnFailure) {
|
||||
var commandFiles = fs.readdirSync(dirPath);
|
||||
|
||||
for (var i = 0, len = commandFiles.length; i < len; i++) {
|
||||
if (path.extname(commandFiles[i]) === '.js') {
|
||||
var commandName = path.basename(commandFiles[i], '.js');
|
||||
var assertionFn = require(path.join(dirPath, commandFiles[i]));
|
||||
createAssertion(commandName, assertionFn, abortOnFailure, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Commands
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Loads selenium protocol actions
|
||||
*/
|
||||
function loadProtocolActions(parent) {
|
||||
parent = parent || client.api;
|
||||
var protocol = require('./../api/protocol.js')(client);
|
||||
var actions = Object.keys(protocol);
|
||||
actions.forEach(function(command) {
|
||||
addCommand(command, protocol[command], client.api, parent);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all the composite commands defined by nightwatch
|
||||
*/
|
||||
function loadAllCommands(parent) {
|
||||
loadElementCommands(parent);
|
||||
loadClientCommands(parent);
|
||||
loadCommandFiles(client.api, parent, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the element composite commands defined by nightwatch
|
||||
*/
|
||||
function loadElementCommands(parent) {
|
||||
parent = parent || client.api;
|
||||
var elementCommands = require('./../api/element-commands.js')(client);
|
||||
var entries = Object.keys(elementCommands);
|
||||
entries.forEach(function(command) {
|
||||
addCommand(command, elementCommands[command], client.api, parent);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all the client commands defined by nightwatch
|
||||
*/
|
||||
function loadClientCommands(parent) {
|
||||
parent = parent || client.api;
|
||||
var clientCommands = require('./../api/client-commands.js')(client);
|
||||
var entries = Object.keys(clientCommands);
|
||||
entries.forEach(function(command) {
|
||||
addCommand(command, clientCommands[command], client.api, parent, true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the external commands
|
||||
*/
|
||||
function loadCommandFiles(context, parent, shouldLoadClientCommands) {
|
||||
var relativePaths = ['./../api/element-commands/'];
|
||||
if (shouldLoadClientCommands) {
|
||||
relativePaths.push('./../api/client-commands/');
|
||||
}
|
||||
|
||||
relativePaths.forEach(function(relativePath) {
|
||||
var commandFiles = fs.readdirSync(path.join(__dirname, relativePath));
|
||||
var commandName;
|
||||
var commandModule;
|
||||
|
||||
for (var i = 0, len = commandFiles.length; i < len; i++) {
|
||||
var ext = path.extname(commandFiles[i]);
|
||||
commandName = path.basename(commandFiles[i], ext);
|
||||
if (ext === '.js' && commandName.substr(0, 1) !== '_') {
|
||||
commandModule = require(__dirname + relativePath + commandFiles[i]);
|
||||
var m = loadCommandModule(commandModule, context);
|
||||
addCommand(commandName, m.command, m.context, parent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a command module either specified as an object with a `command` method
|
||||
* or specified as a function which will be instantiated (new function() {..})
|
||||
*
|
||||
* @param {object|function} module
|
||||
* @param {object} context
|
||||
* @param {object} [addt_props]
|
||||
* @returns {{command: function, context: *}}
|
||||
*/
|
||||
function loadCommandModule(module, context, addt_props, return_val) {
|
||||
var m = {command: null, context: context};
|
||||
|
||||
function F() {
|
||||
if (typeof module === 'object') {
|
||||
events.EventEmitter.call(this);
|
||||
}
|
||||
if (addt_props) {
|
||||
for (var prop in addt_props) {
|
||||
if (addt_props.hasOwnProperty(prop)) {
|
||||
this[prop] = addt_props[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
this.client = client;
|
||||
this.api = client.api;
|
||||
if (typeof module === 'function') {
|
||||
module.call(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof module === 'object' && module.command) {
|
||||
util.inherits(F, events.EventEmitter);
|
||||
F.prototype.command = function() {
|
||||
return module.command.apply(this, arguments);
|
||||
};
|
||||
} else if (typeof module === 'function') {
|
||||
F.prototype = Object.create(module.prototype);
|
||||
F.prototype.constructor = F;
|
||||
}
|
||||
|
||||
m.command = function commandFn() {
|
||||
var instance = new F();
|
||||
if (typeof module === 'function') {
|
||||
context = m.context = instance;
|
||||
}
|
||||
instance.command.prototype.constructor.stackTrace = commandFn.stackTrace;
|
||||
instance.command.apply(context, arguments);
|
||||
return context;
|
||||
};
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads custom commands defined by the user
|
||||
* @param {string} [dirPath]
|
||||
* @param {object} [parent]
|
||||
*/
|
||||
function loadCustomCommands(dirPath, parent) {
|
||||
if (!custom_commands_path && !dirPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
dirPath = dirPath || custom_commands_path;
|
||||
parent = parent || client.api;
|
||||
|
||||
if (Array.isArray(dirPath)) {
|
||||
dirPath.forEach(function(folder) {
|
||||
loadCustomCommands(folder, parent);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var absPath = path.resolve(dirPath);
|
||||
var commandFiles = fs.readdirSync(absPath);
|
||||
|
||||
commandFiles.forEach(function(file) {
|
||||
var fullPath = path.join(absPath, file);
|
||||
if (fs.lstatSync(fullPath).isDirectory()) {
|
||||
parent[file] = parent[file] || {};
|
||||
var pathFolder = path.join(dirPath, file);
|
||||
loadCustomCommands(pathFolder, parent[file]);
|
||||
} else if (path.extname(file) === '.js') {
|
||||
var commandModule = require(fullPath);
|
||||
var name = path.basename(file, '.js');
|
||||
|
||||
if (!commandModule) {
|
||||
throw new Error('Module ' + file + 'should have a public method or function.');
|
||||
}
|
||||
|
||||
var m = loadCommandModule(commandModule, client.api);
|
||||
addCommand(name, m.command, m.context, parent, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads custom assertions, similarly to custom commands
|
||||
* @param [folder]
|
||||
*/
|
||||
function loadCustomAssertions(folder, parent) {
|
||||
folder = folder || custom_assertions_path;
|
||||
parent = parent || client.api;
|
||||
if (!custom_assertions_path) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(folder)) {
|
||||
folder.forEach(function(folderName) {
|
||||
loadCustomAssertions(folderName, parent);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
loadCustomAssertionFolder(folder, parent);
|
||||
}
|
||||
|
||||
function loadCustomAssertionFolder(folderName, parent) {
|
||||
var absPath = path.resolve(folderName);
|
||||
loadAssertionFiles(absPath, parent.assert, true);
|
||||
loadAssertionFiles(absPath, parent.verify, false);
|
||||
}
|
||||
|
||||
function loadExpectAssertions(parent) {
|
||||
parent = parent || client.api;
|
||||
var Expect = require('../api/expect.js')(client);
|
||||
var assertions = Object.keys(Expect);
|
||||
|
||||
try {
|
||||
var chaiExpect = module.require('chai').expect;
|
||||
parent.expect = function() {
|
||||
return chaiExpect.apply(chaiExpect, arguments);
|
||||
};
|
||||
} catch (err) {
|
||||
parent.expect = {};
|
||||
}
|
||||
|
||||
assertions.forEach(function(assertion) {
|
||||
parent.expect[assertion] = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var command = Expect[assertion].apply(parent, args);
|
||||
|
||||
function F(element) {
|
||||
events.EventEmitter.call(this);
|
||||
this.client = client;
|
||||
this.element = element;
|
||||
}
|
||||
util.inherits(F, events.EventEmitter);
|
||||
F.prototype.command = function commandFn() {
|
||||
this.element._stackTrace = commandFn.stackTrace;
|
||||
this.element.locate(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
var instance = new F(command.element);
|
||||
var err = new Error;
|
||||
Error.captureStackTrace(err, arguments.callee);
|
||||
CommandQueue.add(assertion, instance.command, instance, [], err.stack);
|
||||
|
||||
return command.expect;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads page object files
|
||||
* @param {string} [dirPath]
|
||||
*/
|
||||
function loadPageObjects(dirPath, parent) {
|
||||
if (!page_objects_path && !dirPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
dirPath = dirPath || page_objects_path;
|
||||
client.api.page = client.api.page || {};
|
||||
parent = parent || client.api.page;
|
||||
|
||||
if (Array.isArray(dirPath)) {
|
||||
dirPath.forEach(function(folder) {
|
||||
loadPageObjects(folder);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var absPath = path.resolve(dirPath);
|
||||
var pageFiles = fs.readdirSync(absPath);
|
||||
|
||||
pageFiles.forEach(function(file) {
|
||||
var fullPath = path.join(absPath, file);
|
||||
if (fs.lstatSync(fullPath).isDirectory()) {
|
||||
parent[file] = parent[file] || {};
|
||||
var pathFolder = path.join(dirPath, file);
|
||||
loadPageObjects(pathFolder, parent[file]);
|
||||
} else if (path.extname(file) === '.js') {
|
||||
var pageName = path.basename(file, '.js');
|
||||
var pageFnOrObject = require(path.join(absPath, file));
|
||||
addPageObject(pageName, pageFnOrObject, client.api, parent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates the page object class
|
||||
* @param {String} name
|
||||
* @param {Object} pageFnOrObject
|
||||
* @param {Object} context
|
||||
* @param {Object} parent
|
||||
*/
|
||||
function addPageObject(name, pageFnOrObject, context, parent) {
|
||||
parent[name] = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
args.unshift(context);
|
||||
|
||||
if (useEnhancedModel(pageFnOrObject)) {
|
||||
var loadOntoPageObject = function(parent) {
|
||||
if (client.options.start_session) {
|
||||
loadElementCommands(parent);
|
||||
loadCommandFiles(client.api, parent, false);
|
||||
loadExpectAssertions(parent);
|
||||
// Alias
|
||||
parent.expect.section = parent.expect.element;
|
||||
}
|
||||
loadAssertions(parent);
|
||||
loadCustomCommands(null, parent);
|
||||
loadCustomAssertions(null, parent);
|
||||
return parent;
|
||||
};
|
||||
pageFnOrObject.name = name;
|
||||
return new Page(pageFnOrObject, loadOntoPageObject, context, client);
|
||||
}
|
||||
|
||||
return new (function() {
|
||||
if (typeof pageFnOrObject == 'function') {
|
||||
return createPageObject(pageFnOrObject, args);
|
||||
}
|
||||
|
||||
return pageFnOrObject;
|
||||
})();
|
||||
};
|
||||
}
|
||||
|
||||
function useEnhancedModel(pageFnOrObject) {
|
||||
return typeof pageFnOrObject == 'object' && (pageFnOrObject.elements || pageFnOrObject.sections);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pageFnOrObject
|
||||
* @param args
|
||||
* @returns {Object}
|
||||
*/
|
||||
function createPageObject(pageFnOrObject, args) {
|
||||
function PageObject() {
|
||||
return pageFnOrObject.apply(this, args);
|
||||
}
|
||||
PageObject.prototype = pageFnOrObject.prototype;
|
||||
return new PageObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a command/assertion to the queue.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} command
|
||||
* @param {Object} context
|
||||
* @param {Object} [parent]
|
||||
*/
|
||||
function addCommand(name, command, context, parent) {
|
||||
parent = parent || client.api;
|
||||
if (parent[name]) {
|
||||
client.results.errors++;
|
||||
var error = new Error('The command "' + name + '" is already defined!');
|
||||
client.errors.push(error.stack);
|
||||
throw error;
|
||||
}
|
||||
parent[name] = function commandFn() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
|
||||
var originalStackTrace;
|
||||
if (commandFn.stackTrace) {
|
||||
originalStackTrace = commandFn.stackTrace;
|
||||
} else {
|
||||
var err = new Error;
|
||||
Error.captureStackTrace(err, arguments.callee);
|
||||
originalStackTrace = err.stack;
|
||||
}
|
||||
|
||||
CommandQueue.add(name, command, context, args, originalStackTrace);
|
||||
return client.api; // for chaining
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the api
|
||||
*
|
||||
* @param {Object} c The nightwatch client instance
|
||||
* @api public
|
||||
*/
|
||||
this.init = function(c) {
|
||||
client = c;
|
||||
custom_commands_path = c.options.custom_commands_path;
|
||||
custom_assertions_path = c.options.custom_assertions_path;
|
||||
page_objects_path = c.options.page_objects_path;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads everything
|
||||
*/
|
||||
this.load = function() {
|
||||
if (client.options.start_session) {
|
||||
loadProtocolActions();
|
||||
loadAllCommands();
|
||||
loadPageObjects();
|
||||
loadExpectAssertions();
|
||||
}
|
||||
loadAssertions();
|
||||
loadCustomCommands();
|
||||
loadCustomAssertions();
|
||||
return this;
|
||||
};
|
||||
|
||||
this.addCommand = addCommand;
|
||||
this.loadCustomCommands = loadCustomCommands;
|
||||
this.loadCustomAssertions = loadCustomAssertions;
|
||||
this.loadPageObjects = loadPageObjects;
|
||||
this.createAssertion = createAssertion;
|
||||
})();
|
275
tests/node_modules/nightwatch/lib/core/assertion.js
generated
vendored
Normal file
275
tests/node_modules/nightwatch/lib/core/assertion.js
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
var util = require('util');
|
||||
var events = require('events');
|
||||
var Logger = require('./../util/logger.js');
|
||||
var Utils = require('./../util/utils.js');
|
||||
|
||||
module.exports = new (function() {
|
||||
var doneSymbol = Utils.symbols.ok;
|
||||
var failSymbol = Utils.symbols.fail;
|
||||
var initialized = false;
|
||||
var client;
|
||||
|
||||
/**
|
||||
* Abstract assertion class that will subclass all defined assertions
|
||||
*
|
||||
* All assertions must implement the following api:
|
||||
*
|
||||
* - @type {boolean|function}
|
||||
* expected
|
||||
* - @type {string}
|
||||
* message
|
||||
* - @type {function}
|
||||
* pass
|
||||
* - @type {function}
|
||||
* value
|
||||
* - @type {function}
|
||||
* command
|
||||
* - @type {function} - Optional
|
||||
* failure
|
||||
*
|
||||
* @param {boolean} abortOnFailure
|
||||
* @param {Nightwatch} client
|
||||
* @constructor
|
||||
*/
|
||||
function BaseAssertion(abortOnFailure, client) {
|
||||
events.EventEmitter.call(this);
|
||||
this.abortOnFailure = abortOnFailure;
|
||||
this.client = client;
|
||||
this.api = client.api;
|
||||
this.startTime = new Date().getTime();
|
||||
this.globals = this.api.globals || {};
|
||||
this.timeout = this.globals.retryAssertionTimeout || 0; //ms
|
||||
this.rescheduleInterval = this.globals.waitForConditionPollInterval || 500; //ms
|
||||
this.shouldRetry = this.timeout > 0;
|
||||
}
|
||||
|
||||
util.inherits(BaseAssertion, events.EventEmitter);
|
||||
|
||||
BaseAssertion.prototype.complete = function() {
|
||||
var self = this, args = Array.prototype.slice.call(arguments, 0);
|
||||
args.unshift('complete');
|
||||
|
||||
setImmediate(function() {
|
||||
self.emit.apply(self, args);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs the command method
|
||||
* @returns {*}
|
||||
* @private
|
||||
*/
|
||||
BaseAssertion.prototype._executeCommand = function() {
|
||||
var self = this;
|
||||
var methods = [
|
||||
'expected',
|
||||
'message',
|
||||
['pass'],
|
||||
['value'],
|
||||
['command']
|
||||
];
|
||||
methods.forEach(function(method) {
|
||||
if (Array.isArray(method)) {
|
||||
var name = method[0];
|
||||
if (typeof self[name] !== 'function') {
|
||||
throw new Error('Assertion must implement method ' + name);
|
||||
}
|
||||
} else if (typeof self[method] == 'undefined') {
|
||||
throw new Error('Assertion must implement method/property ' + method);
|
||||
}
|
||||
});
|
||||
|
||||
return this._scheduleAssertion();
|
||||
};
|
||||
|
||||
BaseAssertion.prototype._scheduleAssertion = function() {
|
||||
var self = this;
|
||||
return this.command(function(result) {
|
||||
var passed, value;
|
||||
|
||||
if (typeof self.failure == 'function' && self.failure(result)) {
|
||||
passed = false;
|
||||
value = null;
|
||||
} else {
|
||||
value = self.value(result);
|
||||
passed = self.pass(value);
|
||||
}
|
||||
|
||||
var timeSpent = new Date().getTime() - self.startTime;
|
||||
if (!passed && timeSpent < self.timeout) {
|
||||
return self._reschedule();
|
||||
}
|
||||
|
||||
var expected = typeof self.expected == 'function' ? self.expected() : self.expected;
|
||||
var message = self._getFullMessage(passed, timeSpent);
|
||||
|
||||
self.client.assertion(passed, value, expected, message, self.abortOnFailure, self._stackTrace);
|
||||
self.emit('complete');
|
||||
});
|
||||
};
|
||||
|
||||
BaseAssertion.prototype._getFullMessage = function(passed, timeSpent) {
|
||||
if ( !this.shouldRetry) {
|
||||
return this.message;
|
||||
}
|
||||
var timeLogged = passed ? timeSpent : this.timeout;
|
||||
return this.message + ' after ' + timeLogged + ' milliseconds.';
|
||||
};
|
||||
|
||||
BaseAssertion.prototype._reschedule = function() {
|
||||
setTimeout(function(){}, this.rescheduleInterval);
|
||||
return this._scheduleAssertion();
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} stackTrace
|
||||
* @param {string|null} message
|
||||
*/
|
||||
function buildStackTrace(stackTrace, message) {
|
||||
var stackParts = stackTrace.split('\n');
|
||||
stackParts.shift();
|
||||
|
||||
if (message) {
|
||||
stackParts.unshift(message);
|
||||
}
|
||||
|
||||
return Utils.stackTraceFilter(stackParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertion factory that creates the assertion instances with the supplied assertion definition
|
||||
* and options
|
||||
*
|
||||
* @param {function} assertionFn
|
||||
* @param {boolean} abortOnFailure
|
||||
* @param {Nightwatch} client
|
||||
* @constructor
|
||||
*/
|
||||
function AssertionInstance(assertionFn, abortOnFailure, client) {
|
||||
this.abortOnFailure = abortOnFailure;
|
||||
this.client = client;
|
||||
this.assertionFn = assertionFn;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will call the supplied constructor of the assertion, after calling the Base constructor
|
||||
* first with other arguments and then inherits the rest of the methods from BaseAssertion
|
||||
*
|
||||
* @param {function} constructor
|
||||
* @param {Array} args
|
||||
* @returns {*}
|
||||
* @private
|
||||
*/
|
||||
AssertionInstance.prototype._constructFromSuper = function(constructor, args) {
|
||||
var self = this;
|
||||
function F() {
|
||||
BaseAssertion.apply(this, [self.abortOnFailure, self.client]);
|
||||
return constructor.apply(this, args);
|
||||
}
|
||||
|
||||
util.inherits(constructor, BaseAssertion);
|
||||
F.prototype = constructor.prototype;
|
||||
return new F();
|
||||
};
|
||||
|
||||
AssertionInstance.prototype._commandFn = function commandFn() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
var instance = this._constructFromSuper(this.assertionFn, args);
|
||||
instance._stackTrace = commandFn.stackTrace;
|
||||
return instance._executeCommand();
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {function} assertionFn
|
||||
* @param {boolean} abortOnFailure
|
||||
* @param {Nightwatch} client
|
||||
* @returns {AssertionInstance}
|
||||
*/
|
||||
this.factory = function(assertionFn, abortOnFailure, client) {
|
||||
return new AssertionInstance(assertionFn, abortOnFailure, client);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an assertion
|
||||
*
|
||||
* @param {Boolean} passed
|
||||
* @param {Object} receivedValue
|
||||
* @param {Object} expectedValue
|
||||
* @param {String} message
|
||||
* @param {Boolean} abortOnFailure
|
||||
* @param {String} originalStackTrace
|
||||
*/
|
||||
this.assert = function assert(passed, receivedValue, expectedValue, message, abortOnFailure, originalStackTrace) {
|
||||
if (!initialized) {
|
||||
throw new Error('init must be called first.');
|
||||
}
|
||||
|
||||
var failure = '';
|
||||
var stacktrace = '';
|
||||
var fullMsg = '';
|
||||
|
||||
if (passed) {
|
||||
if (client.options.output && client.options.detailed_output) {
|
||||
console.log(' ' + Logger.colors.green(doneSymbol) + ' ' + message);
|
||||
}
|
||||
client.results.passed++;
|
||||
} else {
|
||||
failure = 'Expected "' + expectedValue + '" but got: "' + receivedValue + '"';
|
||||
var err = new Error();
|
||||
|
||||
err.name = message;
|
||||
err.message = message + ' - ' + failure;
|
||||
|
||||
if (!originalStackTrace) {
|
||||
Error.captureStackTrace(err, arguments.callee);
|
||||
originalStackTrace = err.stack;
|
||||
}
|
||||
|
||||
err.stack = buildStackTrace(originalStackTrace, client.options.start_session ? null : 'AssertionError: ' + message);
|
||||
|
||||
fullMsg = message;
|
||||
if (client.options.output && client.options.detailed_output) {
|
||||
var logged = ' ' + Logger.colors.red(failSymbol);
|
||||
if (typeof expectedValue != 'undefined' && typeof receivedValue != 'undefined') {
|
||||
fullMsg += ' ' + Logger.colors.white(' - expected ' + Logger.colors.green('"' +
|
||||
expectedValue + '"')) + ' but got: ' + Logger.colors.red('"' + receivedValue + '"');
|
||||
}
|
||||
logged += ' ' + fullMsg;
|
||||
console.log(logged);
|
||||
}
|
||||
|
||||
stacktrace = err.stack;
|
||||
if (client.options.output && client.options.detailed_output) {
|
||||
var parts = stacktrace.split('\n');
|
||||
console.log(Logger.colors.stack_trace(parts.join('\n')) + '\n');
|
||||
}
|
||||
|
||||
client.results.lastError = err;
|
||||
client.results.failed++;
|
||||
}
|
||||
|
||||
client.results.tests.push({
|
||||
message : message,
|
||||
stackTrace : stacktrace,
|
||||
fullMsg : fullMsg,
|
||||
failure : failure !== '' ? failure : false
|
||||
});
|
||||
|
||||
if (!passed && abortOnFailure) {
|
||||
client.terminate(true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializer
|
||||
*
|
||||
* @param {Object} c Nightwatch client instance
|
||||
*/
|
||||
this.init = function(c) {
|
||||
client = c;
|
||||
initialized = true;
|
||||
};
|
||||
})();
|
232
tests/node_modules/nightwatch/lib/core/queue.js
generated
vendored
Normal file
232
tests/node_modules/nightwatch/lib/core/queue.js
generated
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
var util = require('util');
|
||||
var events = require('events');
|
||||
var Logger = require('./../util/logger.js');
|
||||
|
||||
function AsyncTree() {
|
||||
events.EventEmitter.call(this);
|
||||
this.rootNode = {
|
||||
name : '__root__',
|
||||
children : [],
|
||||
started : false,
|
||||
done : false,
|
||||
parent : this.rootNode
|
||||
};
|
||||
this.currentNode = this.rootNode;
|
||||
}
|
||||
util.inherits(AsyncTree, events.EventEmitter);
|
||||
|
||||
AsyncTree.prototype.append = function(nodeName, command, context, args, stackTrace) {
|
||||
var node = {
|
||||
startTime : null,
|
||||
name : nodeName,
|
||||
command : command,
|
||||
context : context,
|
||||
args : args || [],
|
||||
started : false,
|
||||
done : false,
|
||||
children : [],
|
||||
parent : this.currentNode,
|
||||
stackTrace : stackTrace
|
||||
};
|
||||
|
||||
this.currentNode.children.push(node);
|
||||
|
||||
if (this.currentNode.started && !this.currentNode.done) {
|
||||
this.scheduleTraverse(node);
|
||||
}
|
||||
};
|
||||
|
||||
AsyncTree.prototype.print = function(node, level) {
|
||||
process.stdout.write(node.name + '\n');
|
||||
level = level || 1;
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
var childNode = node.children[i];
|
||||
for (var k = 0; k < level; k++) {
|
||||
process.stdout.write(' |- ');
|
||||
}
|
||||
if (childNode.children.length) {
|
||||
var levelUp = level + 1;
|
||||
arguments.callee(childNode, levelUp);
|
||||
} else {
|
||||
process.stdout.write(childNode.name + '\n');
|
||||
}
|
||||
}
|
||||
process.stdout.write('');
|
||||
};
|
||||
|
||||
AsyncTree.prototype.scheduleTraverse = function(node) {
|
||||
if (this.scheduled) {
|
||||
return this;
|
||||
}
|
||||
this.scheduled = true;
|
||||
var self = this;
|
||||
process.nextTick(function() {
|
||||
self.scheduled = false;
|
||||
self.traverse();
|
||||
});
|
||||
};
|
||||
|
||||
AsyncTree.prototype.traverse = function() {
|
||||
this.emit('queue:started');
|
||||
this.currentNode.started = true;
|
||||
|
||||
this.walkDown(this.currentNode);
|
||||
return this;
|
||||
};
|
||||
|
||||
AsyncTree.prototype.walkDown = function walkDown(context) {
|
||||
var node = this.getNextChild(context);
|
||||
if (node) {
|
||||
this.runChildNode(node);
|
||||
} else {
|
||||
if (context.instance && !context.done) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentNode.done = true;
|
||||
if (this.currentNode.name === '__root__') {
|
||||
this.done();
|
||||
} else {
|
||||
this.walkUp(context);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AsyncTree.prototype.walkUp = function(context) {
|
||||
this.currentNode = context.parent;
|
||||
this.walkDown(context.parent);
|
||||
};
|
||||
|
||||
AsyncTree.prototype.getNextChild = function(context) {
|
||||
for (var i = 0; i < context.children.length; i++) {
|
||||
if (!context.children[i].started) {
|
||||
var child = context.children[i];
|
||||
context.children.splice(i, 1);
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
AsyncTree.prototype.runChildNode = function runChildNode(node) {
|
||||
var self = this;
|
||||
|
||||
this.runCommand(node, function onCommandComplete() {
|
||||
var timems = new Date().getTime() - node.startTime;
|
||||
// checking if new children have been added while running this command which haven't finished yet
|
||||
var childrenInProgress = false;
|
||||
var currentChildNode = null;
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
currentChildNode = node.children[i];
|
||||
if (!currentChildNode.done) {
|
||||
childrenInProgress = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.log(' ' + Logger.colors.green('→') +
|
||||
' Completed command ' + Logger.colors.light_green(node.name), '(' + timems, 'ms)');
|
||||
node.done = true;
|
||||
if (!childrenInProgress) {
|
||||
self.traverse();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
AsyncTree.prototype.runCommand = function(node, callback) {
|
||||
this.currentNode = node;
|
||||
node.started = true;
|
||||
|
||||
try {
|
||||
var commandFn = node.command;
|
||||
if (typeof node.command !== 'function') {
|
||||
// backwards compatibility
|
||||
commandFn = node.command.command;
|
||||
}
|
||||
|
||||
if (typeof commandFn !== 'function') {
|
||||
throw new Error('Command must be a function');
|
||||
}
|
||||
|
||||
node.startTime = new Date().getTime();
|
||||
commandFn.prototype.constructor.stackTrace = node.stackTrace;
|
||||
|
||||
var instance = commandFn.apply(node.context, node.args);
|
||||
if (instance instanceof events.EventEmitter) {
|
||||
node.instance = instance;
|
||||
instance.once('complete', callback);
|
||||
}
|
||||
return node.context;
|
||||
} catch (err) {
|
||||
err.stack = node.stackTrace;
|
||||
err.name = 'Error while running ' + node.name + ' command';
|
||||
this.emit('error', err);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
AsyncTree.prototype.done = function() {
|
||||
this.rootNode.started = false;
|
||||
this.emit('queue:finished');
|
||||
return this;
|
||||
};
|
||||
|
||||
AsyncTree.prototype.empty = function() {
|
||||
this.rootNode.children = [];
|
||||
return this;
|
||||
};
|
||||
|
||||
AsyncTree.prototype.reset = function() {
|
||||
this.rootNode.started = false;
|
||||
this.rootNode.done = false;
|
||||
this.removeAllListeners();
|
||||
this.currentNode = this.rootNode;
|
||||
return this;
|
||||
};
|
||||
|
||||
module.exports = new (function() {
|
||||
var queue = new AsyncTree();
|
||||
|
||||
this.reset = function() {
|
||||
queue.reset();
|
||||
};
|
||||
|
||||
this.empty = function() {
|
||||
queue.empty();
|
||||
};
|
||||
|
||||
this.add = function() {
|
||||
queue.append.apply(queue, arguments);
|
||||
};
|
||||
|
||||
this.run = function queueRunner(callback) {
|
||||
if (queue.rootNode.started) {
|
||||
return queue;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
queue.once('queue:finished', function() {
|
||||
callback(null);
|
||||
})
|
||||
.on('error', function(err) {
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
|
||||
return queue.traverse();
|
||||
};
|
||||
|
||||
this.done = function() {
|
||||
queue.done();
|
||||
};
|
||||
|
||||
this.instance = function instance() {
|
||||
return queue;
|
||||
};
|
||||
|
||||
this.list = function list() {
|
||||
return queue.rootNode.children.map(function(item) {
|
||||
return item.name;
|
||||
});
|
||||
};
|
||||
})();
|
Reference in New Issue
Block a user