qunit-harness
Version:
A library for running qunit tests on a local machine and in the SauceLabs environment.
380 lines (289 loc) • 13.6 kB
JavaScript
;
var _createClass = require('babel-runtime/helpers/create-class').default;
var _classCallCheck = require('babel-runtime/helpers/class-call-check').default;
var _regeneratorRuntime = require('babel-runtime/regenerator').default;
var _Object$keys = require('babel-runtime/core-js/object/keys').default;
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default').default;
exports.__esModule = true;
var _webdriver = require('webdriver');
var _webdriver2 = _interopRequireDefault(_webdriver);
var _wdioProtocols = require('@wdio/protocols');
var _lodash = require('lodash');
var _request = require('./request');
var _request2 = _interopRequireDefault(_request);
var _utilsWait = require('../utils/wait');
var _utilsWait2 = _interopRequireDefault(_utilsWait);
var _utilsIsSafari15 = require('../utils/is-safari-15');
var _utilsIsSafari152 = _interopRequireDefault(_utilsIsSafari15);
var CHECK_TEST_RESULT_DELAY = 10 * 1000;
var MAX_JOB_RESTART_COUNT = 3;
var BROWSER_INIT_RETRIES = 3;
var BROWSER_INIT_TIMEOUT = 9 * 60 * 1000;
var SAUCE_API_HOST = 'saucelabs.com';
var SAUCE_API_PORT = 80;
// NOTE: Saucelabs cannot start tests in Safari 15 immediately.
// So, we are forced to add delay before test execution.
var TEST_RUN_DELAY_FOR_SAFARI_15 = 30 * 1000;
//Job
var Job = (function () {
function Job(options, browserInfo) {
_classCallCheck(this, Job);
this.options = {
username: options.username,
accessKey: options.accessKey,
build: options.build,
testName: options.testName,
tags: options.tags,
urls: options.urls,
tunnelIdentifier: options.tunnelIdentifier,
testsTimeout: options.timeout * 1000
};
this.requestAdapter = new _request2.default(this.options.username, this.options.accessKey);
this.browserInfo = browserInfo;
this.browser = null;
this.status = Job.STATUSES.INITIALIZED;
this.restartCount = 0;
this.startTestsTime = null;
var platformName = browserInfo.platform || browserInfo.platformName || '';
var browserName = browserInfo.browserName || '';
var plaformVersion = browserInfo.version || browserInfo.platformVersion || '';
this.platform = [platformName, browserName, plaformVersion];
}
Job.prototype._getTestResult = function _getTestResult() {
var testResult, windowErrorMessage, ie11ErrorMessage;
return _regeneratorRuntime.async(function _getTestResult$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
testResult = null;
case 1:
if (testResult) {
context$2$0.next = 20;
break;
}
if (!(new Date() - this.startTestsTime > this.options.testsTimeout)) {
context$2$0.next = 4;
break;
}
throw new Error('Test exceeded maximum duration');
case 4:
context$2$0.next = 6;
return _regeneratorRuntime.awrap(_utilsWait2.default(CHECK_TEST_RESULT_DELAY));
case 6:
context$2$0.prev = 6;
context$2$0.next = 9;
return _regeneratorRuntime.awrap(this.browser.executeScript('return window.global_test_results', []));
case 9:
testResult = context$2$0.sent;
context$2$0.next = 18;
break;
case 12:
context$2$0.prev = 12;
context$2$0.t0 = context$2$0['catch'](6);
windowErrorMessage = 'window has no properties';
ie11ErrorMessage = ['Error response status: 13, , ', 'UnknownError - An unknown server-side error occurred while processing the command. ', 'Selenium error: JavaScript error (WARNING: The server did not provide any stacktrace information)'].join('');
if (!(context$2$0.t0.message.indexOf(windowErrorMessage) < 0 && context$2$0.t0.message.indexOf(ie11ErrorMessage) < 0)) {
context$2$0.next = 18;
break;
}
throw context$2$0.t0;
case 18:
context$2$0.next = 1;
break;
case 20:
return context$2$0.abrupt('return', testResult);
case 21:
case 'end':
return context$2$0.stop();
}
}, null, this, [[6, 12]]);
};
Job.prototype._getJobResult = function _getJobResult() {
var testResult;
return _regeneratorRuntime.async(function _getJobResult$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
this.status = Job.STATUSES.IN_PROGRESS;
this.startTestsTime = new Date();
context$2$0.next = 4;
return _regeneratorRuntime.awrap(this._getTestResult());
case 4:
testResult = context$2$0.sent;
this.status = Job.STATUSES.COMPLETED;
context$2$0.prev = 6;
context$2$0.next = 9;
return _regeneratorRuntime.awrap(this._publishTestResult(testResult));
case 9:
context$2$0.next = 14;
break;
case 11:
context$2$0.prev = 11;
context$2$0.t0 = context$2$0['catch'](6);
this._reportError('An error occurred while the test result was being published: ' + context$2$0.t0);
case 14:
return context$2$0.abrupt('return', {
url: 'https://' + SAUCE_API_HOST + '/jobs/' + this.browser.sessionId,
platform: this.platform,
result: testResult,
job_id: this.browser.sessionId
});
case 15:
case 'end':
return context$2$0.stop();
}
}, null, this, [[6, 11]]);
};
Job.prototype._reportError = function _reportError(error) {
console.log('The task (' + this.platform + ') failed: ' + error);
};
Job.prototype._publishTestResult = function _publishTestResult(testResult) {
var testSuccess, data;
return _regeneratorRuntime.async(function _publishTestResult$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
testSuccess = (testResult.errors.length === 0 || _Object$keys(testResult.errors).length === 0) && testResult.failed === 0;
data = {
public: 'public',
passed: testSuccess,
'custom-data': {
'qunit': testResult
}
};
context$2$0.next = 4;
return _regeneratorRuntime.awrap(this.requestAdapter.put('/v1/' + this.options.username + '/jobs/' + this.browser.sessionId, data));
case 4:
case 'end':
return context$2$0.stop();
}
}, null, this);
};
Job.prototype.run = function run() {
var jobResult, jobFailed, initBrowserParams, executeCommand;
return _regeneratorRuntime.async(function run$(context$2$0) {
while (1) switch (context$2$0.prev = context$2$0.next) {
case 0:
jobResult = null;
jobFailed = false;
initBrowserParams = {
name: this.options.testName,
tags: this.options.tags,
build: this.options.build,
tunnelIdentifier: this.options.tunnelIdentifier
};
_lodash.assign(initBrowserParams, this.browserInfo);
this.status = Job.STATUSES.INIT_BROWSER;
executeCommand = _wdioProtocols.WebDriverProtocol['/session/:sessionId/execute/sync'];
_wdioProtocols.WebDriverProtocol['/session/:sessionId/execute'] = executeCommand;
context$2$0.prev = 7;
context$2$0.next = 10;
return _regeneratorRuntime.awrap(_webdriver2.default.newSession({
protocol: 'http',
hostname: 'ondemand.' + SAUCE_API_HOST,
port: SAUCE_API_PORT,
user: this.options.username,
key: this.options.accessKey,
capabilities: initBrowserParams,
logLevel: 'error',
connectionRetryTimeout: BROWSER_INIT_TIMEOUT,
connectionRetryCount: BROWSER_INIT_RETRIES,
path: '/wd/hub',
automationProtocol: 'webdriver'
}));
case 10:
this.browser = context$2$0.sent;
if (!_utilsIsSafari152.default(initBrowserParams)) {
context$2$0.next = 14;
break;
}
context$2$0.next = 14;
return _regeneratorRuntime.awrap(_utilsWait2.default(TEST_RUN_DELAY_FOR_SAFARI_15));
case 14:
context$2$0.next = 16;
return _regeneratorRuntime.awrap(this.browser.navigateTo(this.options.urls[0]));
case 16:
context$2$0.next = 22;
break;
case 18:
context$2$0.prev = 18;
context$2$0.t0 = context$2$0['catch'](7);
this._reportError('An error occurred while the browser was being initialized: ' + context$2$0.t0);
jobFailed = true;
case 22:
if (jobFailed) {
context$2$0.next = 41;
break;
}
context$2$0.prev = 23;
context$2$0.next = 26;
return _regeneratorRuntime.awrap(this._getJobResult());
case 26:
jobResult = context$2$0.sent;
context$2$0.next = 33;
break;
case 29:
context$2$0.prev = 29;
context$2$0.t1 = context$2$0['catch'](23);
this._reportError(context$2$0.t1);
jobFailed = true;
case 33:
context$2$0.prev = 33;
context$2$0.next = 36;
return _regeneratorRuntime.awrap(this.browser.deleteSession());
case 36:
context$2$0.next = 41;
break;
case 38:
context$2$0.prev = 38;
context$2$0.t2 = context$2$0['catch'](33);
this._reportError('An error occured while the browser was being closed: ' + context$2$0.t2);
case 41:
if (!jobFailed) {
context$2$0.next = 52;
break;
}
if (!(++this.restartCount < MAX_JOB_RESTART_COUNT)) {
context$2$0.next = 49;
break;
}
console.log('Attempt ' + this.restartCount + ' to restart the task (' + this.platform + ')');
context$2$0.next = 46;
return _regeneratorRuntime.awrap(this.run());
case 46:
jobResult = context$2$0.sent;
context$2$0.next = 52;
break;
case 49:
jobResult = {
platform: this.platform,
job_id: this.browser.sessionId
};
if (this.status === Job.STATUSES.IN_PROGRESS) jobResult.url = 'https://' + SAUCE_API_HOST + '/jobs/' + this.browser.sessionId;
this.status = Job.STATUSES.FAILED;
case 52:
return context$2$0.abrupt('return', jobResult);
case 53:
case 'end':
return context$2$0.stop();
}
}, null, this, [[7, 18], [23, 29], [33, 38]]);
};
Job.prototype.getStatus = function getStatus() {
return this.status;
};
_createClass(Job, null, [{
key: 'STATUSES',
value: {
INIT_BROWSER: 'init browser',
INITIALIZED: 'initialized',
IN_PROGRESS: 'in progress',
COMPLETED: 'completed',
FAILED: 'failed'
},
enumerable: true
}]);
return Job;
})();
exports.default = Job;
module.exports = exports.default;
// NOTE: this error may occur while testing against internet explorer 11.
// This may happen because the IE driver sometimes throws an unknown error
// when executing an expression with the 'window' object.