-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
feat(testrunner): better matchers #1077
Conversation
This patch re-implements matching and reporting for test runner. Among other improvements: - test failures now show a short snippet from test - test failures now explicitly say what received and what was expected - `expect.toBe()` now does text diff when gets strings as input - `expect.toEqual` now does object diff
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.
Looks exciting!
@@ -20,6 +20,7 @@ const Diff = require('text-diff'); | |||
const PNG = require('pngjs').PNG; | |||
const jpeg = require('jpeg-js'); | |||
const pixelmatch = require('pixelmatch'); | |||
const c = require('colors/safe'); |
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.
nit: s/c/colors
You taught me that we don't abbreviate like that :)
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.
done
utils/testrunner/Matchers.js
Outdated
super(message); | ||
this.name = this.constructor.name; | ||
this.formatter = formatter; | ||
this.location = getLocation(__filename); |
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.
How does this work? Won't __filename
be the Matcher.js
file? Why do we care about that file, rather than the spec.js that threw this error.
Update: I got to the getLocation code. It makes more sense. Would it be fair to call this method "getParentFile" or something? I assumed it was doing something very different. I guess its fine.
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.
getCallerLocation
!
this.name = this.constructor.name; | ||
this.formatter = formatter; | ||
this.location = getLocation(__filename); | ||
Error.captureStackTrace(this, this.constructor); |
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.
What does this line do? Shouldn't calling super already capture a stack trace?
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.
That's to filter out the custom error constructor from the stack trace. That's a canonical way to create a custom error in node, e.g. see 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.
It's not in firefox, which hurts the portability of the test runner, but I can probably polyfill it.
utils/testrunner/Matchers.js
Outdated
} | ||
}; | ||
|
||
class MatchError extends Error { | ||
constructor(message, formatter = null) { |
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.
nit: formatter = defaultFormatter
Then you can avoid a null check 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.
formatter is bound at least to the received
argument; but the = null
part is actually never needed. Thanks!
@@ -422,7 +395,10 @@ class TestRunner extends EventEmitter { | |||
const runnableTests = this._runnableTests(); | |||
this.emit(TestRunner.Events.Started, runnableTests); | |||
this._runningPass = new TestPass(this, this._rootSuite, runnableTests, this._parallel, this._breakOnFailure); | |||
const termination = await this._runningPass.run(); | |||
const termination = await this._runningPass.run().catch(e => { | |||
console.error(e); |
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.
this looks strange? We log an error and then throw it again? Is something consuming errors or something? Leftover debug code?
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.
if testrunner.run()
is not awaited and there's an issue with testrunner itself, then it crashes silently with an unhandled promise rejection that doesn't have any stack.
This gives the stack.
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.
Is there a case where this gives you a double error message? Or this is always just problems with the test runner itself, to avoid unhandledpromiserejection woes?
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.
Yeah, that's always for the bugs in the testrunner itself
This patch re-implements matching and reporting for test runner.
Among other improvements:
expect.toBe()
now does text diff when gets strings as inputexpect.toEqual
now does object diffExample output of a failed test: