diff --git a/.meteor/versions b/.meteor/versions index 214e794..fb11d70 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -6,8 +6,9 @@ blaze@2.1.2 blaze-tools@1.0.3 boilerplate-generator@1.0.3 callback-hook@1.0.3 -canotto90:latte@0.6.4 +canotto90:latte@0.7.4 canotto90:pretty-errors@0.0.1 +cfs:http-methods@0.0.29 check@1.0.5 coffeescript@1.0.6 ddp@1.1.0 diff --git a/package.json b/package.json index 9d07a45..278a843 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "describe", "ddescribe", "context", "ccontext", "it", "iit", "beforeAll", "beforeEach", "T", "afterAll", "afterEach", "expect", "should", "_", - "figures", "Npm" + "figures", "Npm", "HTTP" ] } } diff --git a/packages/latte/http_api.js b/packages/latte/http_api.js new file mode 100644 index 0000000..af28db3 --- /dev/null +++ b/packages/latte/http_api.js @@ -0,0 +1,9 @@ +HTTP.methods({ + '/test': { + get: function () { + T.needToBoot = false + T.run(this.query.suite) + } + } +}) + diff --git a/packages/latte/latte.js b/packages/latte/latte.js index e624587..cc618fc 100644 --- a/packages/latte/latte.js +++ b/packages/latte/latte.js @@ -1,28 +1,46 @@ var figures = Npm.require('figures') +var readFile = Meteor.wrapAsync(Npm.require('fs').readFile) T = { // eslint-disable-line - analize: function () { // this lets us analyze suite's structure to act accordingly later (allowing, for example, iit blocks to work) - T.analyzing = true - T.suites.forEach(exec) - T.analyzing = false - }, - run: function () { + run: function (input) { if (!process.env.RUN_TESTS) { return } + console.log('T.onlySuites', T.onlySuites) + console.log('T.analyzing', T.analyzing) + + T.preProcess = false + T.describeBlocks.forEach(exec) + getOnlySuitesFromInput(input) + console.log('T.onlySuites', T.onlySuites) + T.analyzing = false + T.needToBoot = false var testingDB = new global.MongoInternals.RemoteCollectionDriver(T.testingDbUrl) // create a driver pointing to testing's DB getCollections().forEach(pointToTestingDB) // point collections to testing's DB getCollections().forEach(removeAll) // erase date on testing DB (though there should be none) + console.log('0') + console.log('T.onlyRootDescribeBlocksForIit', T.onlyRootDescribeBlocksForIit) T.onlyRootDescribeBlocksForIit.length ? T.onlyRootDescribeBlocksForIit.forEach(exec) : T.suites.forEach(exec) // if there's `iit` blocks, only run those // output number of successful over total tests log('\n' + (T.itCount + ' tests: ').yellow + (T.successfulItCount + ' passing, ').green + (T.itCount - T.successfulItCount + ' failing.').red) + console.log('1') getCollections().forEach(pointBackToDevelopDB) // point collections back to development's DB _(T.postRunCallbacks).reject(preventsSuiteFromRunning).map(fns).forEach(exec) // allow to run a callback when testing has finished (before possibly ending the process) + console.log('A') process.env.RUN_TESTS !== 'cont' && process.exit(T.exceptions.length) // end the process unless option is specified + console.log('B') + T.itCount = 0 + T.successfulItCount = 0 + T.analyzing = true + T.needToBoot = true + T.suites = [] + T.onlyRootDescribeBlocksForIit = [] + console.log('C') + function pointToTestingDB (collection) { collection.latte_original_driver = collection._driver // keep track of original driver, to point back to development's DB once tests have finished collection._driver = testingDB @@ -78,21 +96,11 @@ T = { // eslint-disable-line T.exceptions.push(e) // if `T.exceptions` has any item at the en of the test run, exit code will be != 0 } }, - beforeAll: function (fn) { - if (T.analyzing) { return } - T.beforeAllBlocks.push({ fn: fn, deepLevel: T.deepLevel }) // keep track of beforeAll blocks, to run them later - }, - beforeEach: function (fn) { - if (T.analyzing) { return } - T.beforeEachBlocks.push({ fn: fn, deepLevel: T.deepLevel }) - }, - afterAll: function (fn) { - if (T.analyzing) { return } - T.afterAllBlocks.push({ fn: fn, deepLevel: T.deepLevel }) - }, - afterEach: function (fn) { - if (T.analyzing) { return } - T.afterEachBlocks.push({ fn: fn, deepLevel: T.deepLevel }) + defineHook: function (type) { + return function (fn) { + if (T.analyzing) { return } + T[type + 'Blocks'].push({ fn: fn, deepLevel: T.deepLevel }) + } }, message: function (type, label, deepLevel) { // pretty print messages for console report var prefix = '' @@ -116,8 +124,9 @@ T = { // eslint-disable-line onlyRootDescribeBlocksForIit: [], describeMessages: [], itBlockRunLevel: 0, - isFirstAddedSuite: true, + needToBoot: true, analyzing: true, + preProcess: true, onlySuites: [], testingDbUrl: 'mongodb://127.0.0.1:3001/meteor_latte' } @@ -139,32 +148,18 @@ function descriptionBlock (type, options) { if (!process.env.RUN_TESTS) { return function () {} } // don't run any test related stuff unless explicitly told so options = options || {} - return function analyzeOrExec (label, fn) { + return function describeBlock (label, fn) { + T.needToBoot && Meteor.startup(T.run) + T.needToBoot = false + if (T.preProcess) { return T.describeBlocks.push(describeBlock.bind(this, label, fn)) } if (T.deepLevel === 0 && options.runOnly && !excludedSuite(T.onlySuites, label) && !T.onlySuitesAsUserParams) { T.onlySuites.push(label) } if (T.deepLevel === 0 && preventsSuiteFromRunning(label)) { return } - - return (T.analyzing ? analizeBlock(label, fn) : describeBlock(label, fn)) - } - - function analizeBlock (label, fn) { - if (T.deepLevel === 0) { + if (T.analyzing && T.deepLevel === 0) { var testSuite = describeBlock.bind(this, label, fn) T.currentRootDescribeBlock = testSuite T.suites.push(testSuite) - T.isFirstAddedSuite && Meteor.startup(function () { // upon first suite addition, add a callback to startup to run tests - T.analize() // look at suites structure and prepare the test run (this allows, for example, iit behavior) - T.run() // run code defined inside suites (describe blocks) - }) - T.isFirstAddedSuite = false } - T.deepLevel++ - fn() - T.deepLevel-- - } - - function describeBlock (label, fn) { - if (T.deepLevel === 0 && preventsSuiteFromRunning(label)) { return } - T.describeMessages.push(T.message(type, label, T.deepLevel)) + !T.analyzing && T.describeMessages.push(T.message(type, label, T.deepLevel)) T.deepLevel++ fn() if (T.itBlockRunLevel >= T.deepLevel) { @@ -237,6 +232,20 @@ function getCollections () { } } +// input can be either the file or the describe label to run +function getOnlySuitesFromInput (input) { + if (!input) { return } + var onlySuites = null + var file = null + try { file = input && readFile(input.toString()).toString() } catch(e) {} + if (file) { + var start = file.indexOf('describe(') + 'describe('.length + 1 + var end = file.indexOf(', function') - 1 + onlySuites = [file.substring(start, end)] + } + T.onlySuites = onlySuites || input +} + // Global variables are not attached to the `global` object in Meteor packages, so we ignore style checker for this section. // Details: http://stackoverflow.com/questions/31526454/global-variables-not-being-attached-to-the-global-object-on-meteorjs-packages @@ -245,10 +254,10 @@ describe = T.describe.bind(T) context = T.context.bind(T) it = T.it.bind(T) iit = T.iit.bind(T) -beforeAll = T.beforeAll.bind(T) -beforeEach = T.beforeEach.bind(T) -afterAll = T.afterAll.bind(T) -afterEach = T.afterEach.bind(T) +beforeAll = T.defineHook('beforeAll').bind(T) +beforeEach = T.defineHook('beforeEach').bind(T) +afterAll = T.defineHook('afterAll').bind(T) +afterEach = T.defineHook('afterEach').bind(T) ddescribe = T.ddescribe.bind(T) ccontext = T.ccontext.bind(T) /*eslint-enable */ diff --git a/packages/latte/package.js b/packages/latte/package.js index 2686915..92aa555 100644 --- a/packages/latte/package.js +++ b/packages/latte/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'canotto90:latte', - version: '0.6.4', + version: '0.7.4', summary: 'Run mocha-like specs in Meteor, without Velocity\'s overhead.', git: 'https://github.com/taromero/latte.git', documentation: '../../README.md' @@ -13,7 +13,9 @@ Npm.depends({ Package.onUse(function (api) { api.use('mongo@1.1.0', 'server') api.use('nooitaf:colors@0.0.2') + api.use('cfs:http-methods@0.0.29') api.addFiles('latte.js', 'server') + api.addFiles('http_api.js', 'server') api.export('T', 'server') api.export('describe', 'server') api.export('context', 'server') diff --git a/specs/ddescribe_iit_spec.js b/specs/ddescribe_iit_spec.js index 6969eba..7b35294 100644 --- a/specs/ddescribe_iit_spec.js +++ b/specs/ddescribe_iit_spec.js @@ -24,7 +24,9 @@ describe('describe block containing an iit block, in presence of a ddescribe blo T.postRunCallbacks.push({ label: 'ddescribe should take precedence over iit blocks', fn: function () { - if (ddescribeCounter !== 1) { throw new Error('some assertion failed to exec. ddescribeCounter = ' + ddescribeCounter) } + console.log('prca') + if (ddescribeCounter !== 1) { console.log('prca1'); throw new Error('some assertion failed to exec. ddescribeCounter = ' + ddescribeCounter) } + console.log('prca2') } }) diff --git a/specs/ddescribe_spec.js b/specs/ddescribe_spec.js index ece4014..ecaa705 100644 --- a/specs/ddescribe_spec.js +++ b/specs/ddescribe_spec.js @@ -35,6 +35,7 @@ describe('unnested describe blocks in presence of a ddescribe block', function ( T.postRunCallbacks.push({ label: 'if there is a ddescribe block', fn: function () { + console.log('prcb') if (ddescribeCounter !== 2) { throw new Error('ddescribe_spec: some assertion failed to exec. ddescribeCounter == ' + ddescribeCounter) } } }) diff --git a/specs/iit_spec.js b/specs/iit_spec.js index d6e77f0..44c1d03 100644 --- a/specs/iit_spec.js +++ b/specs/iit_spec.js @@ -66,6 +66,7 @@ describe('iit behaviour', function () { T.postRunCallbacks.push({ label: 'iit behaviour', fn: function () { + console.log('prcd') if (iitCounter !== 3) { throw new Error('some assertion failed to exec. iitCounter == ' + iitCounter) } if (allCounter !== 4) { throw new Error('some before/afterAll block failed to exec. allCounter == ' + allCounter) } if (eachCounter !== 6) { throw new Error('some before/afterEach block failed to exec. eachCounter == ' + eachCounter) } diff --git a/specs/multiple_ddescribe_spec.js b/specs/multiple_ddescribe_spec.js index 51f7a22..9235c82 100644 --- a/specs/multiple_ddescribe_spec.js +++ b/specs/multiple_ddescribe_spec.js @@ -22,6 +22,7 @@ ddescribe('second ddescribe', function () { T.postRunCallbacks.push({ label: 'first ddescribe', fn: function () { + console.log('prcc') if (ddescribeCounter1 !== 1) { throw new Error('some assertion failed to exec. ddescribeCounter = ' + ddescribeCounter1) } } }) @@ -29,6 +30,7 @@ T.postRunCallbacks.push({ T.postRunCallbacks.push({ label: 'second ddescribe', fn: function () { + console.log('prcd') if (ddescribeCounter2 !== 1) { throw new Error('some assertion failed to exec. ddescribeCounter = ' + ddescribeCounter2) } } }) diff --git a/specs/sample_spec.js b/specs/sample_spec.js index 304de6d..0e29592 100644 --- a/specs/sample_spec.js +++ b/specs/sample_spec.js @@ -22,7 +22,7 @@ describe('Subject seeding', function () { }) it('should not create new subjects', function () { - Subjects.find().count().should.eq(1) + Subjects.find().count().should.eq(2) }) })