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

feat(wait): wait will now also run your callback on DOM changes #415

Merged
merged 7 commits into from
Mar 4, 2020

Conversation

kentcdodds
Copy link
Member

@kentcdodds kentcdodds commented Dec 13, 2019

What: Make wait use a MutationObserver in addition to the previous behavior

Why: This way we can get rid of waitForDomChange (in a future release) and we drastically simplify the other async utilities. wait also gets a super-power of being able to re-run the callback faster than the interval when the DOM is changed, so this should speed up people's tests who are using wait today. Closes #376

How: Remove wait-for-expect (cc @lgandecki) because it wont work nicely with this approach. I also refactored the other utilities to build on top of wait (which is something I've wanted to do for a long time now).

Checklist:

  • Documentation added to the docs site
  • I've prepared a PR for types targeting DefinitelyTyped (this should not be necessary. No APIs have changed)
  • Tests
  • Ready to be merged
  • Set lower timeout default

@codesandbox-ci
Copy link

codesandbox-ci bot commented Dec 13, 2019

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit a00cc96:

Sandbox Source
long-rgb-gxwp3 Configuration

@@ -1,71 +1,21 @@
import {
Copy link
Member Author

Choose a reason for hiding this comment

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

@@ -1,85 +1,48 @@
import {
Copy link
Member Author

Choose a reason for hiding this comment

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

@kentcdodds kentcdodds force-pushed the pr/wait-improvements branch 3 times, most recently from b2619b6 to 2ceb1a0 Compare December 13, 2019 18:34
@kentcdodds
Copy link
Member Author

That's weird. I think the codesandbox thing is a fluke.

@mwmcode
Copy link

mwmcode commented Dec 15, 2019

Hi Kent,

I was gonna post a suggestion/PR, but since this one is about wait, I will just leave it here:

Can we expose wait under a second alias: until or till? I think the code would read nicer:

  await till(() => expect(MockRedirect).toHaveBeenCalledWith({to: '/'}, {}));

I know we can alias our imports.. just thought the API would look nicer.. though it might not be worth introducing new API changes (at this time)

Cheers,

@kentcdodds
Copy link
Member Author

Hi @mustafawm, thanks for the feedback. I do prefer to avoid aliases when possible. We have an alias for getQueriesForElement (it's within), but I'm not a super-fan of it. The reason I made the alias was because I thought the function name was kinda long, but I didn't want to make a breaking change to rename it.

I'm not sure there's enough justification to alias this function, but you certainly could do this in your own utils module.

Good luck!

@mwmcode
Copy link

mwmcode commented Dec 15, 2019

Hey Ken, thanks for your quick reply.

Agree. tbh, I wasn't feeling strongly about it .. just thought I put it out there and see :)

Thanks for the utils module suggestion 🙏

@lgandecki
Copy link
Collaborator

Hey Kent,

Thanks for pinging me here and letting me know - it will be bittersweet to see the installs of wait-for-expect plummet but it's for a good reason - the tiny helper is usable on it's own outside of dom-testing scope so we shouldn't be adding more complexity to it, and the dom-testing could use some improvements.. :)

I also like the idea of simplifying the API. To be honest in a lot of projects I've seen and helped with, people didn't even bother to use waitForDomChange, wait "just worked". Optimizations (savings of maybe a few dozens of ms per test) were not worth the extra pause (and learning) to decide which of the wait* tools the programmer should use in a given situation.

I'm glad that the initial design we've came up with lives on. It's so intuitive and clean. My only regret is the default long timeout - I was basing it off what I knew from browser-based testing (selenium, chimp, cypress, etc). But in more of a low-level environment the timeout hardly ever needs to go that high, with the downside that once things break the tests take forever to fail. (In browser-based testing the test would maybe take 8 seconds to fail instead of 4 seconds to pass, but in integration we can jump from 100 ms to 4500 ms which is much more annoying). It brakes the flow. It might be worth pointing this out more explicitly in the docs, that people might want to consider to change the default, if they run lightweight tests. But, at the same time, this family of libraries is all based on "smart defaults" :)

Also - if you are going to do some breaking changes, this might be something to rethink, maybe?

afontcu
afontcu previously approved these changes Dec 15, 2019
Copy link
Member

@afontcu afontcu left a comment

Choose a reason for hiding this comment

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

Looks like a sensible change! Not only we remove a dependency, we also set the stage to simplify the exposed API in a future major version.

I've added a few comments here and there, but looks great overall 👍

// As the name implies, waitForElementToBeRemoved should check `present` --> `removed`
if (isRemoved(callback())) {
throw new Error(
'The callback function which was passed did not return an element or non-empty array of elements. waitForElementToBeRemoved requires that the element(s) exist before waiting for removal.',
Copy link
Member

Choose a reason for hiding this comment

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

nitpicking ^^ sry about that

Suggested change
'The callback function which was passed did not return an element or non-empty array of elements. waitForElementToBeRemoved requires that the element(s) exist before waiting for removal.',
'The callback function which was passed did not return an element or non-empty array of elements. waitForElementToBeRemoved requires that the element(s) exist(s) before waiting for removal.',

src/wait.js Show resolved Hide resolved
@kentcdodds
Copy link
Member Author

Maybe we should change the default timeout as part of this change as well. I think it makes more sense for it to be ~1 second. If someone's test is taking longer than that for a single wait then they probably aren't mocking something they should be (in the context of Cypress and other E2E situations, we could change the default for those environments).

What do folks think about that?

@kentcdodds kentcdodds added the BREAKING CHANGE This change will require a major version bump label Jan 21, 2020
@afontcu
Copy link
Member

afontcu commented Jan 21, 2020

+1 at setting a lower default value for the timeout – I've never found a case where a 4.5s timeout would make a (well-written and properly mocked) test pass while a lower one would make the same test fail.

I'm ok with 1s.

@kentcdodds
Copy link
Member Author

Rebased master and added two commits. If folks could take a look at the last two commits that would be super duper. Thanks!

@codecov
Copy link

codecov bot commented Mar 3, 2020

Codecov Report

Merging #415 into beta will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@         Coverage Diff         @@
##           beta   #415   +/-   ##
===================================
  Coverage   100%   100%           
===================================
  Files        22     22           
  Lines       404    412    +8     
  Branches     95     99    +4     
===================================
+ Hits        404    412    +8
Impacted Files Coverage Δ
src/pretty-dom.js 100% <ø> (ø) ⬆️
src/role-helpers.js 100% <ø> (ø) ⬆️
src/wait.js 100% <100%> (ø) ⬆️
src/config.js 100% <100%> (ø) ⬆️
src/wait-for-dom-change.js 100% <100%> (ø) ⬆️
src/wait-for-element.js 100% <100%> (ø) ⬆️
src/wait-for-element-to-be-removed.js 100% <100%> (ø) ⬆️
src/queries/label-text.js 100% <0%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6084f53...a00cc96. Read the comment docs.

Comment on lines -6 to +8
asyncUtilTimeout: 4500,
asyncUtilTimeout: 1000,
Copy link
Member Author

Choose a reason for hiding this comment

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

Just realized I amended the first of those two changes. So this is all that first change was.

Comment on lines +11 to +15
// deprecated... TODO: remove this method. People should use wait instead
// the reasoning is that waiting for just any DOM change is an implementation
// detail. People should be waiting for a specific thing to change.
Copy link
Member

Choose a reason for hiding this comment

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

If we plan to remove this method in the next major release, should be add a warning so people know they are relying on a soon-to-be-gone method? Is it too invasive?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm kinda thinking that we should add the warning in the major version bump, and then remove it in the next one.

@kentcdodds kentcdodds changed the base branch from master to next March 4, 2020 16:59
@kentcdodds
Copy link
Member Author

I'm starting to think that instead of deprecating we should just remove it entirely what do people think?

To be clear, I'm talking about waitForDomChange and waitForElement.

waitForElement can be done really easily with wait and waitForDomChange is testing implementation details (and can be done really easily with wait as well.

Thoughts?

@kentcdodds
Copy link
Member Author

Changed my mind. We'll just have a deprecation warning for this release. People will be less mad at us 😅

@kentcdodds kentcdodds merged commit 5aa6386 into beta Mar 4, 2020
@kentcdodds kentcdodds deleted the pr/wait-improvements branch March 4, 2020 17:58
@kentcdodds
Copy link
Member Author

🎉 This PR is included in version 7.0.0-beta.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

kentcdodds pushed a commit that referenced this pull request Mar 4, 2020
Closes #376
Closes #416

BREAKING CHANGE: `waitForElement` is deprecated in favor of `find*` queries or `wait`.
BREAKING CHANGE: `waitForDomChange` is deprecated in favor of `wait`
BREAKING CHANGE: default timeout for async utilities is now 1000ms rather than 4500ms. This can be configured: https://testing-library.com/docs/dom-testing-library/api-configuration
kentcdodds pushed a commit that referenced this pull request Mar 4, 2020
Closes #376
Closes #416

BREAKING CHANGE: `waitForElement` is deprecated in favor of `find*` queries or `wait`.
BREAKING CHANGE: `waitForDomChange` is deprecated in favor of `wait`
BREAKING CHANGE: default timeout for async utilities is now 1000ms rather than 4500ms. This can be configured: https://testing-library.com/docs/dom-testing-library/api-configuration
@kentcdodds kentcdodds restored the pr/wait-improvements branch March 12, 2020 21:31
@kentcdodds kentcdodds deleted the pr/wait-improvements branch March 12, 2020 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BREAKING CHANGE This change will require a major version bump released on @beta
Projects
None yet
Development

Successfully merging this pull request may close these issues.

BREAKING: make waitForDomChange accept a callback
5 participants