var tape = require('../'); var tap = require('tap'); var concat = require('concat-stream'); var tapParser = require('tap-parser'); var yaml = require('js-yaml'); tap.test('preserves stack trace with newlines', function (tt) { tt.plan(3); var test = tape.createHarness(); var stream = test.createStream(); var parser = stream.pipe(tapParser()); var stackTrace = 'foo\n bar'; parser.once('assert', function (data) { delete data.diag.at; tt.deepEqual(data, { ok: false, id: 1, name: "Error: Preserve stack", diag: { stack: stackTrace, operator: 'error', expected: 'undefined', actual: '[Error: Preserve stack]' } }); }); stream.pipe(concat(function (body) { var body = body.toString('utf8'); body = stripAt(body); tt.equal( body, 'TAP version 13\n' + '# multiline stack trace\n' + 'not ok 1 Error: Preserve stack\n' + ' ---\n' + ' operator: error\n' + ' expected: |-\n' + ' undefined\n' + ' actual: |-\n' + ' [Error: Preserve stack]\n' + ' stack: |-\n' + ' foo\n' + ' bar\n' + ' ...\n' + '\n' + '1..1\n' + '# tests 1\n' + '# pass 0\n' + '# fail 1\n' ); tt.deepEqual(getDiag(body), { stack: stackTrace, operator: 'error', expected: 'undefined', actual: '[Error: Preserve stack]' }); })); test('multiline stack trace', function (t) { t.plan(1); var err = new Error('Preserve stack'); err.stack = stackTrace; t.error(err); }); }); tap.test('parses function name from original stack', function (tt) { tt.plan(1); var test = tape.createHarness(); test.createStream(); test._results._watch = function (t) { t.on('result', function (res) { tt.equal('Test.testFunctionNameParsing', res.functionName); }); }; test('t.equal stack trace', function testFunctionNameParsing(t) { t.equal(true, false, 'true should be false'); t.end(); }); }); tap.test('parses function name from original stack for anonymous function', function (tt) { tt.plan(1); var test = tape.createHarness(); test.createStream(); test._results._watch = function (t) { t.on('result', function (res) { tt.equal('Test.', res.functionName); }); }; test('t.equal stack trace', function (t) { t.equal(true, false, 'true should be false'); t.end(); }); }); tap.test('preserves stack trace for failed assertions', function (tt) { tt.plan(6); var test = tape.createHarness(); var stream = test.createStream(); var parser = stream.pipe(tapParser()); var stack = ''; parser.once('assert', function (data) { tt.equal(typeof data.diag.at, 'string'); tt.equal(typeof data.diag.stack, 'string'); at = data.diag.at || ''; stack = data.diag.stack || ''; tt.ok(/^Error: true should be false(\n at .+)+/.exec(stack), 'stack should be a stack'); tt.deepEqual(data, { ok: false, id: 1, name: "true should be false", diag: { at: at, stack: stack, operator: 'equal', expected: false, actual: true } }); }); stream.pipe(concat(function (body) { var body = body.toString('utf8'); body = stripAt(body); tt.equal( body, 'TAP version 13\n' + '# t.equal stack trace\n' + 'not ok 1 true should be false\n' + ' ---\n' + ' operator: equal\n' + ' expected: false\n' + ' actual: true\n' + ' stack: |-\n' + ' ' + stack.replace(/\n/g, '\n ') + '\n' + ' ...\n' + '\n' + '1..1\n' + '# tests 1\n' + '# pass 0\n' + '# fail 1\n' ); tt.deepEqual(getDiag(body), { stack: stack, operator: 'equal', expected: false, actual: true }); })); test('t.equal stack trace', function (t) { t.plan(1); t.equal(true, false, 'true should be false'); }); }); tap.test('preserves stack trace for failed assertions where actual===falsy', function (tt) { tt.plan(6); var test = tape.createHarness(); var stream = test.createStream(); var parser = stream.pipe(tapParser()); var stack = ''; parser.once('assert', function (data) { tt.equal(typeof data.diag.at, 'string'); tt.equal(typeof data.diag.stack, 'string'); at = data.diag.at || ''; stack = data.diag.stack || ''; tt.ok(/^Error: false should be true(\n at .+)+/.exec(stack), 'stack should be a stack'); tt.deepEqual(data, { ok: false, id: 1, name: "false should be true", diag: { at: at, stack: stack, operator: 'equal', expected: true, actual: false } }); }); stream.pipe(concat(function (body) { var body = body.toString('utf8'); body = stripAt(body); tt.equal( body, 'TAP version 13\n' + '# t.equal stack trace\n' + 'not ok 1 false should be true\n' + ' ---\n' + ' operator: equal\n' + ' expected: true\n' + ' actual: false\n' + ' stack: |-\n' + ' ' + stack.replace(/\n/g, '\n ') + '\n' + ' ...\n' + '\n' + '1..1\n' + '# tests 1\n' + '# pass 0\n' + '# fail 1\n' ); tt.deepEqual(getDiag(body), { stack: stack, operator: 'equal', expected: true, actual: false }); })); test('t.equal stack trace', function (t) { t.plan(1); t.equal(false, true, 'false should be true'); }); }); function getDiag(body) { var yamlStart = body.indexOf(' ---'); var yamlEnd = body.indexOf(' ...\n'); var diag = body.slice(yamlStart, yamlEnd).split('\n').map(function (line) { return line.slice(2); }).join('\n'); // Get rid of 'at' variable (which has a line number / path of its own that's // difficult to check). var withStack = yaml.safeLoad(diag); delete withStack.at; return withStack; } function stripAt(body) { return body.replace(/^\s*at:\s+Test.*$\n/m, ''); }