UNPKG

nightwatch

Version:

Easy to use Node.js based end-to-end testing solution for web applications using the W3C WebDriver API.

295 lines (228 loc) 6.65 kB
const path = require('path'); const fs = require('fs'); const EventEmitter = require('events'); const Utils = require('../../utils'); class BaseLoader extends EventEmitter { static unflattenNamespace(target, namespace, value) { const key = namespace.shift(); if (key) { target[key] = target[key] || {}; value = target[key]; return BaseLoader.unflattenNamespace(target[key], namespace, value); } return value; } static createDriverCommand(transport, commandName) { return function commandFn({args}) { return transport.driver[commandName](...args).catch((error) => { if (error.remoteStacktrace) { delete error.remoteStacktrace; } return { value: null, error }; }); }; } get commandQueue() { return this.nightwatchInstance.queue; } get loadSubDirectories() { return false; } get reporter() { return this.nightwatchInstance.reporter; } get api() { return this.nightwatchInstance.api; } get elementLocator() { return this.nightwatchInstance.elementLocator; } get transport() { return this.nightwatchInstance.transport; } get namespace() { return this.__namespace; } get module() { return this.__module; } set module(val) { this.__module = val; } get commandName() { return this.__commandName; } get commandFn() { return this.__commandFn; } set commandFn(val) { this.__commandFn = val; } set commandName(val) { this.__commandName = val; } set stackTrace(val) { this.__stackTrace = val; } get stackTrace() { return this.__stackTrace; } get instance() { return this.__instance; } get isUserDefined() { return this.__isUserDefined; } set isUserDefined(val) { this.__isUserDefined = val; } set ignoreUnderscoreLeadingNames(val) { this.__ignoreUnderscoreNames = val; } get ignoreUnderscoreLeadingNames() { return this.__ignoreUnderscoreNames && !this.isUserDefined; } constructor(nightwatchInstance) { super(); this.nightwatchInstance = nightwatchInstance; } isTypescriptDisabled() { return this.nightwatchInstance.settings.disable_typescript; } getTargetNamespace() { return null; } isFileNameValid(fileName) { if (fileName.startsWith('_') && this.ignoreUnderscoreLeadingNames) { return false; } return Utils.isFileNameValid(fileName); } setNamespace(val) { this.__namespace = val; return this; } loadModule(dirPath, fileName) { const fullPath = path.join(dirPath, fileName); if (!this.loadSubDirectories && fs.lstatSync(fullPath).isDirectory()) { return this; } this.requireModule(fullPath, fileName); return this; } requireModule(fullPath, fileName) { if (!this.isFileNameValid(fileName)) { return this; } if (this.isTypescriptDisabled() && Utils.isTsFile(fileName)) { return this; } this.commandName = path.parse(fullPath).name; this.fileName = fullPath; try { this.module = Utils.requireModule(fullPath); } catch (err) { const {message} = err; const showStackTrace = ['SyntaxError', 'TypeError'].includes(err.name); const error = new Error(`There was an error while trying to load the file ${fullPath}:`); error.detailedErr = `[${err.code || err.name}] ${message};`; error.extraDetail = `\n Current working directory is: ${process.cwd()}`; error.showTrace = showStackTrace; error.displayed = false; if (showStackTrace) { error.stack = err.stack; } throw error; } } validateMethod() {} defineArgs(parent) { const {commandName} = this; const commandFn = this.commandFn.bind(this); const args = [this.createQueuedCommandFn({ parent, commandName, commandFn, context: this })]; const namespace = this.getTargetNamespace(parent); if (namespace) { args.unshift(namespace); } return args; } define(parent = null) { if (!this.commandFn) { return this; } this.validateMethod(parent); const {commandName, nightwatchInstance} = this; const args = this.defineArgs(parent); nightwatchInstance.setApiMethod(commandName, ...args); if (this.module && this.module.AliasName) { nightwatchInstance.setApiMethod(this.module.AliasName, ...args); } return this; } getCommandOptions() { return {}; } createQueuedCommandFn({parent, commandName, namespace, commandFn, context}) { const {commandQueue, api, nightwatchInstance} = this; return function queuedCommandFn(...args) { const stackTrace = Utils.getOriginalStackTrace(queuedCommandFn); const deferred = Utils.createPromise(); deferred.commandName = commandName; // if this command was called from another async (custom) command const isAsyncCommand = this.isES6Async; const options = this.getCommandOptions(); // if this command was called from an async test case let isES6Async = options.alwaysAsync || nightwatchInstance.settings.always_async_commands; if (!isES6Async) { isES6Async = Utils.isUndefined(this.isES6Async) ? ( nightwatchInstance.isES6AsyncTestcase || nightwatchInstance.isES6AsyncCommand ) : isAsyncCommand; } if (!Utils.isUndefined(nightwatchInstance.isES6AsyncTestHook)) { isES6Async = nightwatchInstance.isES6AsyncTestHook; } const node = commandQueue.add({ commandName, commandFn, context: this, args, stackTrace, namespace, options, deferred, isES6Async }); if (isES6Async || options.alwaysAsync || node.isES6Async) { if (parent && parent.__pageObjectItem__) { Object.assign(node.deferred.promise, parent.__pageObjectItem__); } else { Object.assign(node.deferred.promise, api); } return node.deferred.promise; } return api; }.bind(context); } loadDriverCommands({commands, namespace}) { commands.forEach(propertyName => { const commandFn = BaseLoader.createDriverCommand(this.transport, propertyName); this.nightwatchInstance.setApiMethod(propertyName, namespace, (function (commandName) { return this.createQueuedCommandFn({ commandName, commandFn, context: this, namespace }); }.bind(this))(propertyName)); }); } } module.exports = BaseLoader;