-
Notifications
You must be signed in to change notification settings - Fork 1.1k
TypeError: Cannot read property textContent of null when you expect a property on a missing element queried by data-testid #3
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
Comments
Thanks for filing this @sompylasar! For more context, here's what the error looks like when I make a typo in a similar test: TypeError: Cannot read property 'textContent' of null
18 | test('calling render with the same component on the same container does not remount', () => {
19 | const {container, queryByTestId} = render(<NumberDisplay number={1} />)
> 20 | expect(queryByTestId('number-displays').textContent).toBe('1')
21 |
22 | // re-render the same component with different props
23 | // but pass the same container in the options argument.
at Object.<anonymous>.test (src/__tests__/number-display.js:20:10) The fact that Jest will call out the line number where the error happened makes the problem less concerning for me. I think that people will understand what went wrong. And just to be clear for everyone, we're not throwing any errors, this is a regular JavaScript error (trying to read For the benefit of everyone else, I talked with @sompylasar about this already. He asked if we could throw an error in expect(queryByTestId('foo')).not.toBeTruthy() Where you're trying to assert that something does not exist. So one thing's for sure: We will not be changing the current behavior. However, it would be nice to improve the error message. One suggestion @sompylasar made is we could create a new function called Another idea I had is to create custom expect matchers that people can use in their apps that could throw more helpful error messages: expect(queryByTestId('foo')).not.toBeInTheDOM()
expect(queryByTestId('number-display')).toHaveTextContent('1') I don't think I'll work on these myself, but I would be happy to accept a contribution that adds this capability with a simple API :) |
@kentcdodds: I give it a shot, the implementation looks like the following: expect.extend({
toBeInTheDOM(received) {
if (received) {
return {
message: () =>
'expected the dom to be present',
pass: true,
};
} else {
return {
message: () => 'expected the dom not to be present',
pass: false,
};
}
},
})
expect.extend({
toHaveTextContent(htmlElement,checkWith) {
console.log(htmlElement.textContent)
let pass = htmlElement.textContent === checkWith;
if (pass) {
return {
message: () =>
`expected ${htmlElement.textContent} not equals to ${checkWith}`,
pass: true,
};
} else {
return {
message: () => `expected ${htmlElement.textContent} equals to ${checkWith}`,
pass: false,
};
}
},
}) And I used in expect(queryByTestId('foo')).not.toBeInTheDOM()
expect(queryByTestId('greeting-text')).toBeInTheDOM()
expect(queryByTestId('greeting-text')).toHaveTextContent('hello there') Everything was green! If you find this good enough, then I can export these functions as a simple API. By the way thanks for a neat small library. The |
console.log(htmlElement.textContent)
let pass = htmlElement.textContent === checkWith;
if (pass) {
return {
message: () =>
`expected ${htmlElement.textContent} not equals to ${checkWith}`,
pass: true,
};
} else {
return {
message: () => `expected ${htmlElement.textContent} equals to ${checkWith}`,
pass: false,
};
} I'd suggest retrieving |
@sompylasar Agreed and it was a quick implementation for you guys to review. Will take care when I raise a PR. |
Another suggestion: a generic matcher .toMatchDOM(el => el.textContent === 'hello') where |
@sompylasar I like this idea, as we are allowing the user to pass their own assert function to execute in the current assertion context. |
I'd rather it be called: There's a |
Another related issue with the The rejected proposal of throwing an error would resolve this issue as well since it would no longer return What are your thoughts on this problem? I lean towards fudging the type declaration as the developer experience is really bad when |
What if you just write a small wrapper around the |
For the same reason I would use a 29-lines react-testing-library instead of having the small wrappers it provides inside my test/project. |
Yeah, I don't love that idea as it creates a reasonable amount of friction for devs. I think it's very similar to how you imported and re-exported react-dom APIs in this library to ease the friction. Having teams learn and use this library, but getting them to not use the render function in favor of some other wrapper we have is probably a deal breaker in terms of making things easy for them. Also, how do you feel about the code exhibited in this library not being possible for the many teams that are writing typed JavaScript, either via Flow or TypeScript? I realize those teams are probably still in the minority, but likely not an insignificant percentage. As such a consumer, I'd prefer to see the type definitions relaxed (made incorrect) to ease the development at the cost of type-safety in error scenarios for our tests. One other option I will explore, that you might prefer, is to overwrite the type definitions for this library in my project. I still feel like this is a hack and that it's not better than changing the definitions in this library itself, but at least would offer up another alternative. |
Ok, here are a few ideas: Add options to const queryByTestId = render(<MyThing />)
expect(queryByTestId('foo', {throwIfMissing: true})).toBeTruthy() Add const queryByTestId = render(<MyThing />)
expect(getByTestId('foo')).toBeTruthy() I'm not huge on the idea of expanding the API for something like this, but I appreciate the usefulness to some teams. And honestly, if we did this, I'd probably recommend people use this. Most of the time you wont want the return value to be Anyway, I think I'd accept a PR that:
I think this will make everyone happier :) |
Thanks @kentcdodds, that sounds reasonable to me. I'll start throwing together a PR. |
@kentcdodds Hey, do you want to me to raise a PR for these methods:
Where do you want me to place these extensions? |
How about you do this:
What do you think? |
If I understand things correctly, it should be the following approach:
3 & 4 seems to be fine. I'm wondering why there is a split up on logic in these two files? Why can't be in a single shot and have a test cases for the same? Any benefit we get with the split up? |
The reason to split it up is so people can just do this in their test files: import 'react-testing-library/extend-expect' It's explicit, but it's really easy. And it means that if someone wanted to use them differently, or only use one of them, they could: import {toBeInTheDOM} from 'react-testing-library/dist/jest-extensions'
expect.extend({toBeInTheDOM}) Gives a bit more flexibility without sacrificing usability. |
@kentcdodds Ahh, that make sense to me. Will do the same and raise a PR. Thanks! |
Ok, @pbomb's PR was merged. A release should be out soon and you'll be able to use |
For the record, the link to PR: #10 |
I think we've dealt with this 👍 |
@sompylasar, if you'd like to make a pr to add yourself to the contributor table you're more than welcome. You can follow the instructions in the CONTRIBUTING.md 👍 |
@kentcdodds Thanks! |
👉 #29 |
* feat(debug_helper): Adding debug helper when a get call fails * fix(review): Few minor changes * moving pretty-format to the dep * fix(review_comments): Making the fixes mentioned in the review comments * Update README.md * Update element-queries.js
fix: 🐛 allow to click elements within labels
react-testing-library
version: 1.0.1node
version: n/anpm
(oryarn
) version: n/aRelevant code or config
What you did:
Did not render the element with
'greeting-text'
identifier.What happened:
TypeError: Cannot read property textContent of null
Reproduction repository:
https://codesandbox.io/s/4q3zol71y9
Problem description:
The error does not describe what has gone wrong.
Suggested solution:
Throw a user-friendly error.
The text was updated successfully, but these errors were encountered: