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

Enzyme not unmounting by itslef #911

Closed
hakunin opened this issue Apr 21, 2017 · 12 comments
Closed

Enzyme not unmounting by itslef #911

hakunin opened this issue Apr 21, 2017 · 12 comments

Comments

@hakunin
Copy link

hakunin commented Apr 21, 2017

Hi, I noticed that Enzyme doesn't unmount the components I mounted after each test.
In my case, they will listen and react to stuff, thus the test gets slower and slower.

Are we supposed to do it manually?
I'd expect a high level library like Enzyme to unmount everything at the end of each test.

Without unmounting:
screenshot 2017-04-21 14 47 56

With unmounting its plenty fast but I get errors from the unmount code
screenshot 2017-04-21 14 53 36

I tried clearing the timers in the afterEach() function where I try to unmount but it didn't help. Any ideas?

@ljharb
Copy link
Member

ljharb commented Apr 21, 2017

Yes, you're supposed to do it manually.

It would be impossible for enzyme to know when your test is over, or even that you're writing a test at all.

Your component probably needs to clean up after itself in componentWillUnmount.

@hakunin
Copy link
Author

hakunin commented Apr 21, 2017

It would be impossible for enzyme to know when your test is over

How about afterEach? Does that not mean the test is over?

@ljharb
Copy link
Member

ljharb commented Apr 21, 2017

It is impossible for enzyme to know that any of its code is running in an afterEach, for example. Obviously your test is over inside the afterEach, but only you know that - not enzyme.

@hakunin
Copy link
Author

hakunin commented Apr 21, 2017

I don't follow. Are you saying Enzyme can't add afterEach callback that would cleanup the mounted components?

@ljharb
Copy link
Member

ljharb commented Apr 21, 2017

Yes, because enzyme doesn't know you're using mocha, or any other test framework. afterEach doesn't exist in every test framework, it exists in the one you chose to use.

@hakunin
Copy link
Author

hakunin commented Apr 21, 2017

then a simple enzyme.cleanup() in a global afterAll hook would still work, or even something like enzyme.init(jest), but I will simply create a wrapper myself :) thanks for explaining it

@hakunin hakunin closed this as completed Apr 21, 2017
@ljharb
Copy link
Member

ljharb commented Apr 21, 2017

Indeed, something that would be useful for you here would be a wrapper that kept in memory every enzyme wrapper that was ever created, and provided an unmount/cleanup method to clean them all up, so you could call that in afterEach.

That belongs in a separate enzyme wrapper package, but would be very useful.

@silvenon
Copy link
Contributor

Material UI solved it like this (source).

@jackgeek
Copy link

I think this really belongs in the enzyme library. Its not immediately clear that you have to clean up. If there was a documented enzyme.cleanup() that would be very useful.

uyhcire added a commit to uyhcire/tabliner that referenced this issue Jun 4, 2019
A test in `TabTree.test.tsx` was failing when the whole test file was run, but it succeeded when running by itself. I suspected it was triggering an event listener that was left over from a previous test. That turned out to be right - this commit fixes the test by making sure event listeners are cleaned up.

To make sure listeners are cleaned up, I needed to make sure all components are unmounted after each test. Enzyme does not unmount components (enzymejs/enzyme#911), so I had to write a wrapper to help unmount everything.

The wrapper is a `safeMount` method that adds all mounted components to a global list. The global `afterEach` in `setupTests.ts` then unmounts all components after each test.

To prevent myself from accidentally using the unwrapped `mount` in the future, I also added a custom lint rule that detects `mount` calls.
@cgood92
Copy link

cgood92 commented Oct 21, 2019

I came across this unfortunate news today, and I have implemented a solution that seems to be working for me. I will post it here, and I would love feedback.

jest-setup.js

import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import reactDOM from 'react-dom'

const attachTo = global.document.createElement('div')

class ReactAdapterWithMountTracking extends Adapter {
	constructor(...args) {
		super(...args)
	}
	createRenderer(options){
		// Provide a default option on each render for attachTo, being a global div that we can unmount later
		Object.assign(options, { attachTo: options.attachTo || attachTo })
		return Adapter.prototype.createRenderer.call(this, options)
	}
}

afterEach(() => {
	// Unmount react component after each test
	reactDOM.unmountComponentAtNode(attachTo)
})

configure({ adapter: new ReactAdapterWithMountTracking() })

@cgood92
Copy link

cgood92 commented Oct 22, 2019

I made this into an NPM package for easy consumption. Now you can do the following:

npm i -d eynzme-cleanup 

And add this to your jest setup script (where you set up your enzyme adapter)

import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import { cleanup, makeAdapter } from 'enzyme-cleanup'

afterEach(cleanup)

configure({ adapter: makeAdapter(Adapter) })

@jackgeek

This comment has been minimized.

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

No branches or pull requests

5 participants