UNPKG

@wdio/crossbrowsertesting-service

Version:

A WebdriverIO service that manages local tunnel and job metadata for CrossBrowserTesting users.

180 lines (179 loc) 6.39 kB
import got from 'got'; import logger from '@wdio/logger'; const log = logger('@wdio/crossbrowsertesting-service'); const jobDataProperties = ['name', 'tags', 'public', 'build', 'extra']; export default class CrossBrowserTestingService { _config; _capabilities; _browser; _testCnt = 0; _failures = 0; _isServiceEnabled; _suiteTitle; _cbtUsername; _cbtAuthkey; constructor(_config, _capabilities) { this._config = _config; this._capabilities = _capabilities; this._cbtUsername = this._config.user; this._cbtAuthkey = this._config.key; this._isServiceEnabled = !!(this._cbtUsername && this._cbtAuthkey); } before(caps, specs, browser) { this._browser = browser; } /** * Before suite * @param {object} suite Suite */ beforeSuite(suite) { this._suiteTitle = suite.title; } /** * Before test * @param {object} test Test */ beforeTest(test) { if (!this._isServiceEnabled) { return; } /** * in jasmine we get Jasmine__TopLevel__Suite as title since service using test * framework hooks in order to execute async functions. * This tweak allows us to set the real suite name for jasmine jobs. */ /* istanbul ignore if */ if (this._suiteTitle === 'Jasmine__TopLevel__Suite') { this._suiteTitle = test.fullName.slice(0, test.fullName.indexOf(test.title) - 1); } } afterSuite(suite) { if (Object.prototype.hasOwnProperty.call(suite, 'error')) { ++this._failures; } } /** * After test * @param {object} test Test */ afterTest(test, context, results) { if (!results.passed) { ++this._failures; } } /** * For CucumberJS * * Before feature * @param {string} uri * @param {object} feature */ beforeFeature(uri, feature) { if (!this._isServiceEnabled) { return; } this._suiteTitle = feature.name; } /** * * Runs before a Cucumber Scenario. * @param {ITestCaseHookParameter} world world object containing information on pickle and test step * @param {object} result results object containing scenario results * @param {boolean} result.passed true if scenario has passed * @param {string} result.error error stack if scenario failed * @param {number} result.duration duration of scenario in milliseconds */ afterScenario(world, result) { // check if scenario has failed if (!result.passed) { ++this._failures; } } /** * Update info * @return {Promise} Promsie with result of updateJob method call */ after(result) { if (!this._isServiceEnabled || !this._browser) { return; } let failures = this._failures; /** * set failures if user has bail option set in which case afterTest and * afterSuite aren't executed before after hook */ if (this._config.mochaOpts && this._config.mochaOpts.bail && Boolean(result)) { failures = 1; } const status = 'status: ' + (failures > 0 ? 'failing' : 'passing'); if (!this._browser.isMultiremote) { log.info(`Update job with sessionId ${this._browser.sessionId}, ${status}`); return this.updateJob(this._browser.sessionId, failures); } const browser = this._browser; return Promise.all(Object.keys(this._capabilities).map((browserName) => { log.info(`Update multiremote job for browser "${browserName}" and sessionId ${browser.getInstance(browserName).sessionId}, ${status}`); return this.updateJob(browser.getInstance(browserName).sessionId, failures, false, browserName); })); } onReload(oldSessionId, newSessionId) { if (!this._isServiceEnabled || !this._browser) { return; } const status = 'status: ' + (this._failures > 0 ? 'failing' : 'passing'); if (!this._browser.isMultiremote) { log.info(`Update (reloaded) job with sessionId ${oldSessionId}, ${status}`); return this.updateJob(oldSessionId, this._failures, true); } const browserName = this._browser.instances.filter((browserName) => this._browser.getInstance(browserName).sessionId === newSessionId)[0]; log.info(`Update (reloaded) multiremote job for browser "${browserName}" and sessionId ${oldSessionId}, ${status}`); return this.updateJob(oldSessionId, this._failures, true, browserName); } async updateJob(sessionId, failures, calledOnReload = false, browserName) { const json = this.getBody(failures, calledOnReload, browserName); this._failures = 0; const response = await got.put(this.getRestUrl(sessionId), { json, responseType: 'json', username: this._cbtUsername, password: this._cbtAuthkey }); return response.body; } /** * * @param {string} sessionId Session id * @returns {String} */ getRestUrl(sessionId) { return `https://crossbrowsertesting.com/api/v3/selenium/${sessionId}`; } getBody(failures, calledOnReload = false, browserName) { const body = { test: {} }; /** * set default values */ body.test.name = this._suiteTitle; /** * add reload count to title if reload is used */ if ((calledOnReload || this._testCnt) && this._browser) { let testCnt = ++this._testCnt; if (this._browser.isMultiremote) { testCnt = Math.ceil(testCnt / this._browser.instances.length); } body.test.name += ` (${testCnt})`; } for (const prop of jobDataProperties) { if (!this._capabilities[prop]) { continue; } body.test[prop] = this._capabilities[prop]; } if (browserName) { body.test.name = `${browserName}: ${body.test.name}`; } body.test.success = failures === 0 ? '1' : '0'; return body; } }