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

Deprecate renderIntoDocument() #116

Closed
hnordt opened this issue Jun 15, 2018 · 19 comments
Closed

Deprecate renderIntoDocument() #116

hnordt opened this issue Jun 15, 2018 · 19 comments
Labels
needs discussion Whether changes are needed is still undecided and additional discussion is needed.

Comments

@hnordt
Copy link

hnordt commented Jun 15, 2018

The fundamental (and great) aspect of this library is:

The more your tests resemble the way your software is used, the more confidence they can give you.

I've watched all your talks and you keep saying that Simulate is a bad idea (even Dan Abramov told us that, if I'm not wrong) and I really agree with you!

We all want to make testing easier, and the only confusing thing that I see in this great library is having two render methods.

My suggestion is that we just deprecate renderIntoDocument() and move renderIntoDocument()'s behavior to render().

I don't see any reason to use render() over renderIntoDocument().

@kentcdodds
Copy link
Member

Thanks for bringing this up. As soon as this is done then I will be willing to do that. Until then, we have to have the cleanup method and I think that would be annoying/confusing as well. I'm happy to hear other's thoughts on the matter though.

@hnordt
Copy link
Author

hnordt commented Jun 15, 2018

We could encourage people to have a beforeEach that cleans things up, but that'd be annoying and reduce the simplicity.

I think having a beforeEach(cleanup) is a lot simpler than having both render(), renderIntoDocument() and Simulate. Also we need to explain when to use element.click() over Simulate.click() and explain why element.click() or element.focus() can't be used if render() is being used.

Other than that, we can't really trust Simulate, so the additional beforeEach(cleanup) effort would be fine as the trade-off would be increasing confidence.

For me, cleanup is part of the testing process. To make things more clear we could rename cleanup() to removeRenderedContainerFromDocument() or something like that.

Another approach:

test(() => {
  const { destroy } = render()
  // ...
  destroy()
})

@kentcdodds
Copy link
Member

You make good points. And honestly, many people have a testSetup file where they they could do this repetitive work and reduce that friction.

@hnordt
Copy link
Author

hnordt commented Jun 15, 2018

Yeah, we could import something like react-testing-library/auto-cleanup in setupTests.js.

@kentcdodds
Copy link
Member

What if we did it automatically 🤔 Like put this at the top of our main file:

if (typeof beforeEach !== undefined) {
  beforeEach(cleanup)
}

Hmmmm..... Why would that be bad?

@hnordt
Copy link
Author

hnordt commented Jun 15, 2018

The only problem I see is that then importing the library would cause a side effect, which is a bad thing.

@hnordt
Copy link
Author

hnordt commented Jun 15, 2018

We could change a bit the render() usage:

test('sync test', () => {
  render(<Login />, ({ getByLabelText }) => {
    getByLabelText('username')
    getByLabelText('username').value = 'chucknorris'
  })
})

test('async test', () => {
  render(<Login />, async ({ getByLabelText }) => {
    await wait(() => getByLabelText('username'))
    getByLabelText('username').value = 'chucknorris'
  })
})

The implementation:

const render = async (..., callback) => {
  const publicAPI = ...
  await callback(publicAPI)
  
  document.body.removeChild(container)
  ReactDOM.unmountComponentAtNode(container)
}

The nice thing about this approach is that it matches the ReactDOM.render() API:

ReactDOM.render(element, container[, callback])

So we would have:

ReactTesting.render(element[, container], callback)

or

ReactTesting.render(element, callback[, options = { container, baseElement }])

@kentcdodds
Copy link
Member

Thanks for the ideas! I'm not sure that makes things any simpler. I feel like it would be a step backward.

The only problem I see is that then importing the library would cause a side effect, which is a bad thing.

I can understand that perspective. The side-effect is basically unobservable though so I think it'd probably be ok, but I wont push it.

I think I'm in favor of just deprecating renderIntoDocument and putting its logic into render as you originally suggested. Then we'd just tell people to make sure to have a beforeEach(cleanup) configured. We could also expose a module as you suggested. So people could do:

import 'react-testing-library/cleanup'
import {render} from 'react-testing-library'

I don't think that's too much to ask.

We could also re-export everything from cleanup:

import {render} from 'react-testing-library/cleanup'

Thoughts?

@hnordt
Copy link
Author

hnordt commented Jun 15, 2018

For me the best approach would be suggesting the users to import react-testing-library/cleanup on their global test setup script or import it on every test if they don't have a global test setup script.

Also if they call render() and we didn't detect that cleanup() was called we could throw an error.

import {render} from 'react-testing-library/cleanup'

I like the simplicity of it and I dislike that it's not very semantic. But I'm not opposed to it, I don't see any other problems than the semantic issue.

@kentcdodds
Copy link
Member

I agree with what you said! Though

Also if they call render() and we didn't detect that cleanup() was called we could throw an error.

How do you propose we do that?

@kentcdodds kentcdodds added the needs discussion Whether changes are needed is still undecided and additional discussion is needed. label Jun 15, 2018
@hnordt
Copy link
Author

hnordt commented Jun 15, 2018

Hum...

let willCleanup = false

function render() {
  if (!willCleanup) throw new Error(`You forgot to import "react-testing-library/cleanup"!`)
  // ...
}

function cleanup() {
  // ...
  willCleanup = true
}

It would work?

@kentcdodds
Copy link
Member

Unfortunately not. It's totally valid to call render multiple times before a cleanup

@hnordt
Copy link
Author

hnordt commented Jun 15, 2018

Yes, but import 'react-testing-library/cleanup' is a side effect, so it would run before the test itself.

@hnordt
Copy link
Author

hnordt commented Jun 15, 2018

Ahh... My code is wrong, what I really want is that importing react-testing-library/cleanup sets willCleanup to true.

@hnordt
Copy link
Author

hnordt commented Jun 15, 2018

What about:

// index.js

let willCleanup = false

function render() {
  if (!willCleanup) throw new Error(`You forgot to import "react-testing-library/cleanup"!`)
  // ...
}

// or setupCleanup, I don't know the best name
function configureCleanup(beforeEach) {
  if (beforeEach !== undefined) {
    beforeEach(cleanup)
    willCleanup = true
  }
}

export { render, configureCleanup, ... }

// cleanup.js

import { configureCleanup } from "./"

configureCleanup(beforeEach)

If beforeEach is not available, the user can import configureCleanup himself (instead of react-testing-library/cleanup) and pass the correct beforeEach fn.

@kentcdodds
Copy link
Member

Yes, but import 'react-testing-library/cleanup' is a side effect, so it would run before the test itself.

That's not a problem though. We just need to register an afterEach(cleanup) which shouldn't be a problem at all.

@kentcdodds
Copy link
Member

I'm thinking that what I want to do is start off without have a react-testing-library/cleanup file and just do as simple as possible. Remove Simulate, replace render with renderIntoDocument, and publish a breaking change. I think I'll work on this myself.

@hnordt
Copy link
Author

hnordt commented Jun 18, 2018

@kentcdodds sounds like a good plan.

kentcdodds pushed a commit that referenced this issue Jun 18, 2018
Closes #116

BREAKING CHANGE: `renderIntoDocument` replaces `render` and `Simulate` is no longer exported (use `fireEvent` instead).
kentcdodds pushed a commit that referenced this issue Jun 18, 2018
Closes #116

BREAKING CHANGE: `renderIntoDocument` replaces `render` and `Simulate` is no longer exported (use `fireEvent` instead).
kentcdodds pushed a commit that referenced this issue Jun 19, 2018
Closes #116

BREAKING CHANGE: `renderIntoDocument` replaces `render` and `Simulate` is no longer exported (use `fireEvent` instead).
kentcdodds pushed a commit that referenced this issue Jun 19, 2018
)

Closes #116

BREAKING CHANGE: `renderIntoDocument` replaces `render` and `Simulate` is no longer exported (use `fireEvent` instead).
@kentcdodds
Copy link
Member

🎉 This issue has been resolved in version 4.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

lucbpz pushed a commit to lucbpz/react-testing-library that referenced this issue Jul 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs discussion Whether changes are needed is still undecided and additional discussion is needed.
Projects
None yet
Development

No branches or pull requests

2 participants