feat(render): deprecate renderIntoDocument and make it the default#118
feat(render): deprecate renderIntoDocument and make it the default#118kentcdodds merged 1 commit intomasterfrom
Conversation
Codecov Report
@@ Coverage Diff @@
## master #118 +/- ##
=====================================
Coverage 100% 100%
=====================================
Files 1 1
Lines 17 18 +1
Branches 0 2 +2
=====================================
+ Hits 17 18 +1
Continue to review full report at Codecov.
|
|
The README needs to be updated. I can do it if you want. |
|
What part? This PR makes major updates to the README. |
|
@kentcdodds nevermind, it's there, I didn't see. |
README.md
Outdated
| option, it will not be appended to the `document.body` automatically. | ||
|
|
||
| **baseElement**: This is used as the base element for the queries as well as | ||
| what is printed when you use `debug()`. |
There was a problem hiding this comment.
Which one is the default for this baseElement?
README.md
Outdated
|
|
||
| renderIntoDocument(<div />) | ||
| ``` | ||
| > `getByText` don't work for your use case. Using data-testid attributes do not |
There was a problem hiding this comment.
Add backticks around data-testid on this line, too?
README.md
Outdated
|
|
||
| </details> | ||
| Failing to call `cleanup` when you've called `render` could result in a memory | ||
| leak and tests which are not `idempotent` (which can lead to difficult to debug |
There was a problem hiding this comment.
"idempotent" is not a code identifier, use regular quotes instead of backticks here?
README.md
Outdated
| > to attach event handlers to the rendered node rather than the `document`. | ||
| > Learn more here: | ||
| > NOTE: If you don't like having to use `cleanup` (which we have to do because | ||
| > we render into document.body) to get `fireEvent` working, then feel free to |
There was a problem hiding this comment.
add backticks around document.body
README.md
Outdated
|
|
||
| // wait until the callback does not throw an error. In this case, that means | ||
| // it'll wait until we can get a form control with a label that matches "username" | ||
| await wait(() => expect(queryByText(/loading.../i).not.toBeInTheDOM()) |
There was a problem hiding this comment.
- it'll wait until we can get a form control with a label that matches "username" does not sound aligned with the code it comments: it actually waits for "loading..." to disappear from the DOM, and only after that we look for the form control on the next line
/loading.../i– the...matches three arbitrary characters instead of the expected three ASCII dots, worth escaping?
| // So the next best thing is to fire a submit on the form itself | ||
| // then ensure that there's a submit button. | ||
| Simulate.submit(formNode) | ||
| fireEvent.click(submitButtonNode) |
There was a problem hiding this comment.
According to the NOTE comment above, clicking on the submit button won't work in jsdom. Does fireEvent.click take care of that?
| // maybe one day we'll expose this (perhaps even as a utility returned by render). | ||
| // but let's wait until someone asks for it. | ||
| function cleanupAtContainer(container) { | ||
| document.body.removeChild(container) |
There was a problem hiding this comment.
If container is custom passed by the caller, thus not appended to the document.body by render, the caller may not expect that it will be removed by cleanup which should be a mirror to render.
There was a problem hiding this comment.
Hmmm... So what are you suggesting?
There was a problem hiding this comment.
Oh, I see what you mean. I'm not sure how to solve that issue reliably. If they don't like the behavior then they can file an issue and we can add an option to prevent this. Let's wait to add complexity until someone has an issue.
There was a problem hiding this comment.
Usually if a piece of code owns the lifecycle of an object (the caller in the case of custom container; the module with the render function in the case of default container), that piece is responsible for both creation+setup and teardown+destruction.
The suggestion is to make sure not to remove the container from the DOM if it hasn't been added to the DOM by the render module, only remove the map entry (lifecycle of which is owned by the render module) and ReactDOM.unmountComponentAtNode (which is a mirror to ReactDOM.render, mounted component's lifecycle is also owned by the render module).
I understand that the object/memory ownership and the allocate/deallocate pattern is often missed/violated in the JavaScript community due to various reasons, so it may look odd to require following it from this library users.
There was a problem hiding this comment.
That makes sense. Perhaps we should not add items to the set if we don't append it to the body. Would you like to open a PR for that?
There was a problem hiding this comment.
Hmmmm..... I'm still not certain this is the behavior people would expect our want 🤔
There was a problem hiding this comment.
Okay then, let's assume people move the ownership of the container from their code to the library code by calling render with that container.
There was a problem hiding this comment.
What if instead we did:
container.parentElement && container.parentElement.removeChild(container)I think that would make sense to happen in the cleanup regardless of whether it's in the body or not.
There was a problem hiding this comment.
That would make sense to shorten the caller code to let it manage only container creation, and, my point still holds, the ownership of the container object lifecycle is moved from the caller into the render function.
There was a problem hiding this comment.
I'm a little confused by what you're suggesting. But why don't you make a PR and maybe that'll clear things up for me.
typings/index.d.ts
Outdated
| debug: () => void | ||
| rerender: (ui: React.ReactElement<any>) => void | ||
| unmount: VoidFunction | ||
| cleanup: VoidFunction |
There was a problem hiding this comment.
Is this an established practice to have a single type definition for functions with different purposes? I would avoid sharing the type because these functions, although look similar, are not the same thing. For example, debug looks like a VoidFunction but the type is not shared. Oh by the way, I don't see a definition of VoidFunction in this file, where is it coming from?
There was a problem hiding this comment.
This was a mistake on my part. Originally I had added a helper cleanup utility, then thought better of it because nobody's asking for that additional helper and not enough people would use it to be worth the docs.
Closes #116 BREAKING CHANGE: `renderIntoDocument` replaces `render` and `Simulate` is no longer exported (use `fireEvent` instead).
bb61e94 to
777cfd3
Compare
|
🎉 This PR is included in version 4.0.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
|
I saw you removed the |
No idea 🤷♂️ |
|
@kentcdodds this is amazing! happy to see |
|
Wow this is great @kentcdodds ! 👍 |
* waitForDomChange is implemented along with tests, documentation, and types. * Implements changes requested on 10-9-18. Removes matchSnapshots. Correctly formats README.md. Changes Promise to return a mutationsList. Adds documentation for mutationsList. * causes waitForElement to throw an error if callback is not defined. changes tests to account for new behavior. removes the documentation around the default callback. adds MutationObserver documentation for waitForDomChange
What: deprecate renderIntoDocument and make it the default
Why: Closes #116
How:
Checklist:
cc @hnordt @sompylasar