-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Magic assert #1154
Merged
Merged
Magic assert #1154
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
e60f1cd
magic assert
e9bcbbd
fix stack paths with beginning spaces
27f40e5
rename t.jsxNotEqual to t.notJsxEqual
6d89985
make snapshots compatible with magic assert output
29f3865
fix t.snapshot stackStartFunction
b4e9254
fix stack parsing when serializing error
a9c1d9e
add minor comments
406daef
fix stackStartFunction for t.notJsxEqual
2187982
remove auto-generated diff from t.snapshot error message
1a6e33e
add extractStack() to correctly extract actual stack from err.stack
7b2dd8b
display error message
fecc9de
fix full-width line test in verbose reporter
0214d66
make error stack grey in verbose reporter
018802e
unify output
dbdf8b5
remove moot test
7804a8d
check if snapshot exists before trying to parse it
13279e9
update jsx support
8b7b3d2
show error stack if present
26d5db2
add "threw non-error" note to uncaught errors
7062599
remove empty space if error message is empty
ddeaf8c
fix path parsing for code excerpts
6320ddc
dont check for explicit stack path in serialize-error tests
1b8fcfe
cleanup
4379e3a
change splice to slice
7a53696
remove notes
e06d8f3
remove t.jsxEqual
96caf61
fix power-assert patterns
be3c42d
use babel-preset-transform-test-files fork
9a27d34
handle jsx differently in t.snapshot
2fa8da9
explain jest-snapshot double json encoding
9e9642f
adjust code excerpt line trimming
2508272
remove react element rendering
efe21ac
use babel-preset-transform-test-files@2
62a25a7
use @ava/pretty-format
286d620
cleanup
cf6ee8e
remove previous pretty-format
b139bc6
change custom jsx key in snapshots
9ea5af4
disable assertion output for t.throws
443888f
skip code excerpt when its broken
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
'use strict'; | ||
const fs = require('fs'); | ||
const equalLength = require('equal-length'); | ||
const codeExcerpt = require('code-excerpt'); | ||
const truncate = require('cli-truncate'); | ||
const chalk = require('chalk'); | ||
|
||
const formatLineNumber = (lineNumber, maxLineNumber) => { | ||
return ' '.repeat(String(maxLineNumber).length - String(lineNumber).length) + lineNumber; | ||
}; | ||
|
||
module.exports = (file, line, options) => { | ||
options = options || {}; | ||
|
||
const maxWidth = options.maxWidth || 80; | ||
const source = fs.readFileSync(file, 'utf8'); | ||
const excerpt = codeExcerpt(source, line, {around: 1}); | ||
if (!excerpt) { | ||
return null; | ||
} | ||
|
||
const lines = excerpt.map(item => ({ | ||
line: item.line, | ||
value: truncate(item.value, maxWidth - String(line).length - 5) | ||
})); | ||
|
||
const joinedLines = lines.map(line => line.value).join('\n'); | ||
const extendedLines = equalLength(joinedLines).split('\n'); | ||
|
||
return lines | ||
.map((item, index) => ({ | ||
line: item.line, | ||
value: extendedLines[index] | ||
})) | ||
.map(item => { | ||
const isErrorSource = item.line === line; | ||
|
||
const lineNumber = formatLineNumber(item.line, line) + ':'; | ||
const coloredLineNumber = isErrorSource ? lineNumber : chalk.grey(lineNumber); | ||
const result = ` ${coloredLineNumber} ${item.value}`; | ||
|
||
return isErrorSource ? chalk.bgRed(result) : result; | ||
}) | ||
.join('\n'); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,79 @@ | ||
'use strict'; | ||
|
||
module.exports = enhanceAssert; | ||
module.exports.formatter = formatter; | ||
const dotProp = require('dot-prop'); | ||
|
||
// When adding patterns, don't forget to add to | ||
// https://github.com/avajs/babel-preset-transform-test-files/blob/master/espower-patterns.json | ||
// Then release a new version of that preset and bump the SemVer range here. | ||
module.exports.PATTERNS = [ | ||
const PATTERNS = [ | ||
't.truthy(value, [message])', | ||
't.falsy(value, [message])', | ||
't.true(value, [message])', | ||
't.false(value, [message])', | ||
't.is(value, expected, [message])', | ||
't.not(value, expected, [message])', | ||
't.deepEqual(value, expected, [message])', | ||
't.notDeepEqual(value, expected, [message])', | ||
't.regex(contents, regex, [message])', | ||
't.notRegex(contents, regex, [message])' | ||
]; | ||
|
||
module.exports.NON_ENHANCED_PATTERNS = [ | ||
const NON_ENHANCED_PATTERNS = [ | ||
't.pass([message])', | ||
't.fail([message])', | ||
't.throws(fn, [message])', | ||
't.notThrows(fn, [message])', | ||
't.ifError(error, [message])', | ||
't.snapshot(contents, [message])' | ||
't.snapshot(contents, [message])', | ||
't.is(value, expected, [message])', | ||
't.not(value, expected, [message])', | ||
't.deepEqual(value, expected, [message])', | ||
't.notDeepEqual(value, expected, [message])' | ||
]; | ||
|
||
function enhanceAssert(opts) { | ||
const enhanceAssert = opts => { | ||
const empower = require('empower-core'); | ||
|
||
const enhanced = empower( | ||
opts.assert, | ||
{ | ||
destructive: false, | ||
onError: opts.onError, | ||
onSuccess: opts.onSuccess, | ||
patterns: module.exports.PATTERNS, | ||
wrapOnlyPatterns: module.exports.NON_ENHANCED_PATTERNS, | ||
bindReceiver: false | ||
} | ||
); | ||
const enhanced = empower(opts.assert, { | ||
destructive: false, | ||
onError: opts.onError, | ||
onSuccess: opts.onSuccess, | ||
patterns: PATTERNS, | ||
wrapOnlyPatterns: NON_ENHANCED_PATTERNS, | ||
bindReceiver: false | ||
}); | ||
|
||
return enhanced; | ||
} | ||
}; | ||
|
||
function formatter() { | ||
const createFormatter = require('power-assert-context-formatter'); | ||
const SuccinctRenderer = require('power-assert-renderer-succinct'); | ||
const AssertionRenderer = require('power-assert-renderer-assertion'); | ||
const isRangeMatch = (a, b) => { | ||
return (a[0] === b[0] && a[1] === b[1]) || | ||
(a[0] > b[0] && a[0] < b[1]) || | ||
(a[1] > b[0] && a[1] < b[1]); | ||
}; | ||
|
||
return createFormatter({ | ||
renderers: [ | ||
{ | ||
ctor: AssertionRenderer | ||
}, | ||
{ | ||
ctor: SuccinctRenderer, | ||
options: { | ||
maxDepth: 3 | ||
} | ||
} | ||
] | ||
}); | ||
} | ||
const computeStatement = (tokens, range) => { | ||
return tokens | ||
.filter(token => isRangeMatch(token.range, range)) | ||
.map(token => token.value === undefined ? token.type.label : token.value) | ||
.join(''); | ||
}; | ||
|
||
const getNode = (ast, path) => dotProp.get(ast, path.replace(/\//g, '.')); | ||
|
||
const formatter = () => { | ||
return context => { | ||
const ast = JSON.parse(context.source.ast); | ||
const tokens = JSON.parse(context.source.tokens); | ||
const args = context.args[0].events; | ||
|
||
return args | ||
.map(arg => { | ||
const range = getNode(ast, arg.espath).range; | ||
|
||
return [computeStatement(tokens, range), arg.value]; | ||
}) | ||
.reverse(); | ||
}; | ||
}; | ||
|
||
module.exports = enhanceAssert; | ||
module.exports.PATTERNS = PATTERNS; | ||
module.exports.NON_ENHANCED_PATTERNS = NON_ENHANCED_PATTERNS; | ||
module.exports.formatter = formatter; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
'use strict'; | ||
const stackLineRegex = /^.+ \(.+:[0-9]+:[0-9]+\)$/; | ||
|
||
module.exports = stack => { | ||
return stack | ||
.split('\n') | ||
.filter(line => stackLineRegex.test(line)) | ||
.map(line => line.trim()) | ||
.join('\n'); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
'use strict'; | ||
const indentString = require('indent-string'); | ||
const chalk = require('chalk'); | ||
const diff = require('diff'); | ||
|
||
const cleanUp = line => { | ||
if (line[0] === '+') { | ||
return `${chalk.green('+')} ${line.slice(1)}`; | ||
} | ||
|
||
if (line[0] === '-') { | ||
return `${chalk.red('-')} ${line.slice(1)}`; | ||
} | ||
|
||
if (line.match(/@@/)) { | ||
return null; | ||
} | ||
|
||
if (line.match(/\\ No newline/)) { | ||
return null; | ||
} | ||
|
||
return ` ${line}`; | ||
}; | ||
|
||
module.exports = err => { | ||
if (err.statements) { | ||
const statements = JSON.parse(err.statements); | ||
|
||
return statements | ||
.map(statement => `${statement[0]}\n${chalk.grey('=>')} ${statement[1]}`) | ||
.join('\n\n') + '\n'; | ||
} | ||
|
||
if ((err.actualType === 'object' || err.actualType === 'array') && err.actualType === err.expectedType) { | ||
const patch = diff.createPatch('string', err.actual, err.expected); | ||
const msg = patch | ||
.split('\n') | ||
.slice(4) | ||
.map(cleanUp) | ||
.filter(Boolean) | ||
.join('\n'); | ||
|
||
return `Difference:\n\n${msg}`; | ||
} | ||
|
||
if (err.actualType === 'string' && err.expectedType === 'string') { | ||
const patch = diff.diffChars(err.actual, err.expected); | ||
const msg = patch | ||
.map(part => { | ||
if (part.added) { | ||
return chalk.bgGreen.black(part.value); | ||
} | ||
|
||
if (part.removed) { | ||
return chalk.bgRed.black(part.value); | ||
} | ||
|
||
return part.value; | ||
}) | ||
.join(''); | ||
|
||
return `Difference:\n\n${msg}\n`; | ||
} | ||
|
||
return [ | ||
'Actual:\n', | ||
`${indentString(err.actual, 2)}\n`, | ||
'Expected:\n', | ||
`${indentString(err.expected, 2)}\n` | ||
].join('\n'); | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could use a single template string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried that, but didn't work out, because the resulting string contains code's indentation:
Am I doing smth wrong here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that's a common issue when using template strings like that. You either need to just remove the indent, which looks weird, or use something like https://github.com/sindresorhus/redent In this case, I don't think it's worth it.