Skip to content

Commit 3ea7921

Browse files
committed
[Fix] t.teardown(): ensure callback is only called once
Fixes #551
1 parent 50751db commit 3ea7921

2 files changed

Lines changed: 59 additions & 16 deletions

File tree

lib/test.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -212,34 +212,28 @@ Test.prototype._end = function (err) {
212212
}
213213

214214

215-
function next(i) {
216-
if (i === self._teardown.length) {
215+
function next() {
216+
if (self._teardown.length === 0) {
217217
completeEnd();
218218
return;
219219
}
220-
var fn = self._teardown[i];
220+
var fn = self._teardown.shift();
221221
var res;
222222
try {
223223
res = fn();
224224
} catch (e) {
225225
self.fail(e);
226226
}
227227
if (res && typeof res.then === 'function') {
228-
res.then(function () {
229-
next(++i);
230-
}, function (_err) {
228+
res.then(next, function (_err) {
231229
err = err || _err;
232230
});
233231
} else {
234-
next(++i);
232+
next();
235233
}
236234
}
237235

238-
if (this._teardown.length > 0) {
239-
next(0);
240-
} else {
241-
completeEnd();
242-
}
236+
next();
243237

244238
function completeEnd() {
245239
if (!self.ended) self.emit('end');

test/teardown.js

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,22 @@ tap.test('teardowns', function (tt) {
113113
);
114114
}),
115115
typeof Promise === 'function' ? [
116+
'# teardown is only ever called once, even when async',
117+
'ok ' + (11 + v.nonFunctions.length) + ' passes',
118+
'# teardown: once?',
116119
'# success (promise)',
117-
'ok ' + (11 + v.nonFunctions.length) + ' should be truthy',
120+
'ok ' + (12 + v.nonFunctions.length) + ' should be truthy',
118121
'# success (promise) teardown: 1',
119122
'# success (promise) teardown: 2',
120123
'# success (promise) teardown: 3'
121124
] : [
125+
'# SKIP teardown is only ever called once, even when async',
122126
'# SKIP success (promise)'
123127
], [
124128
'',
125-
'1..' + ((typeof Promise === 'function' ? 1 : 0) + 10 + v.nonFunctions.length),
126-
'# tests ' + ((typeof Promise === 'function' ? 1 : 0) + 10 + v.nonFunctions.length),
127-
'# pass ' + ((typeof Promise === 'function' ? 1 : 0) + 5),
129+
'1..' + ((typeof Promise === 'function' ? 2 : 0) + 10 + v.nonFunctions.length),
130+
'# tests ' + ((typeof Promise === 'function' ? 2 : 0) + 10 + v.nonFunctions.length),
131+
'# pass ' + ((typeof Promise === 'function' ? 2 : 0) + 5),
128132
'# fail ' + (5 + v.nonFunctions.length),
129133
''
130134
]));
@@ -226,6 +230,18 @@ tap.test('teardowns', function (tt) {
226230
});
227231
});
228232

233+
test('teardown is only ever called once, even when async', { skip: typeof Promise !== 'function' }, function (t) {
234+
t.plan(1);
235+
236+
t.teardown(function () {
237+
t.comment('teardown: once?');
238+
});
239+
240+
t.pass('passes');
241+
242+
return Promise.resolve();
243+
});
244+
229245
test('success (promise)', { skip: typeof Promise !== 'function' }, function (t) {
230246
t.plan(1);
231247

@@ -265,3 +281,36 @@ tap.test('teardown with promise', { skip: typeof Promise !== 'function', timeout
265281
t.end();
266282
});
267283
});
284+
285+
tap.test('teardown only runs once', { skip: typeof Promise !== 'function', timeout: 1e3 }, function (tt) {
286+
tt.plan(1);
287+
288+
var test = tape.createHarness();
289+
test.createStream().pipe(concat(function (body) {
290+
tt.same(stripFullStack(body.toString('utf8')), [].concat(
291+
'TAP version 13',
292+
'# teardown is only called once, even with a plan',
293+
'ok 1 passes',
294+
'# Tearing down!',
295+
'',
296+
'1..1',
297+
'# tests 1',
298+
'# pass 1',
299+
'',
300+
'# ok',
301+
''
302+
));
303+
}));
304+
305+
test('teardown is only called once, even with a plan', function (t) {
306+
t.plan(1);
307+
308+
t.teardown(function () {
309+
t.comment('Tearing down!');
310+
});
311+
312+
t.pass('passes');
313+
314+
return Promise.resolve();
315+
});
316+
});

0 commit comments

Comments
 (0)