UNPKG

cabbie-sync

Version:
708 lines (510 loc) 24 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _keys = require('babel-runtime/core-js/object/keys'); var _keys2 = _interopRequireDefault(_keys); var _stringify = require('babel-runtime/core-js/json/stringify'); var _stringify2 = _interopRequireDefault(_stringify); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _applicationCacheStatuses = require('./enums/application-cache-statuses'); var _browserOrientations = require('./enums/browser-orientations'); var _httpMethod = require('./flow-types/http-method'); var _options4 = require('./flow-types/options'); var _sessionData = require('./flow-types/session-data'); var _logEntry = require('./log-entry'); var _url = require('url'); var _fs = require('fs'); var _dotenv = require('dotenv'); var _depd = require('depd'); var _depd2 = _interopRequireDefault(_depd); var _availableBrowsers = require('available-browsers'); var _availableBrowsers2 = _interopRequireDefault(_availableBrowsers); var _crossSpawn = require('cross-spawn'); var _crossSpawn2 = _interopRequireDefault(_crossSpawn); var _addDebugging = require('./add-debugging'); var _addDebugging2 = _interopRequireDefault(_addDebugging); var _syncRequest = require('sync-request'); var _syncRequest2 = _interopRequireDefault(_syncRequest); var _errors = require('./utils/errors'); var _connection = require('./connection'); var _connection2 = _interopRequireDefault(_connection); var _browser = require('./browser'); var _browser2 = _interopRequireDefault(_browser); var _debug = require('./debug'); var _debug2 = _interopRequireDefault(_debug); var _timeOut = require('./time-out'); var _timeOut2 = _interopRequireDefault(_timeOut); var _status = require('./status'); var _status2 = _interopRequireDefault(_status); var _parseResponse = require('./utils/parse-response'); var _parseResponse2 = _interopRequireDefault(_parseResponse); var _activeWindow = require('./active-window'); var _activeWindow2 = _interopRequireDefault(_activeWindow); var _ime = require('./ime'); var _ime2 = _interopRequireDefault(_ime); var _cookieStorage = require('./cookie-storage'); var _cookieStorage2 = _interopRequireDefault(_cookieStorage); var _localStorage = require('./local-storage'); var _localStorage2 = _interopRequireDefault(_localStorage); var _sessionStorage = require('./session-storage'); var _sessionStorage2 = _interopRequireDefault(_sessionStorage); var _windowHandle = require('./window-handle'); var _windowHandle2 = _interopRequireDefault(_windowHandle); var _flowRuntime = require('flow-runtime'); var _flowRuntime2 = _interopRequireDefault(_flowRuntime); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * * This file is generated automatically, run npm run build to re-generate. **/ var LogEntry = _flowRuntime2.default.tdz(function () { return _logEntry.LogEntry; }); var Session = _flowRuntime2.default.tdz(function () { return _sessionData.Session; }); var Options = _flowRuntime2.default.tdz(function () { return _options4.Options; }); var HttpMethod = _flowRuntime2.default.tdz(function () { return _httpMethod.HttpMethod; }); var BrowserOrientation = _flowRuntime2.default.tdz(function () { return _browserOrientations.BrowserOrientation; }); var ApplicationCacheStatus = _flowRuntime2.default.tdz(function () { return _applicationCacheStatuses.ApplicationCacheStatus; }); var deprecate = (0, _depd2.default)('cabbie'); /* * Create a new Driver session, remember to call `.dispose()` * at the end to terminate the session. */ var Driver = function () { /* * Get the Session-Storage object. */ /* * Get the Cookie-Storage object. */ /* * The currently active window. This has most of the methods to interact with * the the current page. */ /* * The browser object. * * @private */ /* * The location of the selenium server */ /* * @private */ function Driver(remote /*: string*/) { var options /*: Options*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; (0, _classCallCheck3.default)(this, Driver); var _remoteType = _flowRuntime2.default.string(); var _optionsType = _flowRuntime2.default.ref(Options); _flowRuntime2.default.param('remote', _remoteType).assert(remote); _flowRuntime2.default.param('options', _optionsType).assert(options); options = _optionsType.assert(addEnvironment(options)); this.remote = remote; this.options = options; this.debug = new _debug2.default(options); var remoteURI = remote; var capabilities = (0, _extends3.default)({}, options.browser && (remote === 'saucelabs' || remote === 'browserstack' || remote === 'testingbot') ? (0, _availableBrowsers2.default)(remote, options.browser.name, options.browser.version, options.browser.platform) : {}, options.capabilities || {}); var remoteAliases = { 'chrome-driver': 'chromedriver', 'taxi-rank': 'taxirank', 'sauce-labs': 'saucelabs', 'browser-stack': 'browserstack', 'testing-bot': 'testingbot' }; if (remote in remoteAliases) { remote = _remoteType.assert(remoteAliases[remote]); } switch (remote) { case 'chromedriver': remoteURI = 'http://localhost:9515/'; break; case 'taxirank': remoteURI = 'http://localhost:9516'; break; case 'saucelabs': var _options = options, sauceUsername = _options.sauceUsername, sauceAccessKey = _options.sauceAccessKey; if (!sauceUsername || !sauceAccessKey) { throw new Error('To use sauce labs, you must specify SAUCE_USERNAME and SAUCE_ACCESS_KEY in enviornment variables or ' + 'provide sauceUsername and sauceAccessKey as options.'); } remoteURI = 'http://' + sauceUsername + ':' + sauceAccessKey + '@ondemand.saucelabs.com/wd/hub'; break; case 'browserstack': var _options2 = options, browserStackUsername = _options2.browserStackUsername, browserStackAccessKey = _options2.browserStackAccessKey; if (!browserStackUsername || !browserStackAccessKey) { throw new Error('To use browserstack, you must specify BROWSER_STACK_USERNAME and BROWSER_STACK_ACCESS_KEY in ' + 'enviornment variables or provide browserStackUsername and browserStackAccessKey as options.'); } remoteURI = 'http://hub-cloud.browserstack.com/wd/hub'; capabilities['browserstack.user'] = browserStackUsername; capabilities['browserstack.key'] = browserStackAccessKey; break; case 'testingbot': var _options3 = options, testingBotKey = _options3.testingBotKey, testingBotSecret = _options3.testingBotSecret; if (!testingBotKey || !testingBotSecret) { throw new Error('To use testingbot, you must specify TESTING_BOT_KEY and TESTING_BOT_SECRET in enviornment ' + 'variables or provide testingBotKey and testingBotSecret as options.'); } remoteURI = 'http://' + testingBotKey + ':' + testingBotSecret + '@hub.testingbot.com/wd/hub'; break; } this._connection = new _connection2.default(remote, remoteURI, this.debug); this.session = this._createSession(remote, this._connection, (0, _extends3.default)({}, options, { capabilities: capabilities })); this.browser = new _browser2.default(this, options); this.timeOut = new _timeOut2.default(this); this.activeWindow = new _activeWindow2.default(this, options); this.ime = new _ime2.default(this); this.cookieStorage = new _cookieStorage2.default(this); this.localStorage = new _localStorage2.default(this); this.sessionStorage = new _sessionStorage2.default(this); deprecate.property(this, 'browser', 'All properties of browser are now directly available on the Driver object'); } /* * Get the Local-Storage object. */ /* * Get the IME object. */ /* * Timeout configuration */ /* * The options that were originally passed in to createCabbieDriver */ /* * @private */ /* * The current session. You can pass this session to createCabbieDriver to convert * between sync and async drivers. e.g. * * ```js * const driver = createCabbieDriver(oldDriver.remote, {...oldDriver.options, session: oldDriver.session}); * ``` */ (0, _createClass3.default)(Driver, [{ key: '_createSession', value: function _createSession(remote /*: string*/, connection /*: Connection*/, options /*: Options*/) /*: Session*/ { var _remoteType2 = _flowRuntime2.default.string(); var _connectionType = _flowRuntime2.default.ref(_connection2.default); var _optionsType2 = _flowRuntime2.default.ref(Options); var _returnType = _flowRuntime2.default.return(_flowRuntime2.default.ref(Session)); _flowRuntime2.default.param('remote', _remoteType2).assert(remote); _flowRuntime2.default.param('connection', _connectionType).assert(connection); _flowRuntime2.default.param('options', _optionsType2).assert(options); if (remote === 'taxirank') { this._closeTaxiRank = startTaxiRank(connection); } return _returnType.assert(createSession(remote, this._connection, options)); } /* * Performs a context dependent JSON request for the current session. * The result is parsed for errors. * @private */ }, { key: 'requestJSON', value: function requestJSON(method /*: HttpMethod*/, path /*: string*/, body /*:: ?: Object*/) /*: any*/ { var _methodType = _flowRuntime2.default.ref(HttpMethod); var _pathType = _flowRuntime2.default.string(); var _bodyType = _flowRuntime2.default.object(); var _returnType2 = _flowRuntime2.default.return(_flowRuntime2.default.any()); _flowRuntime2.default.param('method', _methodType).assert(method); _flowRuntime2.default.param('path', _pathType).assert(path); _flowRuntime2.default.param('body', _bodyType, true).assert(body); var session = this.session; return _returnType2.assert(this._connection.requestWithSession(session, method, path, { json: body })); } /* * Get an array of windows for all available windows */ }, { key: 'getWindows', value: function getWindows() /*: Array<WindowHandle>*/ { var _this = this; var _returnType3 = _flowRuntime2.default.return(_flowRuntime2.default.array(_flowRuntime2.default.ref(_windowHandle2.default))); var windowHandles = this.requestJSON('GET', '/window_handles'); return _returnType3.assert(windowHandles.map(function (windowHandle) { return new _windowHandle2.default(_this, windowHandle); })); } /* * Get the current browser orientation */ }, { key: 'getOrientation', value: function getOrientation() /*: BrowserOrientation*/ { var _returnType4 = _flowRuntime2.default.return(_flowRuntime2.default.ref(BrowserOrientation)); return _returnType4.assert(this.requestJSON('GET', '/orientation')); } /* * Get the current browser orientation */ }, { key: 'setOrientation', value: function setOrientation(orientation /*: BrowserOrientation*/) /*: void*/ { var _orientationType = _flowRuntime2.default.ref(BrowserOrientation); var _returnType5 = _flowRuntime2.default.return(_flowRuntime2.default.void()); _flowRuntime2.default.param('orientation', _orientationType).assert(orientation); this.requestJSON('POST', '/orientation', { orientation: orientation }); } /* * Get the current geo location */ }, { key: 'getGeoLocation', value: function getGeoLocation() /*: { latitude: number; longitude: number; altitude: number; }*/ { var _returnType6 = _flowRuntime2.default.return(_flowRuntime2.default.object(_flowRuntime2.default.property('latitude', _flowRuntime2.default.number()), _flowRuntime2.default.property('longitude', _flowRuntime2.default.number()), _flowRuntime2.default.property('altitude', _flowRuntime2.default.number()))); return _returnType6.assert(this.requestJSON('GET', '/location')); } /* * Set the current geo location */ }, { key: 'setGeoLocation', value: function setGeoLocation(loc /*: { latitude: number; longitude: number; altitude: number; }*/) /*: void*/ { var _locType = _flowRuntime2.default.object(_flowRuntime2.default.property('latitude', _flowRuntime2.default.number()), _flowRuntime2.default.property('longitude', _flowRuntime2.default.number()), _flowRuntime2.default.property('altitude', _flowRuntime2.default.number())); var _returnType7 = _flowRuntime2.default.return(_flowRuntime2.default.void()); _flowRuntime2.default.param('loc', _locType).assert(loc); this.requestJSON('POST', '/location', loc); } /* * Get the status of the html5 application cache */ }, { key: 'getApplicationCacheStatus', value: function getApplicationCacheStatus() /*: ApplicationCacheStatus*/ { var _returnType8 = _flowRuntime2.default.return(_flowRuntime2.default.ref(ApplicationCacheStatus)); return _returnType8.assert(this.requestJSON('GET', '/application_cache/status')); } /* * Get the log for a given log type. Log buffer is reset after each request. */ }, { key: 'getLogs', value: function getLogs(logType /*: string*/) /*: Array<LogEntry>*/ { var _logTypeType = _flowRuntime2.default.string(); var _returnType9 = _flowRuntime2.default.return(_flowRuntime2.default.array(_flowRuntime2.default.ref(LogEntry))); _flowRuntime2.default.param('logType', _logTypeType).assert(logType); return _returnType9.assert(this.requestJSON('POST', '/log', { type: logType })); } /* * Get available log types */ }, { key: 'getLogTypes', value: function getLogTypes() /*: Array<string>*/ { var _returnType10 = _flowRuntime2.default.return(_flowRuntime2.default.array(_flowRuntime2.default.string())); return _returnType10.assert(this.requestJSON('GET', '/log/types')); } /* * End this Driver session */ }, { key: 'dispose', value: function dispose(status /*:: ?: Object*/) /*: void*/ { var _statusType = _flowRuntime2.default.object(); var _returnType11 = _flowRuntime2.default.return(_flowRuntime2.default.void()); _flowRuntime2.default.param('status', _statusType, true).assert(status); if (status) { this.sauceJobUpdate(status); } this.requestJSON('DELETE', ''); if (this._closeTaxiRank) { this._closeTaxiRank(); } } /* * Sauce Labs Methods */ }, { key: 'sauceJobUpdate', value: function sauceJobUpdate(body /*: Object*/) /*: boolean*/ { var _bodyType2 = _flowRuntime2.default.object(); var _returnType12 = _flowRuntime2.default.return(_flowRuntime2.default.boolean()); _flowRuntime2.default.param('body', _bodyType2).assert(body); var remote = _flowRuntime2.default.string().assert(this._connection.remote); var session = this.session; if (remote.indexOf('saucelabs') === -1) { return _returnType12.assert(false); } if (body === undefined) { return _returnType12.assert(true); } var auth = (0, _url.parse)(remote).auth; if (typeof auth !== 'string') { throw new Error('Could not find sauce labs authentication in remote'); } (0, _syncRequest2.default)('PUT', 'http://' + auth + '@saucelabs.com/rest/v1/' + auth.split(':')[0] + '/jobs/' + session.sessionID, { json: body }); return _returnType12.assert(true); } // TODO: provide instructions for converting async driver to sync driver and visa versersa }]); return Driver; }(); /* * End this Driver session * * Alias for `dispose` * @method quit */ _flowRuntime2.default.any().assert(Driver.prototype).quit = Driver.prototype.dispose; function startTaxiRank(connection /*: Connection*/) /*: () => void*/ { var _connectionType2 = _flowRuntime2.default.ref(_connection2.default); var _returnType13 = _flowRuntime2.default.return(_flowRuntime2.default.function(_flowRuntime2.default.return(_flowRuntime2.default.void()))); _flowRuntime2.default.param('connection', _connectionType2).assert(connection); var started = false; try { var res = connection.request('GET', '/version', { noRetries: true }); if (res.statusCode === 200) { var version = JSON.parse(res.body.toString('utf8')); var expectedVersion = require('taxi-rank/package.json').version; started = version === expectedVersion; } } catch (ex) {} if (process.env.CI) { if (started) return _returnType13.assert(function () {}); var taxiRank = (0, _crossSpawn2.default)(process.execPath, [require.resolve('./taxi-rank-ci.js')], { stdio: ['inherit', 'inherit', 'inherit'] }); return _returnType13.assert(function () { return taxiRank.kill(); }); } if (!started) { console.log('starting taxi rank'); (0, _crossSpawn2.default)(process.execPath, [require.resolve('./taxi-rank.js')], { detached: true, stdio: ['ignore', 'ignore', 'ignore'] }).unref(); var startTime = Date.now(); try { connection.request('GET', '/version'); } catch (ex) { var endTime = Date.now(); console.log('Failed to start a detached server after ' + Math.round((endTime - startTime) / 1000) + ' seconds.'); console.log('Starting slower, attached server.'); (0, _crossSpawn2.default)(process.execPath, [require.resolve('./taxi-rank.js')], { stdio: ['inherit', 'inherit', 'inherit'] }); } } // this could be done in process for async mode, but must be a separate process for sync mode var logger = (0, _crossSpawn2.default)(process.execPath, [require.resolve('./taxi-rank-log.js')], { stdio: ['inherit', 'inherit', 'inherit'] }); return _returnType13.assert(function () { logger.kill(); }); } _flowRuntime2.default.annotate(startTaxiRank, _flowRuntime2.default.function(_flowRuntime2.default.param('connection', _flowRuntime2.default.ref(_connection2.default)), _flowRuntime2.default.return(_flowRuntime2.default.function(_flowRuntime2.default.return(_flowRuntime2.default.void()))))); function createSession(remote /*: string*/, connection /*: Connection*/, options /*: Options*/) /*: Session*/ { var _remoteType3 = _flowRuntime2.default.string(); var _connectionType3 = _flowRuntime2.default.ref(_connection2.default); var _optionsType3 = _flowRuntime2.default.ref(Options); var _returnType14 = _flowRuntime2.default.return(_flowRuntime2.default.ref(Session)); _flowRuntime2.default.param('remote', _remoteType3).assert(remote); _flowRuntime2.default.param('connection', _connectionType3).assert(connection); _flowRuntime2.default.param('options', _optionsType3).assert(options); if (options.session !== undefined) { return _returnType14.assert(options.session); } var capabilities = _flowRuntime2.default.object().assert({}); capabilities.desiredCapabilities = options.capabilities || {}; if (options.requiredCapabilities) { capabilities.requiredCapabilities = options.requiredCapabilities; } var res = connection.request('POST', '/session', { json: capabilities }); if (res.statusCode !== 200) { switch (remote) { case 'saucelabs': if (res.statusCode === 401) { var err = new Error('Sauce Labs Authentication Failed.\r\nCheck the value of the SAUCE_USERNAME and SAUCE_ACCESS_KEY ' + 'environment variables exactly match your credentials, you passed in: ' + (0, _stringify2.default)(options.sauceUsername) + ' and ' + (0, _stringify2.default)(options.sauceAccessKey) + '.'); throw err; } break; case 'browserstack': if (res.statusCode === 401) { var _err = new Error('Browser Stack Authentication Failed.\r\nCheck the value of the BROWSER_STACK_USERNAME and BROWSER_STACK_ACCESS_KEY ' + 'environment variables exactly match your credentials, you passed in: ' + (0, _stringify2.default)(options.browserStackUsername) + ' and ' + (0, _stringify2.default)(options.browserStackAccessKey) + '.'); throw _err; } break; case 'testingbot': if (res.statusCode === 401) { var _err2 = new Error('Testing Bot Authentication Failed.\r\nCheck the value of the TESTING_BOT_KEY and TESTING_BOT_SECRET ' + 'environment variables exactly match your credentials, you passed in: ' + (0, _stringify2.default)(options.testingBotKey) + ' and ' + (0, _stringify2.default)(options.testingBotSecret) + '.'); throw _err2; } break; } throw new Error('Failed to start a Selenium session. ' + remote + ' responded with status code ' + res.statusCode + ':\n' + res.body.toString('utf8')); } var body = JSON.parse(res.body.toString('utf8')); if (body.status === 0) { return _returnType14.assert({ sessionID: body.sessionId, capabilities: body.value }); } else { throw (0, _errors.fromBody)(body); } } _flowRuntime2.default.annotate(createSession, _flowRuntime2.default.function(_flowRuntime2.default.param('remote', _flowRuntime2.default.string()), _flowRuntime2.default.param('connection', _flowRuntime2.default.ref(_connection2.default)), _flowRuntime2.default.param('options', _flowRuntime2.default.ref(Options)), _flowRuntime2.default.return(_flowRuntime2.default.ref(Session)))); var environmentAliases = { SAUCE_USERNAME: 'sauceUsername', SAUCE_ACCESS_KEY: 'sauceAccessKey', BROWSER_STACK_USERNAME: 'browserStackUsername', BROWSER_STACK_ACCESS_KEY: 'browserStackAccessKey', TESTING_BOT_KEY: 'testingBotkey', TESTING_BOT_SECRET: 'testingBotSecret', // deprecated aliases TESTINGBOT_KEY: 'testingBotkey', TESTINGBOT_SECRET: 'testingBotSecret' }; function addEnvironment(options /*: Options*/) /*: Options*/ { var _optionsType4 = _flowRuntime2.default.ref(Options); var _returnType15 = _flowRuntime2.default.return(_flowRuntime2.default.ref(Options)); _flowRuntime2.default.param('options', _optionsType4).assert(options); var result = (0, _extends3.default)({}, options); (0, _keys2.default)(environmentAliases).forEach(function (key) { if (result[environmentAliases[key]] === undefined && process.env[key]) { result[environmentAliases[key]] = process.env[key]; } }); try { var parsedObj = (0, _dotenv.parse)((0, _fs.readFileSync)('.env.local', 'utf8')); (0, _keys2.default)(environmentAliases).forEach(function (key) { if (result[environmentAliases[key]] === undefined && parsedObj[key]) { result[environmentAliases[key]] = parsedObj[key]; } }); } catch (e) {} try { var _parsedObj = (0, _dotenv.parse)((0, _fs.readFileSync)('.env', 'utf8')); (0, _keys2.default)(environmentAliases).forEach(function (key) { if (result[environmentAliases[key]] === undefined && _parsedObj[key]) { result[environmentAliases[key]] = _parsedObj[key]; } }); } catch (e) {} return _returnType15.assert(result); } _flowRuntime2.default.annotate(addEnvironment, _flowRuntime2.default.function(_flowRuntime2.default.param('options', _flowRuntime2.default.ref(Options)), _flowRuntime2.default.return(_flowRuntime2.default.ref(Options)))); (0, _addDebugging2.default)(Driver); exports.default = Driver;