-
Notifications
You must be signed in to change notification settings - Fork 470
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(debug_helper): Adding debug helper when a get call fails #3
Conversation
Codecov Report
@@ Coverage Diff @@
## master #3 +/- ##
=====================================
Coverage 100% 100%
=====================================
Files 7 5 -2
Lines 127 102 -25
Branches 33 27 -6
=====================================
- Hits 127 102 -25
Continue to review full report at Codecov.
|
src/queries.js
Outdated
@@ -1,4 +1,6 @@ | |||
import {matches} from './matches' | |||
import prettyFormat from 'pretty-format' // eslint-disable-line |
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.
Why eslint-disable-line 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.
So basically pretty-format
is not part of the package.json - dependencies but its part of jest
I believe. Hence I have added the eslint-disable-line
, yes, I need to clean up a bit by adding the exact eslint-ignore for the same.
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.
But what if I don't use jest with dom-testing-library?
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.
Sorry, pretty-format
is from jest-matcher-utils
(https://github.com/facebook/jest/blob/master/packages/jest-matcher-utils/package.json#L14) which is in our dependencies. Sorry for the rushed comment, saying it as jest
in first place!
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.
Hmm.. Is there a reason for not depending on pretty-format directly as well? :)
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.
@lgandecki We use custom jest assertions, for which we depend on jest-matcher-utils
. As part of printing the DOM, we thought we could use pretty-format
as it was already part of the jest-matcher-utils
and it does actually a good job. It works well for our use case, so why not? :)
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'm not against using pretty-format, I'm just trying to understand if there is a reason to not put it in package.json as a direct dependency. Then there is no need to fight around eslint complaining (rightly). And if jest-matcher-utils switch to something else internally and stop requiring pretty-format, our package will still work.
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.
Agreed
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.
@lgandecki Yes, I agree. Will make the changes. Thanks your comments!
src/queries.js
Outdated
} | ||
return el | ||
} | ||
|
||
function checkDebugLimit(debugContent) { |
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.
The name is confusong: it shouldn't be "check" (would return boolean), it is more of a "trimToDebugLimit".
src/queries.js
Outdated
} | ||
return el | ||
} | ||
|
||
function checkDebugLimit(debugContent) { | ||
const limit = process.env.DEBUG_PRINT_LIMIT |
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 if the limit needed in browser where there's no env, e.g. via Cypress?
I suggest exporting a mutable "defaultOptions" object from the module instead, like Node's util.inspect.defaultOptions.
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.
Yes, thats a good point.
src/queries.js
Outdated
debugContent = debugContent.slice(0, 7000) | ||
if (contentLength >= 7000) | ||
// there are more chars we have stripped, just show to the user | ||
debugContent += '\n . . .' |
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.
The above "if" and "else" are essentially copy-paste except limit
is replaced with a default value.
I suggest pulling the "magic number" into a "defaultOptions" object and use it like so:
const limit = defaultOptions.limit;
// OR: const limit = defaultOptions.limit || 7000;
const contentLength = debugContent.length
debugContent = debugContent.slice(0, limit)
if (limit <= contentLength)
// there are more chars we have stripped, just show to the user
debugContent += '\n . . .'
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.
Yes, I agree. Can be improved. This is just a rough draft, I have to clean up few things. Thanks for your comments.
@kentcdodds Hey Kent.. @sompylasar suggested the following:
w.r.t to process env for |
Ping, any thoughts on my last comment? Guess people missed it ;) cc @kentcdodds |
I have thoughts. Patience. Not all of us have time to address this within hours or days. We'll get to it when we can 😉 One thing you could do is rebase your branch and fix merge conflicts 😀 |
@kentcdodds Oops! Sorry thought people had missed it. will do the rebase and update the branch. |
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.
Some thoughts and ideas :)
README.md
Outdated
For example: | ||
|
||
```javascript | ||
;`<div data-testid="debugging" data-otherid="debugging"> |
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.
prettier added the ;
to make this valid javascript.
Why don't we replace this whole block with:
```javascript
// <div>Hello world</div>
getByText(container, 'Goodbye world') // will fail by throwing error
```
This way:
- There's less noise that could distract from people's understanding of what's happening
- There's no weird
;
- We're using
getByText
properly (withcontainer
as the first arg).
README.md
Outdated
The above test case will fail, however it prints the state of your DOM under test, so you will get to see: | ||
|
||
``` | ||
Unable to find an element with the text: Test value.. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible. |
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.
"Test value." -> "Goodbye world"
README.md
Outdated
> | ||
Hello World! | ||
</div> | ||
</div> |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
README.md
Outdated
</div> | ||
``` | ||
|
||
Note: Since the DOM size can go really large, you can set the limit of DOM content to be printed via environment variable `DEBUG_PRINT_LIMIT`. |
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.
"go" -> "get"
src/queries.js
Outdated
throw new Error( | ||
`Unable to find an element with the placeholder text of: ${text}`, | ||
`Unable to find an element with the placeholder text of: ${text} \nHere is the state of your container: \n${htmlElement}`, |
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.
Let's remove the text: "Here is the state of your container" entirely. I think people will know what the printed HTML is without that.
src/queries.js
Outdated
} | ||
return el | ||
} | ||
|
||
function getByPlaceholderText(container, text, ...rest) { | ||
const el = queryByPlaceholderText(container, text, ...rest) | ||
if (!el) { | ||
const htmlElement = trimToDebugLimit( |
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 we make a function called htmlElementToDisplay
that trims and formats it, so we don't have to duplicate this everywhere.. Also, make sure that it compares the length of the html
string rather than the formatted version because the formatted version will have extra characters for the highlighting.
I envision the error code below looking like:
throw new Error(
`Unable to find an element with the placeholder text of: ${text}\n\n${htmlElementToDisplay(htmlElement)}`,
)
And the htmlElementToDisplay
should be something like:
function htmlElementToDisplay(htmlElement) {
const debugContent = prettyFormat(htmlElement, {
plugins: [DOMElement, DOMCollection],
printFunction: false,
highlight: true
})
const maxLength = process.env.DEBUG_PRINT_LIMIT || 7000
return htmlElement.outerHTML.length > maxLength ? `${debugContent.slice(0, maxLength)}...` : debugContent
}
Note the addition of DOMCollection
to the plugins (handles an array of nodes I think). Also note that we checking the maxLength against htmlElement.outerHTML
. If we checked it against debugContent
then we'd get a length that wasn't quite right (because the debugContent
includes a bunch of characters for the coloring).
src/__tests__/element-queries.js
Outdated
process.env.DEBUG_PRINT_LIMIT = 10000 // user shouldn't see `. . .` | ||
expect(() => | ||
expect(getByLabelText('not present')).toBeInTheDOM(), | ||
).toThrowError() |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
src/__tests__/element-queries.js
Outdated
</div>` | ||
const {getByTestId} = render(Hello) | ||
process.env.DEBUG_PRINT_LIMIT = 10 // user should see `. . .` | ||
expect(() => expect(getByTestId('not present')).toBeInTheDOM()).toThrowError() |
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 is a good assertion, but we should add another assertion to make sure the error includes the ...
You can do this by adding a regex to the toThrowError
call:
.toThrowError(/\.\.\./)
In the one below we should do the opposite
.toThrowError(/^((?!\.\.\.).)*$/)
I'm pretty sure that should verify that there is no ...
in the error message.
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.
Sorry, meant to set my review to "Request changes" rather than "Approve"
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.
Sorry, meant to set my review to "Request changes" rather than "Approve"
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 is super! Thanks so much for your help on this!
@kentcdodds Did we go with unchecked process.env for configuration? |
🎉 This PR is included in version 1.4.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
Yes, for this first release I thought it'd be fine to go with the process.env-only approach. Though now that I think about it that will break the browser case. We should probably protect that reference 🤔 I was planning on accepting a PR for enhancing the configurability of this feature. I didn't consider that this would break the browser use-case. |
That said, anyone using this in the browser will be using a bundler so I'm pretty sure this'll be fine. |
I thought about this, too. Although I'm not 100% sure. @antoaravinth Could you please check if this holds true at least for Cypress? You can do so from |
@sompylasar Yes it will. I have checked anyways:
|
@antoaravinth Awesome! 👍 |
Fix for testing-library/react-testing-library#31
@kentcdodds Let me know if things are good to go!