UNPKG

@kronoslive/codeceptjs

Version:

Supercharged End 2 End Testing Framework for NodeJS

225 lines (199 loc) 6.37 kB
const event = require('./event'); const recorder = require('./recorder'); const assertThrown = require('./assert/throws'); const { isAsyncFunction } = require('./utils'); const parser = require('./parser'); const injectHook = function (inject, suite) { try { inject(); } catch (err) { recorder.throw(err); } recorder.catch((err) => { event.emit(event.test.failed, suite, err); throw err; }); return recorder.promise(); }; /** * Wraps test function, injects support objects from container, * starts promise chain with recorder, performs before/after hooks * through event system. */ module.exports.test = (test) => { const testFn = test.fn; if (!testFn) { return test; } test.steps = []; test.timeout(0); test.async = true; test.fn = function (done) { recorder.errHandler((err) => { recorder.session.start('teardown'); recorder.cleanAsyncErr(); if (test.throws) { // check that test should actually fail try { assertThrown(err, test.throws); event.emit(event.test.passed, test); event.emit(event.test.finished, test); recorder.add(() => done()); return; } catch (newErr) { err = newErr; } } event.emit(event.test.failed, test, err); event.emit(event.test.finished, test); recorder.add(() => done(err)); }); Object.defineProperty(testFn, 'name', { value: 'Scenario' }); if (isAsyncFunction(testFn)) { event.emit(event.test.started, test); const catchError = e => { recorder.throw(e); recorder.catch((e) => { const err = (recorder.getAsyncErr() === null) ? e : recorder.getAsyncErr(); recorder.session.start('teardown'); recorder.cleanAsyncErr(); event.emit(event.test.failed, test, err); event.emit(event.test.finished, test); recorder.add(() => done(err)); }); }; let injectedArguments; try { injectedArguments = getInjectedArguments(testFn, test); } catch (e) { catchError(e); return; } testFn.call(test, injectedArguments).then(() => { recorder.add('fire test.passed', () => { event.emit(event.test.passed, test); event.emit(event.test.finished, test); }); recorder.add('finish test', () => done()); recorder.catch(); }).catch(catchError); return; } try { event.emit(event.test.started, test); testFn.call(test, getInjectedArguments(testFn, test)); } catch (err) { recorder.throw(err); } finally { recorder.add('fire test.passed', () => { event.emit(event.test.passed, test); event.emit(event.test.finished, test); }); recorder.add('finish test', () => done()); recorder.catch(); } }; return test; }; /** * Injects arguments to function from controller */ module.exports.injected = function (fn, suite, hookName) { return function (done) { const errHandler = (err) => { recorder.session.start('teardown'); recorder.cleanAsyncErr(); event.emit(event.test.failed, suite, err); if (hookName === 'after') event.emit(event.test.after, suite); if (hookName === 'afterSuite') event.emit(event.suite.after, suite); recorder.add(() => done(err)); }; recorder.errHandler((err) => { errHandler(err); }); if (!fn) throw new Error('fn is not defined'); event.emit(event.hook.started, suite); if (!recorder.isRunning()) { recorder.start(); recorder.errHandler((err) => { errHandler(err); }); } this.test.body = fn.toString(); Object.defineProperty(fn, 'name', { value: hookName }); if (isAsyncFunction(fn)) { fn.call(this, getInjectedArguments(fn)).then(() => { recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite)); recorder.add(`finish ${hookName} hook`, () => done()); recorder.catch(); }).catch((e) => { recorder.throw(e); recorder.catch((e) => { const err = (recorder.getAsyncErr() === null) ? e : recorder.getAsyncErr(); errHandler(err); }); recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e)); }); return; } try { fn.call(this, getInjectedArguments(fn)); recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite)); recorder.add(`finish ${hookName} hook`, () => done()); recorder.catch(); } catch (err) { recorder.throw(err); recorder.catch((e) => { const err = (recorder.getAsyncErr() === null) ? e : recorder.getAsyncErr(); errHandler(err); }); recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, err)); } }; }; /** * Starts promise chain, so helpers could enqueue their hooks */ module.exports.setup = function (suite) { return injectHook(() => { recorder.startUnlessRunning(); event.emit(event.test.before, suite && suite.ctx && suite.ctx.currentTest); }, suite); }; module.exports.teardown = function (suite) { return injectHook(() => { recorder.startUnlessRunning(); event.emit(event.test.after, suite && suite.ctx && suite.ctx.currentTest); }, suite); }; module.exports.suiteSetup = function (suite) { return injectHook(() => { recorder.startUnlessRunning(); event.emit(event.suite.before, suite); }, suite); }; module.exports.suiteTeardown = function (suite) { return injectHook(() => { recorder.startUnlessRunning(); event.emit(event.suite.after, suite); }, suite); }; const getInjectedArguments = (fn, test) => { const container = require('./container'); const testArgs = {}; const params = parser.getParams(fn) || []; const objects = container.support(); for (const key of params) { testArgs[key] = {}; if (test && test.inject && test.inject[key]) { // @FIX: need fix got inject testArgs[key] = test.inject[key]; continue; } if (!objects[key]) { throw new Error(`Object of type ${key} is not defined in container`); } testArgs[key] = container.support(key); } return testArgs; }; module.exports.getInjectedArguments = getInjectedArguments;