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(render): deprecate renderIntoDocument and make it the default #118

Merged
merged 1 commit into from Jun 19, 2018

Conversation

kentcdodds
Copy link
Member

What: deprecate renderIntoDocument and make it the default

Why: Closes #116

How:

  • Code refactor
  • My son is waiting for me... Otherwise I'd be more informative.

Checklist:

  • Documentation
  • Tests
  • Ready to be merged
  • Added myself to contributors table N/A

cc @hnordt @sompylasar

@codecov
Copy link

codecov bot commented Jun 18, 2018

Codecov Report

Merging #118 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master   #118   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           1      1           
  Lines          17     18    +1     
  Branches        0      2    +2     
=====================================
+ Hits           17     18    +1
Impacted Files Coverage Δ
src/index.js 100% <100%> (ø) ⬆️

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 6f1ce48...777cfd3. Read the comment docs.

@hnordt
Copy link

hnordt commented Jun 18, 2018

The README needs to be updated. I can do it if you want.

@kentcdodds
Copy link
Member Author

What part? This PR makes major updates to the README.

@hnordt
Copy link

hnordt commented Jun 19, 2018

@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()`.
Copy link
Contributor

Choose a reason for hiding this comment

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

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
Copy link
Contributor

Choose a reason for hiding this comment

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

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
Copy link
Contributor

Choose a reason for hiding this comment

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

"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
Copy link
Contributor

Choose a reason for hiding this comment

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

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())
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. 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
  2. /loading.../i – the ... matches three arbitrary characters instead of the expected three ASCII dots, worth escaping?

// then ensure that there's a submit button.
Simulate.submit(formNode)
fireEvent.click(submitButtonNode)
Copy link
Contributor

Choose a reason for hiding this comment

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

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)
Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmmm... So what are you suggesting?

Copy link
Member Author

Choose a reason for hiding this comment

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

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Member Author

Choose a reason for hiding this comment

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

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmmmm..... I'm still not certain this is the behavior people would expect our want 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Member Author

Choose a reason for hiding this comment

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

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

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.

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 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.

@@ -46,15 +46,14 @@ export interface RenderResult extends GetsAndQueries {
debug: () => void
rerender: (ui: React.ReactElement<any>) => void
unmount: VoidFunction
cleanup: VoidFunction
Copy link
Contributor

Choose a reason for hiding this comment

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

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

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).
@kentcdodds
Copy link
Member Author

🎉 This PR is included in version 4.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@sompylasar
Copy link
Contributor

I saw you removed the cleanup: VoidFunction, but the unmount: VoidFunction is still there in the index.d.ts TypeScript definition file, without a visible definition of the VoidFunction type – where does this type come from?

@kentcdodds kentcdodds deleted the pr/render-only branch June 19, 2018 05:53
@kentcdodds
Copy link
Member Author

where does this type come from?

No idea 🤷‍♂️

@jomaxx
Copy link
Collaborator

jomaxx commented Jun 19, 2018

@kentcdodds this is amazing! happy to see renderIntoDocument become the default render

@antsmartian
Copy link
Collaborator

Wow this is great @kentcdodds ! 👍

julienw pushed a commit to julienw/react-testing-library that referenced this pull request Dec 20, 2018
* 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
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.

None yet

5 participants