Skip to content

docs: userEvent/convenience Example Code #1283

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

Merged
merged 9 commits into from
Aug 25, 2023

Conversation

ssi02014
Copy link
Contributor

@ssi02014 ssi02014 commented Jul 21, 2023

I wrote the example code for the "user-event/Convenience APIs".

user-event v13 I think it would be helpful for more people to have example code like on the page.

Except for "hover" and "unhover", this is based on the user-event v13 example code.

The example code all passes the tests fine.

스크린샷 2023-07-21 오후 10 04 52

@netlify
Copy link

netlify bot commented Jul 21, 2023

Deploy Preview for testing-library ready!

Name Link
🔨 Latest commit 39e31c9
🔍 Latest deploy log https://app.netlify.com/sites/testing-library/deploys/64c806d285b8540008fdc554
😎 Deploy Preview https://deploy-preview-1283--testing-library.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@ssi02014
Copy link
Contributor Author

Hi, @timdeschryver 👋
I wanted to contribute to that repository, so I created this pull request.

Is my work appropriate for that repository?
I'd appreciate it if you could take a look

Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution @ssi02014 !
What do you think of it @ph-fritsche ?


await userEvent.hover(hoverBox)

expect(hoverBox).toHaveStyle({backgroundColor: 'red'})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you update this expectation please?
For example, to update the text of the div element instead.
The reason for this is that I personally don't like the toHaveStyle expectations, and IIRC some of the testing environments don't support this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@timdeschryver
Oh, thank you.
I have modified the example code according to your comments.

@ssi02014 ssi02014 requested a review from timdeschryver July 25, 2023 18:31
@ph-fritsche
Copy link
Member

I'm not sure about this. Examples bloat the docs and it is difficult to keep them concise and accurate.
Someone who understands all the implications without extra comments might not need an example at all, whereas someone who needs an example might be misled to believe everything in the example is best practice.
Misunderstandings will be perpetuated by quoting these examples on other platforms/channels like Stackoverflow.

// The title doesn't matter for the example, but in a real project it should tell about the tested behavior.
test('click', async () => {
  // Yes, using `.setup()` is recommended and for a few tests this can be inlined,
  // but if certain steps like calling `render()` and `userEvent.setup()` are repeated throughout a test suite
  // we also recommend to use your own setup function that includes all these steps for better readability.
  const user = userEvent.setup()
  const onChange = jest.fn()
  render(<input type="checkbox" onChange={onChange} />)

  const checkbox = screen.getByRole('checkbox')

  await user.click(checkbox)

  // Here we assert that UserEvent, the framework library and the DOM implementation do work.
  // The code excerpts we see on Stackoverflow, Discord, etc. often include many assertions like these
  // and often enough they lack assertions on behavior implemented in the subject under test.
  expect(onChange).toHaveBeenCalledTimes(1)
  expect(checkbox).toBeChecked()
})

If we want to include (more) examples, maybe we should create a small example project that really adheres to best practices.

@ssi02014
Copy link
Contributor Author

ssi02014 commented Jul 26, 2023

@ph-fritsche @timdeschryver
Thank you for your review.

but if certain steps like calling render() and userEvent.setup() are repeated throughout a test suite
we also recommend to use your own setup function that includes all these steps for better readability.

I write independent test code for each case, which is why I had the problem you describe above.

If we want to include (more) examples, maybe we should create a small example project that really adheres to best practices.

This is actually the best.

I sympathize with your comments as well.

I found the user-event v13 page very helpful when I first started using "userEvent", and I wrote the following pull request based on my experience.

I figured this might help others as much as it helped me.

https://testing-library.com/docs/user-event/utility/
Also, the example code was already written on that page, so I thought it would be a good fit.

I'd like you to draw your own conclusions about the pull request. 🙏
I intend to follow your opinion.

@timdeschryver
Copy link
Member

Thanks for the feedback @ph-fritsche .

I agree with your points, and I think that having a small example in the docs that covers the usage is helpful (and acts as a starting point), that's why we should keep it at a minimum.

The proposed examples project is a good idea, but it's a bit out of scope for this PR (but can be a reason to close this PR).

Is this something that we can all agree with?
An example for click might look as follows, where it just verifies its behavior.

test('click', async () => {
  const user = userEvent.setup()
  render(<input type="checkbox" />)
  
  const checkbox = screen.getByRole('checkbox')
  await user.click(checkbox)

  expect(checkbox).toBeChecked()
})

@ssi02014
Copy link
Contributor Author

ssi02014 commented Jul 26, 2023

@timdeschryver
Yes, I think so too.
I think it's good to keep the example code to a minimum, as it can help people like me who are just starting out.

@ssi02014
Copy link
Contributor Author

ssi02014 commented Jul 28, 2023

@timdeschryver @ph-fritsche
I modified the click example code to make it a bit simpler.

@@ -55,6 +94,37 @@ hover(element: Element): Promise<void>
pointer({target: element})
```

```js
const TestComponent = () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I'm being a pain, but I think it would be better to revert this to the previous example.
The reason for this is to be framework/library-agnostic, this is now a react example.
I can't think of any other test for now 😅

The rest of the changes are looking good! Thanks for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@timdeschryver
That's fine, thanks for your review.
I reverted to the previous code. 🙏

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I was not being clear on what I meant.
The test for hover can be reverted to use toHaveStyle.

The rest of the tests were good how they were, but I see that onChange was added back (which was not the intention.

Copy link
Contributor Author

@ssi02014 ssi02014 Jul 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@timdeschryver
I understood you to remove the "hover/unhover" example code, is that correct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, I can't find it the full snippet anymore because the commits are overwritten with the force push.
But I meant the initial example that was using toHaveStyle, or was this example always using a react component?

From our earlier conversation:

expect(hoverBox).toHaveStyle({backgroundColor: 'red'})

Copy link
Contributor Author

@ssi02014 ssi02014 Jul 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expect(hoverBox).toHaveStyle({backgroundColor: 'red'})

@timdeschryver
I apologize for the confusion caused by the force push.
This example also uses a React Component.

const TestComponent = () => {
  const [isHover, setIsHover] = useState(false)
  
  return (
    <div
      style={{ backgroundColor: isHover ? 'red' : 'green' }}
      onMouseEnter={() => setIsHover(true)}
      onMouseLeave={() => setIsHover(false)}
    >
      Hover
    </div>
  )
}

test('hover/unhover', async () => {
  const user = userEvent.setup()
  render(<TestComponent />)

  const hoverBox = screen.getByText('Hover')

  await user.hover(hoverBox)

  expect(hoverBox).toHaveStyle({ backgroundColor: 'red' })

  await user.unhover(hoverBox)

  expect(hoverBox).toHaveStyle({ backgroundColor: 'green' })
})

Copy link
Contributor Author

@ssi02014 ssi02014 Jul 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@timdeschryver
What about an example like this?
This is a test code for "hover/unhover" without using any React code.

test('hover/unhover', async () => {
  const user = userEvent.setup()
  render(<div>Hover</div>)

  const hoverBox = screen.getByText('Hover')
  let isHover = false
  
  hoverBox.addEventListener('mouseover', () => {
    isHover = true
  })
  hoverBox.addEventListener('mouseout', () => {
    isHover = false
  })
  
  expect(isHover).toBeFalsy()

  await user.hover(hoverBox)

  expect(isHover).toBeTruthy()

  await user.unhover(hoverBox)

  expect(isHover).toBeFalsy()
})

스크린샷 2023-08-01 오전 3 22 01

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my bad!
I'm fine with the second example using the event listener.
Thanks for following up!

@ssi02014 ssi02014 force-pushed the userEvent/convenience branch from 43a8a03 to e50aa8c Compare July 31, 2023 15:48
@ssi02014
Copy link
Contributor Author

@timdeschryver
After thinking about it, I think it would be better to leave onChange for click, double click, and triple click and check how many times the onChange function has been called.

This would make the example code clearer as to whether it was a click, double click, or triple click.

"expect(checkbox).toBeChecked()" is not enough.

@timdeschryver
Copy link
Member

@timdeschryver After thinking about it, I think it would be better to leave onChange for click, double click, and triple click and check how many times the onChange function has been called.

This would make the example code clearer as to whether it was a click, double click, or triple click.

"expect(checkbox).toBeChecked()" is not enough.

I haven't thought about that, good catch 👍

@ssi02014
Copy link
Contributor Author

ssi02014 commented Jul 31, 2023

@timdeschryver
I have modified the code again.
Thanks again for your detailed review.

스크린샷 2023-08-01 오전 4 16 43

@timdeschryver timdeschryver merged commit e618938 into testing-library:main Aug 25, 2023
@timdeschryver
Copy link
Member

@all-contributors please add @ssi02014 for docs

@allcontributors
Copy link
Contributor

@timdeschryver

I've put up a pull request to add @ssi02014! 🎉

@ssi02014 ssi02014 deleted the userEvent/convenience branch August 25, 2023 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants