-
Notifications
You must be signed in to change notification settings - Fork 150
feat: no-get-by-for-checking-element-not-present #65
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
Conversation
@Belco90 If you ever see something missing in the docs or misexplained, could you handle it? I have to admit I'm still not really convinced by the usefulness of that rule and I think you have the use cases in mind. |
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.
Had a quick look, looks good so far 👌
56e08ca
to
0d11ebd
Compare
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 looks like the motivation for this rule has been misunderstood, in part it was my fault because of some wrong examples I added before to previous rule doc. If you see the original issue, you can see properly the two different cases when this rule should be applied:
- Asserting elements are not present: here we need to look for a
expect
statement and few specific matchers as.not.toBeInTheDocument()
,.toBeNull()
or.toBeFalsy()
- Waiting for disappearance: here we do not have to look for a
expect
statement, butwaitForElementToBeRemoved
method
The rule doesn't need a huge amount of changes tho, just clarifying things in the docs and examples, add more test cases and maybe improve the rule implementation for some edge cases.
README.md
Outdated
| [no-dom-import](docs/rules/no-dom-import.md) | Disallow importing from DOM Testing Library | ![angular-badge][] ![react-badge][] ![vue-badge][] | ![fixable-badge][] | | ||
| [prefer-explicit-assert](docs/rules/prefer-explicit-assert.md) | Suggest using explicit assertions rather than just `getBy*` queries | | | | ||
| [consistent-data-testid](docs/rules/consistent-data-testid.md) | Ensure `data-testid` values match a provided regex. | | | | ||
| [no-get-by-for-asserting-element-not-present](docs/rules/no-get-by-for-asserting-element-not-present) | Disallow the use of `expect(getBy*)` when elements are not present | | | |
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-get-by-for-asserting-element-not-present](docs/rules/no-get-by-for-asserting-element-not-present) | Disallow the use of `expect(getBy*)` when elements are not present | | | | |
| [no-get-by-for-asserting-element-not-present](docs/rules/no-get-by-for-asserting-element-not-present) | Disallow the use of `getBy*` queries when checking elements are not present | | | |
@@ -1,75 +1,58 @@ | |||
# Disallow the use of `expect(getBy*)` (prefer-expect-query-by) | |||
# Disallow the use of `expect(getBy*)` when elements are not present (no-get-by-for-asserting-element-not-present) |
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.
# Disallow the use of `expect(getBy*)` when elements are not present (no-get-by-for-asserting-element-not-present) | |
# Disallow the use of `getBy*` queries when checking elements are not present (no-get-by-for-asserting-element-not-present) |
|
||
The (DOM) Testing Library allows to query DOM elements using different types of queries such as `getBy*` and `queryBy*`. Using `getBy*` throws an error in case the element is not found. This is useful when: | ||
|
||
- using method like `waitForElement`, which are `async` functions that will wait for the element to be found until a certain timeout, after that the test will fail. | ||
- using `getBy` queries as an assert itself, so if the element is not found the error thrown will work as the check itself within the test. | ||
|
||
However, when trying to assert if an element is not present or disappearance, we can't use `getBy*` as the test will fail immediately. Instead it is recommended to use `queryBy*`, which does not throw and therefore we can assert that e.g. `expect(queryByText("Foo")).not.toBeInTheDocument()`. | ||
However, when trying to assert if an element is not present or disappearance, using `getBy*` will make the test fail immediately. Instead it is recommended to use `queryBy*`, which does not throw and therefore we can assert that e.g. `expect(queryByText("Foo")).not.toBeInTheDocument()`. |
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.
However, when trying to assert if an element is not present or disappearance, using `getBy*` will make the test fail immediately. Instead it is recommended to use `queryBy*`, which does not throw and therefore we can assert that e.g. `expect(queryByText("Foo")).not.toBeInTheDocument()`. | |
However, when asserting if an element is not present or waiting for disappearance, using `getBy*` will make the test fail immediately. Instead it is recommended to use `queryBy*`, which does not throw and therefore we can: | |
- assert element does not exist: `expect(queryByText("Foo")).not.toBeInTheDocument()` | |
- wait for disappearance: `await waitForElementToBeRemoved(() => queryByText('the mummy'))` |
|
||
The (DOM) Testing Library allows to query DOM elements using different types of queries such as `getBy*` and `queryBy*`. Using `getBy*` throws an error in case the element is not found. This is useful when: | ||
|
||
- using method like `waitForElement`, which are `async` functions that will wait for the element to be found until a certain timeout, after that the test will fail. | ||
- using `getBy` queries as an assert itself, so if the element is not found the error thrown will work as the check itself within the test. | ||
|
||
However, when trying to assert if an element is not present or disappearance, we can't use `getBy*` as the test will fail immediately. Instead it is recommended to use `queryBy*`, which does not throw and therefore we can assert that e.g. `expect(queryByText("Foo")).not.toBeInTheDocument()`. | ||
However, when trying to assert if an element is not present or disappearance, using `getBy*` will make the test fail immediately. Instead it is recommended to use `queryBy*`, which does not throw and therefore we can assert that e.g. `expect(queryByText("Foo")).not.toBeInTheDocument()`. | ||
|
||
> The same applies for the `getAll*` and `queryAll*` queries too. |
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 really sure if this rule should be applied to getAllBy
. You can't check expect(getAllByText('Foo')[0]).toBeNull()
as that would return undefined
, so you'll need to use a different matcher. In addition, there is no reference to getAllBy
in testing library docs, so I would remove this comment and apply this rule only to getBy
.
|
||
> The same applies for the `getAll*` and `queryAll*` queries too. | ||
|
||
## Rule details | ||
|
||
This rule gives a notification whenever `expect` is used with one of the query functions that throw an error if the element is not found. | ||
This rule gives a notification whenever `expect` is used with one of the query functions that throws an error if the element is not found. |
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 rule gives a notification whenever `expect` is used with one of the query functions that throws an error if the element is not found. | |
This rule gives a notification whenever: | |
- `expect` is used to assert element does not exist with `.not.toBeInTheDocument()` or `.toBeNull()` matchers | |
- `waitForElementToBeRemoved` async util is used to wait for element to be removed from DOM |
docs: { | ||
category: 'Best Practices', | ||
description: | ||
'Disallow the use of getBy* queries in expect calls when elements may be absent', |
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.
'Disallow the use of getBy* queries in expect calls when elements may be absent', | |
'Disallow the use of `getBy*` queries when checking elements are not present', |
{ code: `expect(${queryName}('Hello')).toBeTruthy()` }, | ||
{ code: `expect(rendered.${queryName}('Hello')).toEqual("World")` }, | ||
{ code: `expect(rendered.${queryName}('Hello')).not.toBeFalsy()` }, | ||
], |
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.
We need valid tests for waitForElementToBeRemoved
, which is the second part of the rule.
], | ||
[] | ||
), | ||
invalid: getByVariants.reduce( |
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.
We should apply this only to getBy
errors: [{ messageId: 'expectQueryBy' }], | ||
}, | ||
{ | ||
code: `expect(${queryName}('Hello')).toBeUndefined()`, |
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 sure about this one. toBeUndefined
won't work even using queryBy
as it returns null
so we should not include this one in the rule probably.
}, | ||
{ | ||
code: `(async () => { | ||
await waitForElementToBeRemoved(() => { |
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 would other variants for this one having arrow function returning implicitly and having a regular function.
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.
Rule has to be renamed again for not mentioning asserting in the name, right?
Also: this is a breaking change as we are removing previous prefer-expect-query-by
rule, so we need to add BREAKING CHANGE comment when merging this.
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.
Thank, we're almost there 🙌
```js | ||
test('some test', () => { | ||
const { getByText } = render(<App />); | ||
expect(getByText('Foo')).toBeInTheDocument(); |
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.
expect(getByText('Foo')).toBeInTheDocument(); | |
expect(getByText('Foo')).toBeInTheDocument(); | |
expect(queryByText('Foo')).not.toBeInTheDocument(); | |
expect(queryByText('Foo')).toBeFalsy(); |
}, | ||
messages: { | ||
expectQueryBy: | ||
'Use `expect(getBy*)` only when elements are present, otherwise use `expect(queryBy*)`.', |
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.
'Use `expect(getBy*)` only when elements are present, otherwise use `expect(queryBy*)`.', | |
'Use `getBy*` only when elements are present, otherwise use `queryBy*` when checking that elements are not present.', |
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 when cheking that elements are not present
necessary? I feel like it's too much, what about:
Use getBy* only when checking elements are present, otherwise use queryBy*
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.
Brilliant! Thank you so much for your effort and sorry for previous misleading comments.
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.
Very nice, thanks again for improving the rule! 💯
Awesome. Tomorrow morning I'll create the PR for |
…absent-elements # Conflicts: # README.md
🎉 This PR is included in version 2.0.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Closes #61