Created
September 6, 2016 06:45
-
-
Save puyo/03b03a295d482ccde62f6403f8a11101 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Imagine if we had a test framework that did this :...( | |
const models = require('../models') | |
const logger = require('../logger') | |
const Promise = require('bluebird') | |
const co = require('co') | |
const isGenFn = require('is-generator').fn | |
const colors = require('colors/safe') | |
function transactionStrategy(mocha) { | |
if (!mocha || mocha._transactionStrategy) { | |
return | |
} | |
const Runnable = mocha.Runnable | |
const oldRun = Runnable.prototype.run | |
function newRun(done) { | |
if (this.type === 'hook') { | |
return oldRun.bind(this)(done) | |
} | |
// We are attempting to run a test function (this.fn) | |
const self = this | |
const runPromise = Promise.promisify(oldRun.bind(self)) | |
const title = this.title | |
// Cope with the test function being a generator (use co.wrap) | |
const maybeGenFn = this.fn | |
if (isGenFn(maybeGenFn)) { | |
this.fn = co.wrap(maybeGenFn) | |
// Replace `toString` to output the original function contents. | |
this.fn.toString = function () { | |
// https://github.com/mochajs/mocha/blob/7493bca76662318183e55294e906a4107433e20e/lib/utils.js#L251 | |
return Function.prototype.toString.call(maybeGenFn) | |
.replace(/^function *\* *\(.*\)\s*{/, 'function () {') | |
} | |
} | |
// Wrap the test function (this.fn) in a transaction that rolls back | |
// regardless of the test outcome | |
const noTxFn = this.fn | |
this.fn = function(ctx) { | |
logger.info(colors.magenta("-----> " + title)) | |
//logger.debug('CALLING FN WRAPPER') | |
return models.sequelize.transaction({autocommit: false}) | |
.then(tx => { | |
models.Sequelize.cls.set('transaction', tx) // ensures correct use of SAVEPOINT | |
//logger.debug('IN TX, CALLING ACTUAL TEST FN') | |
const result = noTxFn.call(self, ctx) | |
let promise | |
if (result && typeof result.then === 'function') { | |
promise = result | |
} else { | |
promise = Promise.resolve(result) | |
} | |
//logger.debug('EXECUTING TEST PROMISE') | |
return promise | |
.then(err => { | |
//logger.debug("ROLLING BACK") | |
models.Sequelize.cls.set('transaction', null) // avoids double rollback | |
return tx.rollback() | |
.then(_ => logger.info(colors.green("<----- " + title))) | |
}, err => { | |
//logger.error("ERROR IN TEST", err.message) | |
return tx.rollback() | |
.then(_ => logger.info(colors.red("<----- " + title))) | |
.thenThrow(err) | |
}) | |
}) | |
} | |
oldRun.call(self, done) | |
} | |
Runnable.prototype.run = newRun | |
mocha._transactionStrategy = true | |
} | |
const mocha = require('mocha') | |
transactionStrategy(mocha) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Don't know if you're still working with sequelize... but if you are, did you ever work things out so your code itself could have transactions, and they'd work fine as nested transactions within the tests using the above transaction strategy?