UNPKG

nightwatch

Version:

Easy to use Node.js based End-to-End testing solution for browser based apps and websites, using the W3C WebDriver API.

574 lines (449 loc) 13.9 kB
const EventEmitter = require('events'); const HttpOptions = require('./http/options.js'); const HttpRequest = require('./http/request.js'); const Session = require('./core/session.js'); const Utils = require('./utils'); const Settings = require('./settings/settings.js'); const Transport = require('./transport/transport.js'); const Element = require('./element'); const ApiLoader = require('./api'); const {LocateStrategy, Locator} = Element; const {Logger} = Utils; class NightwatchAPI { get WEBDRIVER_ELEMENT_ID() { return Transport.WEB_ELEMENT_ID; } toString() { return 'Nightwatch API'; } constructor(sessionId, settings) { this.capabilities = {}; this.currentTest = null; this.desiredCapabilities = null; this.sessionId = sessionId; this.options = settings; this.globals = settings.globals; } } class NightwatchClient extends EventEmitter { constructor(settings = {}) { super(); this.setMaxListeners(0); this.settings = settings; Settings.setDefaults(this.settings); Logger.setOptions(this.settings); this.isES6AsyncTestcase = false; // backwards compatibility this.options = settings; this.__locateStrategy = null; this.__httpOpts = HttpOptions.global; this.__transport = Transport.create(this); this.__session = new Session(this); this.__elementLocator = new Locator(this); this.__reporter = null; this.__api = new NightwatchAPI(this.sessionId, settings); this .setLaunchUrl() .setScreenshotOptions() .setLocateStrategy() .setSessionOptions() .setHttpOptions(); } get api() { return this.__api; } get queue() { return this.session.commandQueue; } get locateStrategy() { return this.__locateStrategy; } get session() { return this.__session; } get sessionId() { return this.session.getSessionId(); } get transport() { return this.__transport; } get transportActions() { const actions = this.transport.Actions; const api = this.api; return new Proxy(actions, { get(target, name) { return function (...args) { let callback; let method; let isLastArgFunction = Utils.isFunction(args[args.length-1]); if (isLastArgFunction) { callback = args.pop(); } else if (args.length === 0 || !isLastArgFunction) { callback = function(result) {return result}; } const definition = { args }; if (name in target.session) { // actions that require the current session method = target.session[name]; definition.sessionId = api.sessionId; } else { method = target[name]; } return method(definition).then((result) => Utils.makePromise(callback, api, [result])); }; } }); } get elementLocator() { return this.__elementLocator; } get httpOpts() { return this.__httpOpts; } get startSessionEnabled() { return this.settings.start_session; } get screenshotsEnabled() { return Utils.isObject(this.settings.screenshots) ? this.settings.screenshots && this.options.screenshots.enabled === true : false; } get reporter() { return this.__reporter || {}; } get client() { const {settings, api, locateStrategy, reporter, sessionId, elementLocator} = this; return { options: settings, settings, api, locateStrategy, reporter, sessionId, elementLocator }; } ////////////////////////////////////////////////////////////////////////////////////////// // Setters ////////////////////////////////////////////////////////////////////////////////////////// setApiProperty(key, value) { this.__api[key] = value; return this; } setApiOption(key, value) { this.__api.options[key] = value; return this; } /** * * @param key * @param args * @return {NightwatchClient} */ setApiMethod(key, ...args) { let fn; let context = this.__api; if (args.length === 1) { fn = args[0]; } else if (args.length === 2) { let namespace = typeof args[0] == 'string' ? context[args[0]] : args[0]; if (namespace) { context = namespace; } fn = args[1]; } if (!fn) { throw new Error('Method must be a declared.'); } context[key] = fn; return this; } /** * * @param {string} key * @param {string|object} namespace * @return {boolean} */ isApiMethodDefined(key, namespace) { let api = this.__api; if (namespace) { api = typeof namespace == 'string' ? api[namespace] : namespace; if (api === undefined) { return false; } } return api[key] !== undefined; } setReporter(reporter) { this.__reporter = reporter; return this; } ////////////////////////////////////////////////////////////////////////////////////////// // Options ////////////////////////////////////////////////////////////////////////////////////////// /** * @deprecated */ endSessionOnFail(val) { if (arguments.length === 0) { return this.settings.end_session_on_fail; } this.settings.end_session_on_fail = val; } setLaunchUrl() { let value = this.settings.launchUrl || this.settings.launch_url || null; this.setApiProperty('launchUrl', value).setApiProperty('launch_url', value); return this; } setScreenshotOptions() { let screenshots = this.settings.screenshots; if (this.screenshotsEnabled) { if (typeof screenshots.path == 'undefined') { throw new Error('Please specify the screenshots.path in nightwatch.json.'); } this.settings.screenshots.on_error = this.settings.screenshots.on_error || typeof this.options.screenshots.on_error == 'undefined'; this.settings.screenshotsPath = screenshots.path; this.setApiProperty('screenshotsPath', screenshots.path) .setApiOption('screenshotsPath', screenshots.path); } else { this.settings.screenshots = { enabled : false, path : '' }; } return this; } setLocateStrategy(strategy = null) { if (strategy && LocateStrategy.isValid(strategy)) { this.__locateStrategy = strategy; return this; } this.__locateStrategy = this.settings.use_xpath ? LocateStrategy.XPATH : LocateStrategy.CSS_SELECTOR; return this; } setSessionOptions() { this.setApiOption('desiredCapabilities', this.session.desiredCapabilities); return this; } setHttpOptions() { this.settings.webdriver = this.settings.webdriver || {}; this .setWebdriverHttpOption('host', ['seleniumHost', 'selenium_host'], {defaultValue: 'localhost'}) .setWebdriverHttpOption('port', ['seleniumPort', 'selenium_port'], {defaultValue: this.transport.defaultPort}) .setWebdriverHttpOption('ssl', ['useSsl', 'use_ssl'], {defaultValue: false}) .setWebdriverHttpOption('proxy') .setWebdriverHttpOption('timeout_options', 'request_timeout_options') .setWebdriverHttpOption('default_path_prefix', 'default_path_prefix', {defaultValue: this.transport.defaultPathPrefix}) .setWebdriverHttpOption('username') .setWebdriverHttpOption('access_key', ['accessKey', 'access_key', 'password']); const webdriverOpts = this.settings.webdriver; const timeoutOptions = webdriverOpts.timeout_options || {}; if (webdriverOpts.port) { this.httpOpts.setPort(webdriverOpts.port); } if (webdriverOpts.host) { this.httpOpts.setHost(webdriverOpts.host); } this.httpOpts.useSSL(webdriverOpts.ssl); this.httpOpts.setKeepAlive(webdriverOpts.keep_alive); if (webdriverOpts.proxy !== undefined) { this.httpOpts.setProxy(webdriverOpts.proxy); } if (typeof timeoutOptions.timeout != 'undefined') { this.httpOpts.setTimeout(timeoutOptions.timeout); } if (typeof timeoutOptions.retry_attempts != 'undefined') { this.httpOpts.setRetryAttempts(timeoutOptions.retry_attempts); } if (typeof webdriverOpts.default_path_prefix == 'string') { this.httpOpts.setDefaultPathPrefix(webdriverOpts.default_path_prefix); } if (webdriverOpts.username) { this .setApiOption('username', webdriverOpts.username) .setApiOption('accessKey', webdriverOpts.access_key); this.httpOpts.setCredentials({ username : webdriverOpts.username, key : webdriverOpts.access_key }); } HttpRequest.globalSettings = this.httpOpts.settings; return this; } setWebdriverHttpOption(newSetting, oldSetting, opts = {}) { let webdriverOpts = this.settings.webdriver; let isDefined = typeof webdriverOpts[newSetting] != 'undefined'; if (isDefined) { return this; } if (oldSetting === undefined) { oldSetting = [newSetting]; } else if (!Array.isArray(oldSetting)) { oldSetting = [oldSetting]; } for (let i = 0; i < oldSetting.length; i++) { let item = oldSetting[i]; let isDefined = typeof this.settings[item] != 'undefined'; if (isDefined) { webdriverOpts[newSetting] = this.settings[item]; return this; } } if (typeof opts.defaultValue != 'undefined' && typeof webdriverOpts[newSetting] == 'undefined') { webdriverOpts[newSetting] = opts.defaultValue; } return this; } ////////////////////////////////////////////////////////////////////////////////////////// // Initialize the APIs ////////////////////////////////////////////////////////////////////////////////////////// initialize() { this .loadKeyCodes() .loadNightwatchApis(); } setCurrentTest() { this.setApiProperty('currentTest', this.reporter.currentTest); return this; } loadKeyCodes() { this.setApiProperty('Keys', require('./api/keys.json')); return this; } loadNightwatchApis() { this.setApiProperty('page', {}); this.setApiProperty('assert', {}); if (this.startSessionEnabled) { this.setApiProperty('verify', {}); } ApiLoader.init(this); const assertApi = Object.assign({}, this.__api.assert); const verifyApi = Object.assign({}, this.__api.verify); this.__api.assert = ApiLoader.makeAssertProxy(assertApi); this.__api.verify = ApiLoader.makeAssertProxy(verifyApi); return this; } ////////////////////////////////////////////////////////////////////////////////////////// // Session ////////////////////////////////////////////////////////////////////////////////////////// /** * @return {Promise} */ createSession(argv) { if (!this.session.startSessionEnabled) { return Promise.resolve(); } this.session.on('session:finished', reason => { this.emit('nightwatch:finished', reason); }); return this.session.create(argv) .then(data => { this.setApiProperty('sessionId', data.sessionId); this.setApiProperty('capabilities', data.capabilities); Logger.info(`Received session with ID: ${data.sessionId}\n`); this.emit('nightwatch:session.create', data); return data; }); } /** * @deprecated * @return {Promise} */ startSession() { return this.createSession(); } } const Nightwatch = module.exports = {}; Nightwatch.client = function(settings, reporter = null) { const client = new NightwatchClient(settings); if (reporter === null) { const SimplifiedReporter = require('./reporter/simplified.js'); reporter = new SimplifiedReporter(settings); } client.setReporter(reporter).initialize(); return client; }; Nightwatch.cli = function(callback) { const Argv = require('./runner/cli/argv-setup.js'); Argv.setup(); const argv = Argv.init(); if (argv.help) { Argv.showHelp(); } else if (argv.version) { let packageConfig = require(__dirname + '/../package.json'); console.log(packageConfig.name + ' v' + packageConfig.version); } else { if (!Utils.isFunction(callback)) { throw new Error('Supplied callback argument needs to be a function.'); } callback(argv); } }; /** * @deprecated * @param argv * @param done * @param settings * @return {*|CliRunner} */ Nightwatch.runner = function(argv = {}, done = function() {}, settings = {}) { if (argv.source) { argv._source = argv.source; } argv.reporter = Settings.DEFAULTS.default_reporter; const runner = Nightwatch.CliRunner(argv); return runner.setup(settings) .runTests() .catch(err => { runner.processListener.setExitCode(10); return err; }) .then(err => { return done(err); }); }; /** * * @param [testSource] * @param [settings] */ Nightwatch.runTests = function(testSource, settings) { let argv; if (arguments.length <= 1) { settings = arguments[0] || {}; argv = {}; } else if (Array.isArray(testSource)) { argv = { _source: testSource }; } else if (Utils.isObject(testSource)) { argv = testSource; } else if (Utils.isString(testSource)) { argv = { _source: [testSource] }; } if (argv.source) { argv._source = argv.source; } argv.reporter = Settings.DEFAULTS.default_reporter; try { const runner = Nightwatch.CliRunner(argv); return runner.setup(settings).runTests(); } catch (err) { return Promise.reject(err); } }; Nightwatch.CliRunner = function(argv = {}) { const CliRunner = require('./runner/cli/cli.js'); return new CliRunner(argv); }; /** * @param opts * @return {*} */ Nightwatch.initClient = function(opts = {}) { const cliRunner = Nightwatch.CliRunner(); cliRunner.initTestSettings(opts); return Nightwatch.client(cliRunner.settings); }; Nightwatch.Logger = Logger;