-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Improving api #13
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
Improving api #13
Conversation
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.
Looking very good! Thanks! Just a few comments. Let's iterate and make this really amazing!
src/__tests__/fetch.js
Outdated
|
||
// Act | ||
Simulate.click(getByTestId('load-greeting')) | ||
|
||
await flushPromises() | ||
|
||
// Assert | ||
expect(queryByTestId('foo')).not.toBeInTheDOM() |
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 think people will look to these tests as an example of how to test their components with good practices.
With that in mind, let's do one of the following:
- Add a comment suggesting: "Here are a few assertions you could use, but you don't need all of them."
- Move these to a separate testing file that's intended to show off the different kinds of assertions.
I don't really care which we do.
src/__tests__/fetch.js
Outdated
@@ -1,6 +1,7 @@ | |||
import React from 'react' | |||
import axiosMock from 'axios' | |||
import {render, Simulate, flushPromises} from '../' | |||
import '../../extend-expect' //eslint-disable-line import/no-unassigned-import |
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 just disable this rule globally. It really annoys me and I should remove it from my base config eventually...
In the package.json
, update the eslintConfig
to have a rules
property that disables this rule 👍
src/jest-extensions.js
Outdated
toBeInTheDOM(received) { | ||
if (received) { | ||
return { | ||
message: () => 'expected the dom to be 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.
Rather than calling it "dom" call it "element." The received
is an element, not "dom" 👍
Same below.
src/jest-extensions.js
Outdated
const pass = textContent === checkWith | ||
if (pass) { | ||
return { | ||
message: () => `expected ${textContent} not equals to ${checkWith}`, |
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 use jest-matcher-utils
here so it's colored properly.
src/jest-extensions.js
Outdated
}, | ||
|
||
toHaveTextContent(htmlElement, checkWith) { | ||
const textContent = htmlElement.textContent |
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 add an extra check here that htmlElement
is actually instanceof HTMLElement
? If not we can:
throw new Error(`The given subject is a ${getDisplayName(htmlElement)}, not an HTMLElement`)
Or return an object, but this should probably fail regardless of whether people use .not
.
The getDisplayName
function could be something like this:
function getDisplayName(subject) {
if (subject && subject.constructor) {
return subject.constructor.name
} else {
return typeof subject
}
}
Or, maybe there's a better thing for this available on npm...
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 guess the code that you had mentioned getDisplayName
is enough. npm packages are there, but they offer many functionalities which we won't need at this time.
src/jest-extensions.js
Outdated
} | ||
} else { | ||
return { | ||
message: () => `expected ${textContent} equals to ${checkWith}`, |
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 use jest-matcher-utils
here so it's colored properly.
src/jest-extensions.js
Outdated
}, | ||
|
||
toSatisfyDOM(element, fn) { | ||
const pass = fn(element) |
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 think this should be more like this: https://github.com/jest-community/jest-extended/blob/master/src/matchers/toSatisfy/index.js
In fact, it looks like we should probably be changing everything in this file to use jest-matcher-utils
so it's colored properly etc. Unfortunately it looks like there are no docs, but here's the source.
@kentcdodds Hey, have addressed your comments also I have moved our assertions to |
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.
Looking awesome. Please address my few comments and let's add a section for these to the README please :) Thanks a ton!
src/__tests__/element-queries.js
Outdated
@@ -1,5 +1,6 @@ | |||
import React from 'react' | |||
import {render} from '../' | |||
import '../../extend-expect' |
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 problem with this is it means you have to run the build before you can run the tests (because on a fresh clone the dist
directory doesn't work). It also means that any changes to jest-extensions.js
wont be picked up by tests until the next build.
Instead, you'll basically need to duplicate the code.
Alternatively... You could put the code that's currently in extend-expect.js
into src/extend-expect.js
and then change the contents of: extend-expect.js
to be simply: require('./dist/extend-expect')
. Then you could update this import to simply: '../extend-expect'
👍
src/__tests__/element-queries.js
Outdated
<span data-testid="count-value">2</span>, | ||
) | ||
|
||
//other ways to assert your test cases, but you don't need all of them. |
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.
Not sure why prettier didn't add a space here, but please add a space before the o
:)
src/__tests__/element-queries.js
Outdated
//other ways to assert your test cases, but you don't need all of them. | ||
expect(queryByTestId('count-value')).toBeInTheDOM() | ||
expect(queryByTestId('count-value')).toHaveTextContent('2') | ||
expect(getByTestId('count-value')).toSatisfyDOM(el => el.textContent === '2') |
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 starting to question the value of this matcher. Maybe instead we should just recommend people use jest-extend instead. This is basically the same as toSatisfy
from there.
The other matchers are still very valuable though!
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.
@kentcdodds toSatisfyDOM
seems to be a fit for me in this library. Why we need to ask user to use jest-extend for a such a simple call? Yes, its almost the same code, but I feel it should be added. Anyways, let me know if you think otherwise.
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 that this matcher can be useful, but I'd much rather be very selective about what we include in this library. It's much easier to exclude something and add it later than add something and remove it later. So I lean on the side of excluding things. I'm thinking most people wont need this and those who do will be happy to include jest-extend I think.
src/jest-extensions.js
Outdated
) | ||
|
||
const textContent = htmlElement.textContent | ||
const pass = textContent === checkWith |
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 extend this to use the matcher
function that's in the queries.js
file? Perhaps we should move that matcher
function to a utils
file.
Using the matcher
function would allow the toHaveTextContent
to use a regex/case insensitive substring/function which I think would make this more powerful.
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 idea. Can take care of that, will move matcher
to utils
folder. Import matcher
in queries.js
and jest-extension.js
files to use them. So fundamentally the call would be:
const pass = matches(textContent,htmlElement,checkWith)
@kentcdodds Sure, will look into the changes and update the PR. |
Also, let's figure out what what extra coverage we need for our tests. Open |
@kentcdodds Yes, |
@kentcdodds Update the PR. Few things that are pending:
their use cases etc. Anything else is missing? |
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 like we still need docs in the README and we're not at 100% code coverage.
Also, there's a merge conflict in the README and .all-contributorsrc
. If you just deal with the conflict in .all-contributorsrc
then run npx kcd-scripts contributors generate
then that should fix the README 👍
Thank you so much for iterating on this!
src/utils.js
Outdated
@@ -0,0 +1,9 @@ | |||
export default function matches(textToMatch, node, matcher) { |
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.
Rather than exporting this as the default (because this file is called utils
), could we make it a named export (and feel free to disable the eslint warning, that's another one I've been meaning to disable).
function matches() {/* etc... */}
export {matches}
@kentcdodds This should be good to go. Let me know if anything else is needed. |
Codecov Report
@@ Coverage Diff @@
## master #13 +/- ##
=====================================
Coverage 100% 100%
=====================================
Files 2 5 +3
Lines 53 72 +19
Branches 13 17 +4
=====================================
+ Hits 53 72 +19
Continue to review full report at Codecov.
|
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 great! Thank you so much for these changes! Just a few docs changes please.
README.md
Outdated
The first one `toBeInTheDOM` which allows you to assert whether an element present in the DOM or not | ||
|
||
```javascript | ||
import 'extend-expect' //adds few API to jest's extend |
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 will be import 'react-testing-library/extend-expect'
README.md
Outdated
@@ -219,6 +219,31 @@ const usernameInputElement = getByTestId('username-input') | |||
> Learn more about `data-testid`s from the blog post | |||
> ["Making your UI tests resilient to change"][data-testid-blog-post] | |||
|
|||
#### `toBeInTheDOM` |
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 put these in a different section of the README (maybe right where it is).
So just change this to:
## Custom Jest Matchers
There are two simple custom Jest matchers which you can use to extend the `expect` API of Jest for making assertions easier.
### `toBeInTheDOM`
This allows you to assert whether or not an element present in the DOM
... etc.
README.md
Outdated
This API allows you to check whether the given element has a text content or not. | ||
|
||
```javascript | ||
import 'extend-expect' //adds few API to jest's extend |
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.
Here as well. Also, please add a space after the //
README.md
Outdated
|
||
render(<span data-testid="count-value">2</span>) | ||
expect(queryByTestId('count-value')).toHaveTextContent('2') | ||
expect(queryByTestId('count-value')).not.toHaveTextContent('21') |
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 these two examples, could we use getByTestId
rather than queryByTestId
?
README.md
Outdated
|
||
render(<span data-testid="count-value">2</span>) | ||
expect(queryByTestId('count-value')).toBeInTheDOM() | ||
expect(queryByTestId('count-value1')).not.toBeInTheDOM() |
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 you add a comment below that says: "Note: for this assertion, make sure you use a query
function (like queryByTestId
) rather than a get
function (like getByTestId
). Otherwise the get function could throw an error.
@@ -0,0 +1 @@ | |||
require('./dist/extend-expect') |
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.
Perfect
Sure Kent, will make these changes in sometime and update the PR. |
@kentcdodds Addressed your comments. Let me know if anything else is needed? |
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 great! Thanks!
Thanks so much for your help! I've added you as a collaborator on the project. Please make sure that you review the |
* added fireEvent util * remove react logic * 💯 coverage * Update README.md
chore: 🤖 add dom-testing-library as npm keyword
What: Improving test API
Why: Discussed already here : #3
How: Again as discussed :)
Checklist:
Related to this thread : #3