Skip to content
This repository was archived by the owner on Nov 2, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions lib/test.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -63,6 +63,8 @@ const _emits = Symbol('_emits')
const _nextChildId = Symbol('_nextChildId')
const _expectUncaught = Symbol('_expectUncaught')
const _createdFixture = Symbol('_createdFixture')
const _beforeCalled = Symbol('_beforeCalled')
const _printedResult = Symbol('_printedResult')

const hasOwn = (obj, key) =>
Object.prototype.hasOwnProperty.call(obj, key)
Expand DownExpand Up@@ -620,6 +622,8 @@ class Test extends Base {
}

printResult (ok, message, extra, front) {
this[_printedResult] = true

if (this.doingStdinOnly)
throw new Error('cannot print results in stdinOnly mode')
const n = this.count + 1
Expand DownExpand Up@@ -1435,6 +1439,33 @@ class Test extends Base {
}
}

before (fn) {
this.currentAssert = Test.prototype.before
if (this.occupied || this[_printedResult])
throw new Error('t.before() called after starting tests')

if (this[_beforeCalled])
throw new Error('called t.before() more than once')

this[_beforeCalled] = true

// if it throws, we let it kill the test
const ret = fn.call(this)

if (ret && typeof ret.then === 'function')
this.waitOn(ret, w => {
if (w.rejected) {
// sort of a mini bailout, just for this one test
// drop everything from the queue, quit right away
this.queue.length = 0
this.threw(w.value)
this.planEnd = -1
this.count = 1
this.end()
}
})
}

waitOn (promise, cb, expectReject) {
const w = new Waiter(promise, w => {
assert.equal(this.occupied, w)
Expand Down
168 changes: 168 additions & 0 deletions tap-snapshots/test-test.js-TAP.test.cjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -164,6 +164,174 @@ Bail out! whoops

`

exports[`test/test.js TAP assertions and weird stuff before after assertion fails > output 1`] = `
TAP version 13
# Subtest: child
ok 1 - this is going to be trouble
not ok 2 - t.before() called after starting tests
---
stack: |
{STACK}
tapCaught: testFunctionThrow
test: child
...

1..2
# failed 1 of 2 tests
not ok 1 - child # {time}

1..1
# failed 1 test

`

exports[`test/test.js TAP assertions and weird stuff before after async test fails > output 1`] = `
TAP version 13
# Subtest: child
# Subtest: sync child
1..0
ok 1 - sync child # {time}

not ok 2 - t.before() called after starting tests
---
stack: |
{STACK}
tapCaught: testFunctionThrow
test: child
...

1..2
# failed 1 of 2 tests
not ok 1 - child # {time}

1..1
# failed 1 test

`

exports[`test/test.js TAP assertions and weird stuff before after sync test fails > output 1`] = `
TAP version 13
# Subtest: child
# Subtest: sync child
1..0
ok 1 - sync child # {time}

not ok 2 - t.before() called after starting tests
---
stack: |
{STACK}
tapCaught: testFunctionThrow
test: child
...

1..2
# failed 1 of 2 tests
not ok 1 - child # {time}

1..1
# failed 1 test

`

exports[`test/test.js TAP assertions and weird stuff before async > output 1`] = `
TAP version 13
ok 1 - before was called
ok 2 - before not done yet
# Subtest: child
ok 1 - tests wait for t.before to finish
1..1
ok 3 - child # {time}

1..3

`

exports[`test/test.js TAP assertions and weird stuff before called more than once fails > output 1`] = `
TAP version 13
# Subtest: child
not ok 1 - called t.before() more than once
---
stack: |
{STACK}
tapCaught: testFunctionThrow
test: child
...

1..1
# failed 1 test
not ok 1 - child # {time}

1..1
# failed 1 test

`

exports[`test/test.js TAP assertions and weird stuff before reject > output 1`] = `
TAP version 13
# Subtest: child
not ok 1 - poo
---
at:
line: #
column: #
file: test/test.js
source: |2
t.test('child', t => {
t.before(async () => {throw new Error('poo')})
--^
t.test('async child', t => t.end())
t.fail('should not print this')
stack: |
{STACK}
test: child
...

1..1
# failed 1 test
not ok 1 - child # {time}

1..1
# failed 1 test

`

exports[`test/test.js TAP assertions and weird stuff before sync > output 1`] = `
TAP version 13
ok 1 - before was called
1..1

`

exports[`test/test.js TAP assertions and weird stuff before throw > output 1`] = `
TAP version 13
# Subtest: child
not ok 1 - poo
---
at:
line: #
column: #
file: test/test.js
source: |2
t.test('child', t => {
t.before(() => {throw new Error('poo')})
--^
t.test('async child', t => t.end())
t.fail('should not print this')
stack: |
{STACK}
tapCaught: testFunctionThrow
test: child
...

1..1
# failed 1 test
not ok 1 - child # {time}

1..1
# failed 1 test

`

exports[`test/test.js TAP assertions and weird stuff beforeEach afterEach > output 1`] = `
TAP version 13
# Subtest: child
Expand Down
71 changes: 71 additions & 0 deletions test/test.js
Original file line numberDiff line numberDiff line change
Expand Up@@ -991,6 +991,77 @@ t.test('assertions and weird stuff', t => {
ee.emit('pass')
t.end()
},

'before sync': t => {
let x = false
t.before(() => x = true)
t.equal(x, true, 'before was called')
t.end()
},
'before async': t => {
let x = false
let y = false
t.before(async () => {
x = true
await Promise.resolve(true)
y = true
})
t.equal(x, true, 'before was called')
t.equal(y, false, 'before not done yet')
t.test('child', t => {
t.equal(y, true, 'tests wait for t.before to finish')
t.end()
})
t.end()
},
'before after sync test fails': t => {
t.test('child', t => {
t.test('sync child', t => t.end())
t.before(() => {})
t.fail('should not print this')
})
t.end()
},
'before after async test fails': t => {
t.test('child', t => {
t.test('sync child', async t => {})
t.before(() => {})
t.fail('should not print this')
})
t.end()
},
'before after assertion fails': t => {
t.test('child', t => {
t.pass('this is going to be trouble')
t.before(() => {})
t.fail('should not print this')
})
t.end()
},
'before called more than once fails': t => {
t.test('child', t => {
t.before(() => {})
t.before(() => {})
t.fail('should not print this')
})
t.end()
},
'before throw': t => {
t.test('child', t => {
t.before(() => {throw new Error('poo')})
t.test('async child', t => t.end())
t.fail('should not print this')
})
t.end()
},
'before reject': t => {
t.test('child', t => {
t.before(async () => {throw new Error('poo')})
t.test('async child', t => t.end())
t.fail('should not print this')
})
t.end()
},
}

const keys = Object.keys(cases)
Expand Down