| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- /*!
- * 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;
- })();
|