aboutsummaryrefslogtreecommitdiff
path: root/node_modules/ava/lib/serialize-error.js
blob: 13146ff42279d5e9c87fb92e13cd190aedde7cd5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
'use strict';
const path = require('path');
const cleanYamlObject = require('clean-yaml-object');
const StackUtils = require('stack-utils');
const assert = require('./assert');
const beautifyStack = require('./beautify-stack');

function isAvaAssertionError(source) {
	return source instanceof assert.AssertionError;
}

function filter(propertyName, isRoot) {
	return !isRoot || (propertyName !== 'message' && propertyName !== 'name' && propertyName !== 'stack');
}

const stackUtils = new StackUtils();
function extractSource(stack) {
	if (!stack) {
		return null;
	}

	const firstStackLine = stack.split('\n')[0];
	return stackUtils.parseLine(firstStackLine);
}
function buildSource(source) {
	if (!source) {
		return null;
	}

	// 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;

	return {
		isDependency,
		isWithinProject,
		file,
		line: source.line
	};
}

module.exports = error => {
	const stack = typeof error.stack === 'string' ?
		beautifyStack(error.stack) :
		null;

	const retval = {
		avaAssertionError: isAvaAssertionError(error),
		source: buildSource(extractSource(stack))
	};
	if (stack) {
		retval.stack = stack;
	}

	if (retval.avaAssertionError) {
		retval.improperUsage = error.improperUsage;
		retval.message = error.message;
		retval.name = error.name;
		retval.statements = error.statements;
		retval.values = error.values;

		if (error.fixedSource) {
			const source = buildSource(error.fixedSource);
			if (source) {
				retval.source = source;
			}
		}

		if (error.assertion) {
			retval.assertion = error.assertion;
		}
		if (error.operator) {
			retval.operator = error.operator;
		}
	} else {
		retval.object = cleanYamlObject(error, filter); // Cleanly copy non-standard properties
		if (typeof error.message === 'string') {
			retval.message = error.message;
		}
		if (typeof error.name === 'string') {
			retval.name = error.name;
		}
	}

	if (typeof error.stack === 'string') {
		retval.summary = error.stack.split('\n')[0];
	} else {
		retval.summary = JSON.stringify(error);
	}

	return retval;
};