diff --git a/lib/cli.js b/lib/cli.js index e95c5c22c..2848a5f9e 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -129,9 +129,9 @@ exports.run = () => { if (cli.flags.tap && !cli.flags.watch) { reporter = new TapReporter(); } else if (cli.flags.verbose || isCi) { - reporter = new VerboseReporter({color: cli.flags.color, basePath: projectDir}); + reporter = new VerboseReporter({color: cli.flags.color}); } else { - reporter = new MiniReporter({color: cli.flags.color, watching: cli.flags.watch, basePath: projectDir}); + reporter = new MiniReporter({color: cli.flags.color, watching: cli.flags.watch}); } reporter.api = api; diff --git a/lib/code-excerpt.js b/lib/code-excerpt.js index 03f2e7d82..aa619a0b2 100644 --- a/lib/code-excerpt.js +++ b/lib/code-excerpt.js @@ -8,12 +8,25 @@ const chalk = require('chalk'); const formatLineNumber = (lineNumber, maxLineNumber) => ' '.repeat(Math.max(0, String(maxLineNumber).length - String(lineNumber).length)) + lineNumber; -module.exports = (file, line, options) => { - options = options || {}; +module.exports = (source, options) => { + if (!source.isWithinProject || source.isDependency) { + return null; + } + const file = source.file; + const line = source.line; + + options = options || {}; const maxWidth = options.maxWidth || 80; - const source = fs.readFileSync(file, 'utf8'); - const excerpt = codeExcerpt(source, line, {around: 1}); + + let contents; + try { + contents = fs.readFileSync(file, 'utf8'); + } catch (err) { + return null; + } + + const excerpt = codeExcerpt(contents, line, {around: 1}); if (!excerpt) { return null; } diff --git a/lib/reporters/mini.js b/lib/reporters/mini.js index 40b9bd328..f5b30ffd6 100644 --- a/lib/reporters/mini.js +++ b/lib/reporters/mini.js @@ -1,6 +1,5 @@ 'use strict'; const StringDecoder = require('string_decoder').StringDecoder; -const path = require('path'); const cliCursor = require('cli-cursor'); const lastLineTracker = require('last-line-stream/tracker'); const plur = require('plur'); @@ -187,8 +186,7 @@ class MiniReporter { if (test.error.source) { status += ' ' + colors.errorSource(test.error.source.file + ':' + test.error.source.line) + '\n'; - const errorPath = path.join(this.options.basePath, test.error.source.file); - const excerpt = codeExcerpt(errorPath, test.error.source.line, {maxWidth: process.stdout.columns}); + const excerpt = codeExcerpt(test.error.source, {maxWidth: process.stdout.columns}); if (excerpt) { status += '\n' + indentString(excerpt, 2) + '\n'; } diff --git a/lib/reporters/verbose.js b/lib/reporters/verbose.js index a76d2c647..4d6e127cb 100644 --- a/lib/reporters/verbose.js +++ b/lib/reporters/verbose.js @@ -1,5 +1,4 @@ 'use strict'; -const path = require('path'); const indentString = require('indent-string'); const prettyMs = require('pretty-ms'); const figures = require('figures'); @@ -106,8 +105,7 @@ class VerboseReporter { if (test.error.source) { output += ' ' + colors.errorSource(test.error.source.file + ':' + test.error.source.line) + '\n'; - const errorPath = path.join(this.options.basePath, test.error.source.file); - const excerpt = codeExcerpt(errorPath, test.error.source.line, {maxWidth: process.stdout.columns}); + const excerpt = codeExcerpt(test.error.source, {maxWidth: process.stdout.columns}); if (excerpt) { output += '\n' + indentString(excerpt, 2) + '\n'; } diff --git a/lib/serialize-error.js b/lib/serialize-error.js index e81e12256..c3b3350a7 100644 --- a/lib/serialize-error.js +++ b/lib/serialize-error.js @@ -1,4 +1,5 @@ 'use strict'; +const path = require('path'); const cleanYamlObject = require('clean-yaml-object'); const StackUtils = require('stack-utils'); const prettyFormat = require('@ava/pretty-format'); @@ -58,8 +59,21 @@ module.exports = error => { const firstStackLine = extractStack(err.stack).split('\n')[0]; const source = stackUtils.parseLine(firstStackLine); if (source) { + // Assume the CWD is the project directory. This holds since this function + // is only called in test workers, which are created with their working + // directory set to the project directory. + const projectDir = process.cwd(); + + const file = path.resolve(projectDir, source.file.trim()); + const rel = path.relative(projectDir, file); + + const isWithinProject = rel.split(path.sep)[0] !== '..'; + const isDependency = isWithinProject && path.dirname(rel).split(path.sep).indexOf('node_modules') > -1; + err.source = { - file: source.file.trim(), + isDependency, + isWithinProject, + file, line: source.line }; } diff --git a/package.json b/package.json index 65847bd1c..f2ed5bcde 100644 --- a/package.json +++ b/package.json @@ -183,7 +183,7 @@ "sinon": "^1.17.2", "source-map-fixtures": "^2.1.0", "tap": "^10.0.0", - "temp-write": "^3.0.0", + "temp-write": "^3.1.0", "touch": "^1.0.0", "xo": "^0.17.0", "zen-observable": "^0.4.0" diff --git a/test/code-excerpt.js b/test/code-excerpt.js index 4608a9a39..534196c01 100644 --- a/test/code-excerpt.js +++ b/test/code-excerpt.js @@ -1,4 +1,5 @@ 'use strict'; +const fs = require('fs'); const tempWrite = require('temp-write'); const chalk = require('chalk'); const test = require('tap').test; @@ -7,13 +8,13 @@ const codeExcerpt = require('../lib/code-excerpt'); chalk.enabled = true; test('read code excerpt', t => { - const path = tempWrite.sync([ + const file = tempWrite.sync([ 'function a() {', '\talert();', '}' ].join('\n')); - const excerpt = codeExcerpt(path, 2); + const excerpt = codeExcerpt({file, line: 2, isWithinProject: true, isDependency: false}); const expected = [ ` ${chalk.grey('1:')} function a() {`, chalk.bgRed(` 2: alert(); `), @@ -25,13 +26,13 @@ test('read code excerpt', t => { }); test('truncate lines', t => { - const path = tempWrite.sync([ + const file = tempWrite.sync([ 'function a() {', '\talert();', '}' ].join('\n')); - const excerpt = codeExcerpt(path, 2, {maxWidth: 14}); + const excerpt = codeExcerpt({file, line: 2, isWithinProject: true, isDependency: false}, {maxWidth: 14}); const expected = [ ` ${chalk.grey('1:')} functio…`, chalk.bgRed(` 2: alert…`), @@ -43,14 +44,14 @@ test('truncate lines', t => { }); test('format line numbers', t => { - const path = tempWrite.sync([ + const file = tempWrite.sync([ '', '', '', '', '', '', '', '', 'function a() {', '\talert();', '}' ].join('\n')); - const excerpt = codeExcerpt(path, 10); + const excerpt = codeExcerpt({file, line: 10, isWithinProject: true, isDependency: false}); const expected = [ ` ${chalk.grey(' 9:')} function a() {`, chalk.bgRed(` 10: alert(); `), @@ -60,3 +61,24 @@ test('format line numbers', t => { t.is(excerpt, expected); t.end(); }); + +test('noop if file cannot be read', t => { + const file = tempWrite.sync(''); + fs.unlinkSync(file); + + const excerpt = codeExcerpt({file, line: 10, isWithinProject: true, isDependency: false}); + t.is(excerpt, null); + t.end(); +}); + +test('noop if file is not within project', t => { + const excerpt = codeExcerpt({isWithinProject: false, file: __filename, line: 1}); + t.is(excerpt, null); + t.end(); +}); + +test('noop if file is a dependency', t => { + const excerpt = codeExcerpt({isWithinProject: true, isDependency: true, file: __filename, line: 1}); + t.is(excerpt, null); + t.end(); +}); diff --git a/test/reporters/mini.js b/test/reporters/mini.js index f53c60ad3..6d74c627f 100644 --- a/test/reporters/mini.js +++ b/test/reporters/mini.js @@ -1,5 +1,4 @@ 'use strict'; -const path = require('path'); const indentString = require('indent-string'); const tempWrite = require('temp-write'); const flatten = require('arr-flatten'); @@ -35,6 +34,15 @@ function miniReporter(options) { return reporter; } +function source(file, line) { + return { + file, + line: line || 1, + isWithinProject: true, + isDependency: false + }; +} + process.stderr.setMaxListeners(50); test('start', t => { @@ -354,7 +362,7 @@ test('results with errors', t => { const err1 = new Error('failure one'); err1.stack = beautifyStack(err1.stack); const err1Path = tempWrite.sync('a();'); - err1.source = {file: path.basename(err1Path), line: 1}; + err1.source = source(err1Path); err1.showOutput = true; err1.actual = JSON.stringify('abc'); err1.actualType = 'string'; @@ -364,14 +372,14 @@ test('results with errors', t => { const err2 = new Error('failure two'); err2.stack = 'error message\nTest.fn (test.js:1:1)\n'; const err2Path = tempWrite.sync('b();'); - err2.source = {file: path.basename(err2Path), line: 1}; + err2.source = source(err2Path); err2.showOutput = true; err2.actual = JSON.stringify([1]); err2.actualType = 'array'; err2.expected = JSON.stringify([2]); err2.expectedType = 'array'; - const reporter = miniReporter({basePath: path.dirname(err1Path)}); + const reporter = miniReporter(); reporter.failCount = 1; const runStatus = { @@ -393,7 +401,7 @@ test('results with errors', t => { ' ' + chalk.bold.white('failed one'), ' ' + chalk.grey(`${err1.source.file}:${err1.source.line}`), '', - indentString(codeExcerpt(err1Path, err1.source.line), 2).split('\n'), + indentString(codeExcerpt(err1.source), 2).split('\n'), '', indentString(formatAssertError(err1), 2).split('\n'), /failure one/, @@ -406,7 +414,7 @@ test('results with errors', t => { ' ' + chalk.bold.white('failed two'), ' ' + chalk.grey(`${err2.source.file}:${err2.source.line}`), '', - indentString(codeExcerpt(err2Path, err2.source.line), 2).split('\n'), + indentString(codeExcerpt(err2.source), 2).split('\n'), '', indentString(formatAssertError(err2), 2).split('\n'), /failure two/ @@ -426,14 +434,14 @@ test('results with errors and disabled code excerpts', t => { const err2 = new Error('failure two'); err2.stack = 'error message\nTest.fn (test.js:1:1)\n'; const err2Path = tempWrite.sync('b();'); - err2.source = {file: path.basename(err2Path), line: 1}; + err2.source = source(err2Path); err2.showOutput = true; err2.actual = JSON.stringify([1]); err2.actualType = 'array'; err2.expected = JSON.stringify([2]); err2.expectedType = 'array'; - const reporter = miniReporter({color: true, basePath: path.dirname(err2Path)}); + const reporter = miniReporter({color: true}); reporter.failCount = 1; const runStatus = { @@ -465,7 +473,7 @@ test('results with errors and disabled code excerpts', t => { ' ' + chalk.bold.white('failed two'), ' ' + chalk.grey(`${err2.source.file}:${err2.source.line}`), '', - indentString(codeExcerpt(err2Path, err2.source.line), 2).split('\n'), + indentString(codeExcerpt(err2.source), 2).split('\n'), '', indentString(formatAssertError(err2), 2).split('\n'), /failure two/ @@ -477,7 +485,7 @@ test('results with errors and broken code excerpts', t => { const err1 = new Error('failure one'); err1.stack = beautifyStack(err1.stack); const err1Path = tempWrite.sync('a();'); - err1.source = {file: path.basename(err1Path), line: 10}; + err1.source = source(err1Path, 10); err1.showOutput = true; err1.actual = JSON.stringify('abc'); err1.actualType = 'string'; @@ -487,14 +495,14 @@ test('results with errors and broken code excerpts', t => { const err2 = new Error('failure two'); err2.stack = 'error message\nTest.fn (test.js:1:1)\n'; const err2Path = tempWrite.sync('b();'); - err2.source = {file: path.basename(err2Path), line: 1}; + err2.source = source(err2Path); err2.showOutput = true; err2.actual = JSON.stringify([1]); err2.actualType = 'array'; err2.expected = JSON.stringify([2]); err2.expectedType = 'array'; - const reporter = miniReporter({color: true, basePath: path.dirname(err2Path)}); + const reporter = miniReporter({color: true}); reporter.failCount = 1; const runStatus = { @@ -527,7 +535,7 @@ test('results with errors and broken code excerpts', t => { ' ' + chalk.bold.white('failed two'), ' ' + chalk.grey(`${err2.source.file}:${err2.source.line}`), '', - indentString(codeExcerpt(err2Path, err2.source.line), 2).split('\n'), + indentString(codeExcerpt(err2.source), 2).split('\n'), '', indentString(formatAssertError(err2), 2).split('\n'), /failure two/ @@ -539,7 +547,7 @@ test('results with errors and disabled assert output', t => { const err1 = new Error('failure one'); err1.stack = beautifyStack(err1.stack); const err1Path = tempWrite.sync('a();'); - err1.source = {file: path.basename(err1Path), line: 1}; + err1.source = source(err1Path); err1.showOutput = false; err1.actual = JSON.stringify('abc'); err1.actualType = 'string'; @@ -549,14 +557,14 @@ test('results with errors and disabled assert output', t => { const err2 = new Error('failure two'); err2.stack = 'error message\nTest.fn (test.js:1:1)\n'; const err2Path = tempWrite.sync('b();'); - err2.source = {file: path.basename(err2Path), line: 1}; + err2.source = source(err2Path); err2.showOutput = true; err2.actual = JSON.stringify([1]); err2.actualType = 'array'; err2.expected = JSON.stringify([2]); err2.expectedType = 'array'; - const reporter = miniReporter({color: true, basePath: path.dirname(err1Path)}); + const reporter = miniReporter({color: true}); reporter.failCount = 1; const runStatus = { @@ -578,7 +586,7 @@ test('results with errors and disabled assert output', t => { ' ' + chalk.bold.white('failed one'), ' ' + chalk.grey(`${err1.source.file}:${err1.source.line}`), '', - indentString(codeExcerpt(err1Path, err1.source.line), 2).split('\n'), + indentString(codeExcerpt(err1.source), 2).split('\n'), '', /failure one/, '', @@ -590,7 +598,7 @@ test('results with errors and disabled assert output', t => { ' ' + chalk.bold.white('failed two'), ' ' + chalk.grey(`${err2.source.file}:${err2.source.line}`), '', - indentString(codeExcerpt(err2Path, err2.source.line), 2).split('\n'), + indentString(codeExcerpt(err2.source), 2).split('\n'), '', indentString(formatAssertError(err2), 2).split('\n'), /failure two/ diff --git a/test/reporters/verbose.js b/test/reporters/verbose.js index 2e00ee42a..67b978ebf 100644 --- a/test/reporters/verbose.js +++ b/test/reporters/verbose.js @@ -1,5 +1,4 @@ 'use strict'; -const path = require('path'); const indentString = require('indent-string'); const flatten = require('arr-flatten'); const tempWrite = require('temp-write'); @@ -45,6 +44,15 @@ function barFunc() { throw new Error(); } +function source(file, line) { + return { + file, + line: line || 1, + isWithinProject: true, + isDependency: false + }; +} + test('beautify stack - removes uninteresting lines', t => { try { fooFunc(); @@ -364,7 +372,7 @@ test('results with errors', t => { const error1 = new Error('error one message'); error1.stack = beautifyStack(error1.stack); const err1Path = tempWrite.sync('a()'); - error1.source = {file: path.basename(err1Path), line: 1}; + error1.source = source(err1Path); error1.showOutput = true; error1.actual = JSON.stringify('abc'); error1.actualType = 'string'; @@ -374,14 +382,14 @@ test('results with errors', t => { const error2 = new Error('error two message'); error2.stack = 'error message\nTest.fn (test.js:1:1)\n'; const err2Path = tempWrite.sync('b()'); - error2.source = {file: path.basename(err2Path), line: 1}; + error2.source = source(err2Path); error2.showOutput = true; error2.actual = JSON.stringify([1]); error2.actualType = 'array'; error2.expected = JSON.stringify([2]); error2.expectedType = 'array'; - const reporter = createReporter({color: true, basePath: path.dirname(err1Path)}); + const reporter = createReporter({color: true}); const runStatus = createRunStatus(); runStatus.failCount = 1; runStatus.tests = [{ @@ -400,7 +408,7 @@ test('results with errors', t => { ' ' + chalk.bold.white('fail one'), ' ' + chalk.grey(`${error1.source.file}:${error1.source.line}`), '', - indentString(codeExcerpt(err1Path, error1.source.line), 2).split('\n'), + indentString(codeExcerpt(error1.source), 2).split('\n'), '', indentString(formatAssertError(error1), 2).split('\n'), /error one message/, @@ -413,7 +421,7 @@ test('results with errors', t => { ' ' + chalk.bold.white('fail two'), ' ' + chalk.grey(`${error2.source.file}:${error2.source.line}`), '', - indentString(codeExcerpt(err2Path, error2.source.line), 2).split('\n'), + indentString(codeExcerpt(error2.source), 2).split('\n'), '', indentString(formatAssertError(error2), 2).split('\n'), /error two message/ @@ -433,14 +441,14 @@ test('results with errors and disabled code excerpts', t => { const error2 = new Error('error two message'); error2.stack = 'error message\nTest.fn (test.js:1:1)\n'; const err2Path = tempWrite.sync('b()'); - error2.source = {file: path.basename(err2Path), line: 1}; + error2.source = source(err2Path); error2.showOutput = true; error2.actual = JSON.stringify([1]); error2.actualType = 'array'; error2.expected = JSON.stringify([2]); error2.expectedType = 'array'; - const reporter = createReporter({color: true, basePath: path.dirname(err2Path)}); + const reporter = createReporter({color: true}); const runStatus = createRunStatus(); runStatus.failCount = 1; runStatus.tests = [{ @@ -469,7 +477,7 @@ test('results with errors and disabled code excerpts', t => { ' ' + chalk.bold.white('fail two'), ' ' + chalk.grey(`${error2.source.file}:${error2.source.line}`), '', - indentString(codeExcerpt(err2Path, error2.source.line), 2).split('\n'), + indentString(codeExcerpt(error2.source), 2).split('\n'), '', indentString(formatAssertError(error2), 2).split('\n'), /error two message/ @@ -481,7 +489,7 @@ test('results with errors and disabled code excerpts', t => { const error1 = new Error('error one message'); error1.stack = beautifyStack(error1.stack); const err1Path = tempWrite.sync('a();'); - error1.source = {file: path.basename(err1Path), line: 10}; + error1.source = source(err1Path, 10); error1.showOutput = true; error1.actual = JSON.stringify('abc'); error1.actualType = 'string'; @@ -491,14 +499,14 @@ test('results with errors and disabled code excerpts', t => { const error2 = new Error('error two message'); error2.stack = 'error message\nTest.fn (test.js:1:1)\n'; const err2Path = tempWrite.sync('b()'); - error2.source = {file: path.basename(err2Path), line: 1}; + error2.source = source(err2Path); error2.showOutput = true; error2.actual = JSON.stringify([1]); error2.actualType = 'array'; error2.expected = JSON.stringify([2]); error2.expectedType = 'array'; - const reporter = createReporter({color: true, basePath: path.dirname(err2Path)}); + const reporter = createReporter({color: true}); const runStatus = createRunStatus(); runStatus.failCount = 1; runStatus.tests = [{ @@ -528,7 +536,7 @@ test('results with errors and disabled code excerpts', t => { ' ' + chalk.bold.white('fail two'), ' ' + chalk.grey(`${error2.source.file}:${error2.source.line}`), '', - indentString(codeExcerpt(err2Path, error2.source.line), 2).split('\n'), + indentString(codeExcerpt(error2.source), 2).split('\n'), '', indentString(formatAssertError(error2), 2).split('\n'), /error two message/ @@ -540,7 +548,7 @@ test('results with errors and disabled assert output', t => { const error1 = new Error('error one message'); error1.stack = beautifyStack(error1.stack); const err1Path = tempWrite.sync('a();'); - error1.source = {file: path.basename(err1Path), line: 1}; + error1.source = source(err1Path); error1.showOutput = false; error1.actual = JSON.stringify('abc'); error1.actualType = 'string'; @@ -550,14 +558,14 @@ test('results with errors and disabled assert output', t => { const error2 = new Error('error two message'); error2.stack = 'error message\nTest.fn (test.js:1:1)\n'; const err2Path = tempWrite.sync('b();'); - error2.source = {file: path.basename(err2Path), line: 1}; + error2.source = source(err2Path); error2.showOutput = true; error2.actual = JSON.stringify([1]); error2.actualType = 'array'; error2.expected = JSON.stringify([2]); error2.expectedType = 'array'; - const reporter = createReporter({color: true, basePath: path.dirname(err1Path)}); + const reporter = createReporter({color: true}); const runStatus = createRunStatus(); runStatus.failCount = 1; runStatus.tests = [{ @@ -576,7 +584,7 @@ test('results with errors and disabled assert output', t => { ' ' + chalk.bold.white('fail one'), ' ' + chalk.grey(`${error1.source.file}:${error1.source.line}`), '', - indentString(codeExcerpt(err1Path, error1.source.line), 2).split('\n'), + indentString(codeExcerpt(error1.source), 2).split('\n'), '', /error one message/, '', @@ -588,7 +596,7 @@ test('results with errors and disabled assert output', t => { ' ' + chalk.bold.white('fail two'), ' ' + chalk.grey(`${error2.source.file}:${error2.source.line}`), '', - indentString(codeExcerpt(err2Path, error2.source.line), 2).split('\n'), + indentString(codeExcerpt(error2.source), 2).split('\n'), '', indentString(formatAssertError(error2), 2).split('\n'), /error two message/ diff --git a/test/serialize-error.js b/test/serialize-error.js index b44b059e1..bab0cba22 100644 --- a/test/serialize-error.js +++ b/test/serialize-error.js @@ -1,11 +1,20 @@ 'use strict'; +const fs = require('fs'); +const path = require('path'); const prettyFormat = require('@ava/pretty-format'); const reactTestPlugin = require('@ava/pretty-format/plugins/ReactTestComponent'); +const sourceMapFixtures = require('source-map-fixtures'); +const sourceMapSupport = require('source-map-support'); +const tempWrite = require('temp-write'); +const uniqueTempDir = require('unique-temp-dir'); const test = require('tap').test; const beautifyStack = require('../lib/beautify-stack'); const serialize = require('../lib/serialize-error'); +// Needed to test stack traces from source map fixtures. +sourceMapSupport.install({environment: 'node'}); + function serializeValue(value) { return prettyFormat(value, { plugins: [reactTestPlugin], @@ -21,11 +30,92 @@ test('serialize standard props', t => { t.is(serializedErr.name, 'Error'); t.is(serializedErr.stack, beautifyStack(err.stack)); t.is(serializedErr.message, 'Hello'); + t.is(typeof serializedErr.source.isDependency, 'boolean'); + t.is(typeof serializedErr.source.isWithinProject, 'boolean'); t.is(typeof serializedErr.source.file, 'string'); t.is(typeof serializedErr.source.line, 'number'); t.end(); }); +test('source file is an absolute path', t => { + const err = new Error('Hello'); + const serializedErr = serialize(err); + + t.is(serializedErr.source.file, __filename); + t.end(); +}); + +test('source file is an absolute path, after source map correction', t => { + const fixture = sourceMapFixtures.mapFile('throws'); + try { + fixture.require().run(); + t.fail('Fixture should have thrown'); + } catch (err) { + const serializedErr = serialize(err); + t.is(serializedErr.source.file, fixture.sourceFile); + t.end(); + } +}); + +test('source file is an absolute path, after source map correction, even if already absolute', t => { + const fixture = sourceMapFixtures.mapFile('throws'); + const map = JSON.parse(fs.readFileSync(fixture.file + '.map')); + + const tmp = uniqueTempDir({create: true}); + const sourceRoot = path.join(tmp, 'src'); + const expectedSourceFile = path.join(sourceRoot, map.file); + + const tmpFile = path.join(tmp, path.basename(fixture.file)); + fs.writeFileSync(tmpFile, fs.readFileSync(fixture.file)); + fs.writeFileSync(tmpFile + '.map', JSON.stringify(Object.assign(map, {sourceRoot}), null, 2)); + + try { + require(tmpFile).run(); // eslint-disable-line import/no-dynamic-require + t.fail('Fixture should have thrown'); + } catch (err) { + const serializedErr = serialize(err); + t.is(serializedErr.source.file, expectedSourceFile); + t.end(); + } +}); + +test('determines whether source file is within the project', t => { + const file = tempWrite.sync('module.exports = () => { throw new Error("hello") }'); + try { + require(file)(); // eslint-disable-line import/no-dynamic-require + t.fail('Should have thrown'); + } catch (err) { + const serializedErr = serialize(err); + t.is(serializedErr.source.file, file); + t.is(serializedErr.source.isWithinProject, false); + } + + const err = new Error('Hello'); + const serializedErr = serialize(err); + t.is(serializedErr.source.file, __filename); + t.is(serializedErr.source.isWithinProject, true); + t.end(); +}); + +test('determines whether source file, if within the project, is a dependency', t => { + const fixture = sourceMapFixtures.mapFile('throws'); + try { + fixture.require().run(); + t.fail('Fixture should have thrown'); + } catch (err) { + const serializedErr = serialize(err); + t.is(serializedErr.source.file, fixture.sourceFile); + t.is(serializedErr.source.isWithinProject, true); + t.is(serializedErr.source.isDependency, true); + } + + const err = new Error('Hello'); + const serializedErr = serialize(err); + t.is(serializedErr.source.file, __filename); + t.is(serializedErr.source.isDependency, false); + t.end(); +}); + test('serialize statements', t => { const err = new Error(); err.showOutput = true;