Skip to content
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

add no-unnecessary-act rule #259

Closed
kentcdodds opened this issue Nov 23, 2020 · 14 comments · Fixed by #365
Closed

add no-unnecessary-act rule #259

kentcdodds opened this issue Nov 23, 2020 · 14 comments · Fixed by #365
Assignees
Labels
new rule New rule to be included in the plugin released

Comments

@kentcdodds
Copy link
Member

kentcdodds commented Nov 23, 2020

We should warn against the use of act unnecessarily:

import {screen, fireEvent, render, act} from '@testing-library/react'
import userEvent from '@testing-library/user-event`
import ReactTestUtils from 'react-dom/test-utils'

// ReactTestUtils.act should be treated exactly the same as `act` from `@testing-library/react`

// these are ALL wrong:
act(() => fireEvent.click(el))
act(() => screen.getByText('blah'))
act(() => userEvent.click(el))
await act(async () => userEvent.type('hi', el))
act(() => render(<div />))
await act(async () => render(<div />))
await act(async () => {})
act(() => {})

// this one's fine:
act(() => {
  stuffThatDoesNotUseRTL()
})

// actually, so is this one
act(() => {
  fireEvent.click(el)
  stuffThatDoesNotUseRTL()
})

So basically the rule is: "You should only wrap non-testing-library function calls in act"

Reading material: https://kcd.im/react-act

@Belco90 Belco90 added the new rule New rule to be included in the plugin label Nov 23, 2020
@Belco90
Copy link
Member

Belco90 commented Nov 23, 2020

Hi @kentcdodds, thanks for the proposal! This would be tricky to implement on current v3 where we have some issues to detect testing-library related things. However, we got a new detection mechanism on v4 (still in progress) which will be perfect for implementing this one. I think we will include it in a possible v4.1 or maybe within v4 depending on how we are progressing with last bits of v4.

If someone wants to take care of this one meanwhile, please do it by branching off v4.

Thanks.

@Belco90
Copy link
Member

Belco90 commented Nov 24, 2020

Hi again @kentcdodds. In the twitter thread were you explained this behavior you mentioned that "warning would go away just as well if you added await act(async () => {}) on the next line" so I guess that would be another invalid case, wouldn't be?

@kentcdodds
Copy link
Member Author

Yes! An empty act(() => {}) or await act(async () => {}) should also be invalid 👍

@alessbell
Copy link
Contributor

👋 I can pick this one up and branch off of v4 to get started if no one else has yet @Belco90

@Belco90
Copy link
Member

Belco90 commented Dec 2, 2020

@alessbell That would be awesome! I don't think anyone has started it yet. I'm busy migrating current rules to v4 (you can see progress on #198 ) so didn't have time to even think about this one.

We haven't updated the contributing guidelines yet for v4, but some guidance around it:

  • there is a new detection mechanism on v4 which injects a 3rd argument to every rule create method. You can take advantage of that to detect if something is related to testing library or not
  • even if we have those new helpers for detecting things, you might need something which doesn't exist yet. If so, feel free to add new helper to detection mechanism
  • for this rule you can use isNodeComingFromTestingLibrary helper which will automatically tell you if a particular node comes from something related to testing library or not!
  • I don't think we need to check if act is coming from testing library or ReactTestUtils and just assume every act call we find has to be reported if wrapping something coming from testing library

Let me know if you have any question around v4 or you don't know how to proceed with something! Sorry we don't have the guidelines updated yet, but I think the detection method and helpers are well documented.

@Belco90 Belco90 added this to the v4 milestone Dec 2, 2020
@Belco90
Copy link
Member

Belco90 commented Dec 6, 2020

Hey @alessbell just FYI: I've merged #263 into v4 branch, and I created #265 pointing to v4 too. The former shouldn't affect you directly, but the latter includes some refactors within isNodeComingFromTestingLibrary. It should work in the same way (even covering more edge cases), but just to let you know about it in case you were modifying that util too!

@zaicevas
Copy link
Contributor

Hey @alessbell how are things going with this task? Are there any blockers?

@alessbell
Copy link
Contributor

Thanks for bumping this thread @tozaicevas -- I have an in-progress branch I've just rebased off of the latest v4 and should be able to clean it up this evening 👍 Will open a PR shortly.

@Belco90
Copy link
Member

Belco90 commented Mar 15, 2021

@alessbell thanks for the update! I created a PR yesterday to move the CI to GitHub Actions. I'll merge it later today, and try to get it updated properly on v4 so we can have proper CI in place for your upcoming PR and current ones open for v4.

Also, I've updated tons of things on v4 since my last update here. Feel free to ping me in you need help or just want to know more about it.

Looking forward to your PR, thanks for your work :)

@Belco90
Copy link
Member

Belco90 commented Mar 17, 2021

@alessbell forgot to mention it, but the new CI is already moved to GitHub Actions in both main and v4 branches ✨

@Belco90
Copy link
Member

Belco90 commented Mar 20, 2021

Hey @kentcdodds! One question about your original description of the behavior:

act(() => {
  fireEvent.click(el)
  stuffThatDoesNotUseRTL()
})

You said in the description this should be a valid usage of act, are we sure about it? I thought this should be an invalid example since fireEvent is a Testing Library util, so previous example should be reported until all Testing Library utils are extracted outside the act like:

fireEvent.click(el)
act(() => {
  stuffThatDoesNotUseRTL()
})

@kentcdodds
Copy link
Member Author

It would be valid I think because it will make sure that effects aren't flushed between the fireEvent and the stuffThatDoesNotUseRTL. I can't really think of a situation where you'd want that, but a situation like that probably exists.

@MichaelDeBoey MichaelDeBoey removed this from the v4 milestone Apr 15, 2021
@Belco90
Copy link
Member

Belco90 commented Apr 20, 2021

Hey hey! Since v4 was officially released and the first round of improvements after that was handled too, I have time for implementing other rules like this one. @alessbell will hand her current progress over to me so I can finish it.

@Belco90 Belco90 self-assigned this Apr 22, 2021
Belco90 added a commit that referenced this issue May 11, 2021
* refactor: rename function to detect potential Testing Library func

* feat(no-unnecessary-act): first approach for the rule

* feat(no-unnecessary-act): first bunch of tests

* test: update number of expected rules

* feat(no-unnecessary-act): detect error from returns

* refactor: extract util to determine if a function is empty

* feat(no-unnecessary-act): detect error for empty callbacks

* refactor(no-unnecessary-act): function to find non-testing-library calls

* refactor(no-unnecessary-act): update docs recommended config

* fix: check if node is coming from Testing Library correctly

isNodeComingFromTestingLibrary wasn't checking if the imported
declaration name matches some Testing Library valid module

* feat: save react-dom/test-utils import in detection mechanism

* refactor: extract function for finding import specifier

* refactor(no-unnecessary-act): detect act from React DOM test utils

* fix: remove duplicated isVariableDeclaration declaration

* feat(no-unnecessary-act): detect edge and mixed cases

* docs(no-unnecessary-act): add rule details

* docs(no-unnecessary-act): include rule in README

* refactor: rename findImportedTestingLibraryUtilSpecifier in helpers

* docs(no-unnecessary-act): simplify examples

* refactor: remove unnecessary comment

* fix(no-unnecessary-act): cover more trees searching for statements

* test(no-unnecessary-act): extra cases for thenable promises

Closes #259

Co-authored-by: @alessbell
@github-actions
Copy link

🎉 This issue has been resolved in version 4.3.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new rule New rule to be included in the plugin released
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants