-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
assert: multiple improvements #21628
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
Changes from 1 commit
7589f42
671a3cc
511f8a1
e789901
4587e5d
c00e63d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
1) Switched + / - and red / green in diffs. It seems like that style is more natural to most people. 2) Short primitives do not use the diff anymore. Especially short numbers can be read well like 1 !== 2. Cases that can not be displayed like that (e.g., -0 and +0) use the regular diff output. 3) Improved error descriptions. It was not always clear what the messages stood for. That should now be resolved. 4) Added a position indicator for single lines in case a tty is used and the line is shorter than the visual columns.
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,13 +10,18 @@ let green = ''; | |
| let red = ''; | ||
| let white = ''; | ||
|
|
||
| const READABLE_OPERATOR = { | ||
| deepStrictEqual: 'Input A expected to strictly deep-equal input B', | ||
| notDeepStrictEqual: 'Input A expected to strictly not deep-equal input B', | ||
| strictEqual: 'Input A expected to strictly equal input B', | ||
| notStrictEqual: 'Input A expected to strictly not equal input B' | ||
| const kReadableOperator = { | ||
| deepStrictEqual: 'Expected input to be strictly deep-equal', | ||
| notDeepStrictEqual: 'Expected "actual" not to be strictly deep-equal', | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why use "actual" here?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is the value of the input argument "actual". I had hoped that this is actually clearer than the version before. Do you have a idea or a suggestion for to make it even better?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering why it's not
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is a combination of this message including the whole other output. Without the further output I agree with you. If we do a equal comparison the output would look like: assert.deepStrictEqual([1, 2, 3], [1, 2, 2]);
// Expected inputs to be strictly deep-equal:
// + actual - expected
//
//
// [
// 1,
// 2,
// + 3
// - 2
// ]While a not equal diff looks like: assert.notDeepStrictEqual([1, 2, 3], [1, 2, 3]);
// Expected "actual" not be strictly deep-equal
//
// [
// 1,
// 2,
// 3
// ]So the first part compares two different inputs (actual & expected) while the latter says that "actual" should not be equal to the afterwards printed value.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Thanks for the explanation, this seems fine. |
||
| strictEqual: 'Expected input to be strictly equal', | ||
| notStrictEqual: 'Expected "actual" to be strictly unequal', | ||
| notIdentical: 'Input identical but not reference equal:', | ||
| }; | ||
|
|
||
| // Comparing short primitives should just show === / !== instead of using the | ||
| // diff. | ||
| const kMaxShortLength = 10; | ||
|
|
||
| function copyError(source) { | ||
| const keys = Object.keys(source); | ||
| const target = Object.create(Object.getPrototypeOf(source)); | ||
|
|
@@ -49,22 +54,46 @@ function inspectValue(val) { | |
| } | ||
|
|
||
| function createErrDiff(actual, expected, operator) { | ||
| var other = ''; | ||
| var res = ''; | ||
| var lastPos = 0; | ||
| var end = ''; | ||
| var skipped = false; | ||
| let other = ''; | ||
| let res = ''; | ||
| let lastPos = 0; | ||
| let end = ''; | ||
| let skipped = false; | ||
| const actualLines = inspectValue(actual); | ||
| const expectedLines = inspectValue(expected); | ||
| const msg = READABLE_OPERATOR[operator] + | ||
| `:\n${green}+ expected${white} ${red}- actual${white}`; | ||
| const msg = kReadableOperator[operator] + | ||
| `:\n${green}+ actual${white} ${red}- expected${white}`; | ||
| const skippedMsg = ` ${blue}...${white} Lines skipped`; | ||
|
|
||
| let i = 0; | ||
| let indicator = ''; | ||
|
|
||
| if (actualLines.length === 1 && expectedLines.length === 1) { | ||
| const inputLength = actualLines[0].length + expectedLines[0].length; | ||
| if (inputLength <= kMaxShortLength) { | ||
| if ((typeof actual !== 'object' || actual === null) && | ||
| (typeof expected !== 'object' || expected === null) && | ||
| (actual !== 0 || expected !== 0)) { // -0 === +0 | ||
| return `${kReadableOperator[operator]}:\n\n` + | ||
| `${actualLines[0]} !== ${expectedLines[0]}\n`; | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please add a comment explaining this block of logic?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| } else if (process.stdout.isTTY && | ||
| inputLength < process.stdout.columns && | ||
| actualLines[0] !== expectedLines[0]) { | ||
| while (actualLines[0][i] === expectedLines[0][i]) { | ||
| i++; | ||
| } | ||
| // Add position indicator for the first mismatch in case it is a single | ||
| // line and the input length is less than the column length. | ||
| indicator = `\n ${' '.repeat(i)}^`; | ||
| i = 0; | ||
| } | ||
| } | ||
|
|
||
| // Remove all ending lines that match (this optimizes the output for | ||
| // readability by reducing the number of total changed lines). | ||
| var a = actualLines[actualLines.length - 1]; | ||
| var b = expectedLines[expectedLines.length - 1]; | ||
| var i = 0; | ||
| let a = actualLines[actualLines.length - 1]; | ||
| let b = expectedLines[expectedLines.length - 1]; | ||
| while (a === b) { | ||
| if (i++ < 2) { | ||
| end = `\n ${a}${end}`; | ||
|
|
@@ -88,8 +117,8 @@ function createErrDiff(actual, expected, operator) { | |
| } | ||
|
|
||
| const maxLines = Math.max(actualLines.length, expectedLines.length); | ||
| var printedLines = 0; | ||
| var identical = 0; | ||
| let printedLines = 0; | ||
| let identical = 0; | ||
| for (i = 0; i < maxLines; i++) { | ||
| // Only extra expected lines exist | ||
| const cur = i - lastPos; | ||
|
|
@@ -106,7 +135,7 @@ function createErrDiff(actual, expected, operator) { | |
| printedLines++; | ||
| } | ||
| lastPos = i; | ||
| other += `\n${green}+${white} ${expectedLines[i]}`; | ||
| other += `\n${red}-${white} ${expectedLines[i]}`; | ||
| printedLines++; | ||
| // Only extra actual lines exist | ||
| } else if (expectedLines.length < i + 1) { | ||
|
|
@@ -122,7 +151,7 @@ function createErrDiff(actual, expected, operator) { | |
| printedLines++; | ||
| } | ||
| lastPos = i; | ||
| res += `\n${red}-${white} ${actualLines[i]}`; | ||
| res += `\n${green}+${white} ${actualLines[i]}`; | ||
| printedLines++; | ||
| // Lines diverge | ||
| } else if (actualLines[i] !== expectedLines[i]) { | ||
|
|
@@ -138,8 +167,8 @@ function createErrDiff(actual, expected, operator) { | |
| printedLines++; | ||
| } | ||
| lastPos = i; | ||
| res += `\n${red}-${white} ${actualLines[i]}`; | ||
| other += `\n${green}+${white} ${expectedLines[i]}`; | ||
| res += `\n${green}+${white} ${actualLines[i]}`; | ||
| other += `\n${red}-${white} ${expectedLines[i]}`; | ||
| printedLines += 2; | ||
| // Lines are identical | ||
| } else { | ||
|
|
@@ -159,12 +188,8 @@ function createErrDiff(actual, expected, operator) { | |
| } | ||
|
|
||
| // Strict equal with identical objects that are not identical by reference. | ||
| // E.g., assert.deepStrictEqual({ a: Symbol() }, { a: Symbol() }) | ||
| if (identical === maxLines) { | ||
| // E.g., assert.deepStrictEqual(Symbol(), Symbol()) | ||
| const base = operator === 'strictEqual' ? | ||
| 'Input objects identical but not reference equal:' : | ||
| 'Input objects not identical:'; | ||
|
|
||
| // We have to get the result again. The lines were all removed before. | ||
| const actualLines = inspectValue(actual); | ||
|
|
||
|
|
@@ -177,9 +202,10 @@ function createErrDiff(actual, expected, operator) { | |
| } | ||
| } | ||
|
|
||
| return `${base}\n\n${actualLines.join('\n')}\n`; | ||
| return `${kReadableOperator.notIdentical}\n\n${actualLines.join('\n')}\n`; | ||
| } | ||
| return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}`; | ||
|
|
||
| return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}${indicator}`; | ||
| } | ||
|
|
||
| class AssertionError extends Error { | ||
|
|
@@ -231,7 +257,7 @@ class AssertionError extends Error { | |
| // In case the objects are equal but the operator requires unequal, show | ||
| // the first object and say A equals B | ||
| const res = inspectValue(actual); | ||
| const base = `Identical input passed to ${operator}:`; | ||
| const base = kReadableOperator[operator]; | ||
|
|
||
| // Only remove lines in case it makes sense to collapse those. | ||
| // TODO: Accept env to always show the full error. | ||
|
|
||
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.
suggestion: "inputs" instead of "input"
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.
I am good either way as it seems that both would work. @Trott @vsemozhetbyt do you have a preference?
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.
For me, "inputs" seems more clear (no confusing "input is deep-equal — to what?"), but I am not a native speaker)
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.
I agree with @targos and @vsemozhetbyt for the reason offered by @vsemozhetbyt (using "inputs" removes potential ambiguity).