UNPKG

wdio-workflo-jasmine-framework

Version:

This is a customized version of wdio-jasmine-framework for use with workflo framework.

273 lines (228 loc) 8.95 kB
import Jasmine from 'jasmine' import JasmineReporter from './reporter' import { runInFiberContext, wrapCommands, executeHooksWithArgs } from 'wdio-sync' const INTERFACES = { bdd: ['beforeAll', 'beforeEach', 'it', 'xit', 'fit', 'afterEach', 'afterAll'] } const DEFAULT_TIMEOUT_INTERVAL = 60000 /** * Jasmine 2.x runner */ class JasmineAdapter { constructor (cid, config, specs = [], capabilities = {}) { this.cid = cid this.capabilities = capabilities this.specs = specs this.config = Object.assign({}, config) this.jasmineNodeOpts = Object.assign({ cleanStack: true }, config.jasmineNodeOpts) this.jrunner = {} this.reporter = new JasmineReporter({ cid: this.cid, capabilities: this.capabilities, specs: this.specs, cleanStack: this.jasmineNodeOpts.cleanStack }) } async run () { let self = this this.jrunner = new Jasmine() let jasmine = this.jrunner.jasmine this.orPending = global['pending'] this.jrunner.projectBaseDir = '' this.jrunner.specDir = '' this.jrunner.addSpecFiles(this.specs) jasmine.DEFAULT_TIMEOUT_INTERVAL = this.getDefaultInterval() jasmine.getEnv().addReporter(this.reporter) /** * Filter specs to run based on jasmineNodeOpts.grep and jasmineNodeOpts.invert */ jasmine.getEnv().specFilter = (spec) => { let grepMatch = this.getGrepMatch(spec) let invertGrep = !!this.jasmineNodeOpts.invertGrep if (grepMatch === invertGrep) { spec.pend() } return true } // provide execution filters deciding of jasmine functions should be called or not jasmine.getEnv().testInfoFilePath = this.config.testInfoFilePath /** * enable expectHandler */ jasmine.Spec.prototype.addExpectationResult = this.getExpectationResultHandler(jasmine) /** * patch jasmine to support promises */ INTERFACES['bdd'].forEach((fnName) => { const origFn = global[fnName] global[fnName] = (...args) => { const retryCnt = typeof args[args.length - 1] === 'number' ? args.pop() : 0 const specFn = typeof args[0] === 'function' ? args.shift() : (typeof args[1] === 'function' ? args.pop() : undefined) const specTitle = args[0] const patchedOrigFn = function (done) { // specFn will be replaced by wdio-sync and will always return a promise return specFn.call(this).then(() => done(), (e) => done.fail(e)) } const newArgs = [specTitle, patchedOrigFn, retryCnt].filter(a => Boolean(a)) if (!specFn) { return origFn(specTitle) } return origFn.apply(this, newArgs) } }) /** * wrap commands with wdio-sync */ wrapCommands(global.browser, this.config.beforeCommand, this.config.afterCommand) INTERFACES['bdd'].forEach((fnName) => runInFiberContext( ['it', 'fit'], this.config.beforeHook, this.config.afterHook, fnName )) /** * for a clean stdout we need to avoid that Jasmine initialises the * default reporter */ Jasmine.prototype.configureDefaultReporter = () => {} /** * wrap Suite and Spec prototypes to get access to their data */ let beforeAllMock = jasmine.Suite.prototype.beforeAll jasmine.Suite.prototype.beforeAll = function (...args) { self.lastSpec = this.result beforeAllMock.apply(this, args) } let executeMock = jasmine.Spec.prototype.execute jasmine.Spec.prototype.execute = function (...args) { self.lastTest = this.result self.lastTest.start = new Date().getTime() executeMock.apply(this, args) } await executeHooksWithArgs(this.config.before, [this.capabilities, this.specs, this.config.executionFilters]) let result = await new Promise((resolve) => { this.jrunner.env.beforeAll(this.wrapHook('beforeSuite')) this.jrunner.env.beforeEach(this.wrapHook('beforeTest')) this.jrunner.env.afterEach(this.wrapHook('afterTest')) this.jrunner.env.afterAll(this.wrapHook('afterSuite')) this.jrunner.onComplete(() => resolve(this.reporter.getFailedCount())) this.jrunner.execute() }) await executeHooksWithArgs(this.config.after, [result, this.capabilities, this.specs]) await this.reporter.waitUntilSettled() return result } /** * Hooks which are added as true Mocha hooks need to call done() to notify async */ wrapHook (hookName) { return (done) => executeHooksWithArgs( this.config[hookName], this.prepareMessage(hookName) ).then(() => done(), (e) => { console.log(`Error in ${hookName} hook: ${e.stack.slice(7)}`) done() }) } prepareMessage (hookName) { const params = { type: hookName } switch (hookName) { case 'beforeSuite': case 'afterSuite': params.payload = Object.assign({ file: this.jrunner.specFiles[0] }, this.lastSpec) break case 'beforeTest': case 'afterTest': params.payload = Object.assign({ file: this.jrunner.specFiles[0] }, this.lastTest) break } return this.formatMessage(params) } formatMessage (params) { let message = { type: params.type } if (params.err) { message.err = { message: params.err.message, stack: params.err.stack } } if (params.payload) { message.title = params.payload.description message.fullName = params.payload.fullName || null message.file = params.payload.file if (params.payload.type && params.payload.type === 'test') { message.parent = this.lastSpec.description message.passed = params.payload.failedExpectations.length === 0 } if (params.type === 'afterTest') { message.duration = new Date().getTime() - params.payload.start } if (typeof params.payload.duration === 'number') { message.duration = params.payload.duration } } return message } getDefaultInterval () { let { jasmineNodeOpts } = this if (jasmineNodeOpts.defaultTimeoutInterval) { return jasmineNodeOpts.defaultTimeoutInterval } return DEFAULT_TIMEOUT_INTERVAL } getGrepMatch (spec) { let { grep } = this.jasmineNodeOpts return !grep || spec.getFullName().match(new RegExp(grep)) !== null } getExpectationResultHandler (jasmine) { let { jasmineNodeOpts } = this const origHandler = jasmine.Spec.prototype.addExpectationResult if (typeof jasmineNodeOpts.expectationResultHandler !== 'function') { return origHandler } return this.expectationResultHandler(origHandler) } expectationResultHandler (origHandler) { let { expectationResultHandler } = this.jasmineNodeOpts let result return function (passed, data) { try { expectationResultHandler.call(global.browser, passed, data) result = origHandler.call(this, passed, data) if (!passed) { this.result.failedExpectations[this.result.failedExpectations.length - 1].specObj = data.specObj } } catch (e) { /** * propagate expectationResultHandler error if actual assertion passed */ if (passed) { passed = false data = { passed: false, message: 'expectationResultHandlerError: ' + e.message } } result = origHandler.call(this, passed, data) } return result } } } const _JasmineAdapter = JasmineAdapter const adapterFactory = {} adapterFactory.run = async function (cid, config, specs, capabilities) { const adapter = new _JasmineAdapter(cid, config, specs, capabilities) const result = await adapter.run() return result } export default adapterFactory export { JasmineAdapter, adapterFactory }