diff options
author | Florian Dold <florian.dold@gmail.com> | 2017-05-28 00:38:50 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2017-05-28 00:40:43 +0200 |
commit | 7fff4499fd915bcea3fa93b1aa8b35f4fe7a6027 (patch) | |
tree | 6de9a1aebd150a23b7f8c273ec657a5d0a18fe3e /node_modules/ava/lib/test-collection.js | |
parent | 963b7a41feb29cc4be090a2446bdfe0c1f1bcd81 (diff) |
add linting (and some initial fixes)
Diffstat (limited to 'node_modules/ava/lib/test-collection.js')
-rw-r--r-- | node_modules/ava/lib/test-collection.js | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/node_modules/ava/lib/test-collection.js b/node_modules/ava/lib/test-collection.js new file mode 100644 index 000000000..5404cb119 --- /dev/null +++ b/node_modules/ava/lib/test-collection.js @@ -0,0 +1,206 @@ +'use strict'; +const EventEmitter = require('events'); +const fnName = require('fn-name'); +const Concurrent = require('./concurrent'); +const Sequence = require('./sequence'); +const Test = require('./test'); + +class TestCollection extends EventEmitter { + constructor(options) { + super(); + + this.bail = options.bail; + this.failWithoutAssertions = options.failWithoutAssertions; + this.getSnapshotState = options.getSnapshotState; + this.hasExclusive = false; + this.testCount = 0; + + this.tests = { + concurrent: [], + serial: [] + }; + + this.hooks = { + before: [], + beforeEach: [], + after: [], + afterAlways: [], + afterEach: [], + afterEachAlways: [] + }; + + this.pendingTestInstances = new Set(); + + this._emitTestResult = this._emitTestResult.bind(this); + } + add(test) { + const metadata = test.metadata; + const type = metadata.type; + + if (!type) { + throw new Error('Test type must be specified'); + } + + if (!test.title && test.fn) { + test.title = fnName(test.fn); + } + + // Workaround for Babel giving anonymous functions a name + if (test.title === 'callee$0$0') { + test.title = null; + } + + if (!test.title) { + if (type === 'test') { + test.title = '[anonymous]'; + } else { + test.title = type; + } + } + + if (metadata.always && type !== 'after' && type !== 'afterEach') { + throw new Error('"always" can only be used with after and afterEach hooks'); + } + + // Add a hook + if (type !== 'test') { + if (metadata.exclusive) { + throw new Error(`"only" cannot be used with a ${type} hook`); + } + + this.hooks[type + (metadata.always ? 'Always' : '')].push(test); + return; + } + + this.testCount++; + + // Add `.only()` tests if `.only()` was used previously + if (this.hasExclusive && !metadata.exclusive) { + return; + } + + if (metadata.exclusive && !this.hasExclusive) { + this.tests.concurrent = []; + this.tests.serial = []; + this.hasExclusive = true; + } + + if (metadata.serial) { + this.tests.serial.push(test); + } else { + this.tests.concurrent.push(test); + } + } + _skippedTest(test) { + return { + run: () => { + this._emitTestResult({ + passed: true, + result: test + }); + + return true; + } + }; + } + _emitTestResult(result) { + this.pendingTestInstances.delete(result.result); + this.emit('test', result); + } + _buildHooks(hooks, testTitle, context) { + return hooks.map(hook => { + const test = this._buildHook(hook, testTitle, context); + + if (hook.metadata.skipped || hook.metadata.todo) { + return this._skippedTest(test); + } + + return test; + }); + } + _buildHook(hook, testTitle, contextRef) { + let title = hook.title; + + if (testTitle) { + title += ` for ${testTitle}`; + } + + if (!contextRef) { + contextRef = null; + } + + const test = new Test({ + contextRef, + failWithoutAssertions: false, + fn: hook.fn, + getSnapshotState: this.getSnapshotState, + metadata: hook.metadata, + onResult: this._emitTestResult, + title + }); + this.pendingTestInstances.add(test); + return test; + } + _buildTest(test, contextRef) { + if (!contextRef) { + contextRef = null; + } + + test = new Test({ + contextRef, + failWithoutAssertions: this.failWithoutAssertions, + fn: test.fn, + getSnapshotState: this.getSnapshotState, + metadata: test.metadata, + onResult: this._emitTestResult, + title: test.title + }); + this.pendingTestInstances.add(test); + return test; + } + _buildTestWithHooks(test) { + if (test.metadata.skipped || test.metadata.todo) { + return new Sequence([this._skippedTest(this._buildTest(test))], true); + } + + const context = {context: {}}; + + const beforeHooks = this._buildHooks(this.hooks.beforeEach, test.title, context); + const afterHooks = this._buildHooks(this.hooks.afterEach, test.title, context); + + let sequence = new Sequence([].concat(beforeHooks, this._buildTest(test, context), afterHooks), true); + if (this.hooks.afterEachAlways.length > 0) { + const afterAlwaysHooks = new Sequence(this._buildHooks(this.hooks.afterEachAlways, test.title, context)); + sequence = new Sequence([sequence, afterAlwaysHooks], false); + } + return sequence; + } + _buildTests(tests) { + return tests.map(test => this._buildTestWithHooks(test)); + } + build() { + const beforeHooks = new Sequence(this._buildHooks(this.hooks.before)); + const afterHooks = new Sequence(this._buildHooks(this.hooks.after)); + + const serialTests = new Sequence(this._buildTests(this.tests.serial), this.bail); + const concurrentTests = new Concurrent(this._buildTests(this.tests.concurrent), this.bail); + const allTests = new Sequence([serialTests, concurrentTests]); + + let finalTests = new Sequence([beforeHooks, allTests, afterHooks], true); + if (this.hooks.afterAlways.length > 0) { + const afterAlwaysHooks = new Sequence(this._buildHooks(this.hooks.afterAlways)); + finalTests = new Sequence([finalTests, afterAlwaysHooks], false); + } + return finalTests; + } + attributeLeakedError(err) { + for (const test of this.pendingTestInstances) { + if (test.attributeLeakedError(err)) { + return true; + } + } + return false; + } +} + +module.exports = TestCollection; |