constructor (options) { options = options || {} super(options) this[_nextChildId] = 1 this.pushedEnd = false this.jobs = ownOr(options, 'jobs', 1) this.doingStdinOnly = false this.onTeardown = [] this.subtests = [] this.pool = new Pool() this.queue = ['TAP version 13\n'] // snapshots are keyed off of the main file that loads the // root test object. Typically, this is the TAP object. // To do this, we climb the ladder and only save in the teardown // of that root (parentless) test object. This allows handling // cases where the same test name can be used multiple times // in a single test file, which would otherwise clobber snapshots. this.writeSnapshot = ownOrEnv( options, 'snapshot', 'TAP_SNAPSHOT', true) if (this.parent && this.parent[_snapshot]) this[_snapshot] = this.parent[_snapshot] else this[_snapshot] = new Snapshot(this) if (this.parent && this.parent.cleanSnapshot) this.cleanSnapshot = this.parent.cleanSnapshot this.formatSnapshot = this.parent && this.parent.formatSnapshot this.noparallel = false if (options.cb) this.cb = (...args) => this.hook.runInAsyncScope(options.cb, this, ...args) this.occupied = false this[_currentAssert] = null this[_beforeEnd] = [] this.count = 0 this.n = 0 this.ended = false this.explicitEnded = false this.multiEndThrew = false this.assertAt = null this.assertStack = null this.planEnd = -1 this.onBeforeEach = [] this.onAfterEach = [] this.ranAfterEach = false this[_expectUncaught] = [] // bind all methods to this object, so we can pass t.end as a callback // and do `const test = require('tap').test` like people do. const bound = Object.create(null) bindObj(this, this, bound) bindObj(this, Object.getPrototypeOf(this), bound) bindObj(this, Test.prototype, bound) }
function Base (options) { this.start = 0 this.hrtime = null this.time = null this.readyToProcess = false this.options = options this.parent = ownOr(options, 'parent', null) this.bail = ownOrEnv(options, 'bail', 'TAP_BAIL', true) this.name = ownOr(options, 'name', '') if (!this.name) this.name = '' else this.name = this.name.replace(/[\n\r\s\t]/g, ' ') this.indent = ownOr(options, 'indent', '') this.silent = !!options.silent this.buffered = !!options.buffered || !!options.silent this.finished = false this.strict = ownOrEnv(options, 'strict', 'TAP_STRICT', true) this.omitVersion = !!options.omitVersion this.preserveWhitespace = ownOr(options, 'preserveWhitespace', true) this.jobs = +ownOrEnv(options, 'jobs', 'TAP_JOBS') || 0 this.skip = ownOr(options, 'skip', false) this.todo = ownOr(options, 'todo', false) this.setupParser(options) this.finished = false this.output = '' this.results = null this.bailedOut = false if (this.skip || this.todo) this.main = Base.prototype.main Readable.apply(this, options) domain.create().add(this) this.domain.on('error', this.threw.bind(this)) if (typeof options.debug === 'boolean') this.debug = options.debug ? debug : nodebug }
sub (Class, extra, caller) { if (this.bailedOut) return if (this.doingStdinOnly) throw new Error('cannot run subtests in stdinOnly mode') if (this.results || this.ended) { const er = new Error('cannot create subtest after parent test end') this.threw(er) return Promise.resolve(this) } extra.childId = this[_nextChildId]++ if (!extra.skip && this.grep.length) { const m = this.grep[0].test(extra.name) const match = this.grepInvert ? !m : m if (!match) { const p = 'filter' + (this.grepInvert ? ' out' : '') + ': ' extra.skip = p + this.grep[0] } } if (extra.only && !this.runOnly) this.comment('%j has `only` set but all tests run', extra.name) if (this.runOnly && !extra.only) extra.skip = 'filter: only' if (extra.todo || extra.skip) { this.pass(extra.name, extra) return Promise.resolve(this) } if (!extra.grep) { extra.grep = this.grep.slice(1) extra.grepInvert = this.grepInvert } extra.indent = ' ' if (this.jobs > 1 && process.env.TAP_BUFFER === undefined) extra.buffered = ownOr(extra, 'buffered', true) else extra.buffered = ownOrEnv(extra, 'buffered', 'TAP_BUFFER', true) extra.bail = ownOr(extra, 'bail', this.bail) extra.parent = this extra.stack = stack.captureString(80, caller) extra.context = this.context const t = new Class(extra) this.queue.push(t) this.subtests.push(t) this.emit('subtestAdd', t) const d = new Deferred() t.deferred = d this.process() return d.promise }