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

Unmount is not working as described in the docs #785

Open
lematt1991 opened this issue Jan 23, 2017 · 5 comments
Open

Unmount is not working as described in the docs #785

lematt1991 opened this issue Jan 23, 2017 · 5 comments
Assignees

Comments

@lematt1991
Copy link

I was experiencing some unintuitive behavior from unmount. I took the example from the docs:

it('Calls componentWillUnmount after unmount', () => {
    const willMount = sinon.spy();
    const didMount = sinon.spy();
    const willUnmount = sinon.spy();

    class Foo extends React.Component {
      constructor(props) {
        super(props);
        this.componentWillUnmount = willUnmount;
        this.componentWillMount = willMount;
        this.componentDidMount = didMount;
      }
      render() {
        return (
          <div className={this.props.id}>
            {this.props.id}
          </div>
        );
      }
    }
    const wrapper = mount(<Foo id="foo" />);
    expect(willMount.callCount).toEqual(1);
    expect(didMount.callCount).toEqual(1);
    expect(willUnmount.callCount).toEqual(0);
    wrapper.unmount();
    expect(willMount.callCount).toEqual(1);
    expect(didMount.callCount).toEqual(1);
    expect(willUnmount.callCount).toEqual(1);
  })

And got the following result:

  ● <SurveyEditor/> › Test

    expect(received).toEqual(expected)
    
    Expected value to equal:
      1
    Received:
      0
      
      at Object.<anonymous> (client/pages/__tests__/SurveyEditor.jsx:180:35)

Line 180 corresponds to: expect(willUnmount.callCount).toEqual(1); It seems as though componentWillUnmount is not actually getting called. Relevant dependencies include:

  • "enzyme": "^2.7.0",
  • "jest": "^18.1.0",
  • "jest-cli": "^18.1.0",
  • "sinon": "^1.17.7",
  • "babel-jest": "^18.0.0",
@aweary
Copy link
Collaborator

aweary commented Jan 23, 2017

@ml9951 I tried to reproduce using the same version of Enzyme, but everything worked for me. You can see my test here: https://github.com/aweary/enzyme-test-repo/blob/issue-785/test.js

What version of React are you using?

@lematt1991
Copy link
Author

That is interesting. I tried your example and it is working for me. I also replaced your package.json with the one from my other project and it still worked after deleting node_modules and reinstalling everything. It seems like one of my other tests in that same describe is somehow interfering with it. If I comment out all of my other tests in that file, it works fine. This doesn't really make any sense to me, given that this is a very simple and isolated test that doesn't depend on any stores/actions or anything else that has anything to do with my other tests. I'll see if I can simplify it and get back to you with a reproducible example.

@lematt1991
Copy link
Author

OK, I've managed to reproduce it in a fork of your repo: https://github.com/ml9951/enzyme-test-repo/tree/issue-785. Installing the dependencies and running npm test should reproduce it. I'm testing the flow of a stripped down flux app. Unless I'm missing something, it shouldn't have any impact on the original test that I posted. If you switch the order of the two tests, then they both pass.

@aweary
Copy link
Collaborator

aweary commented Jan 24, 2017

Thanks for the repo! I was able to reproduce your issue with it. That is super weird. Those tests appear to be fully isolated (mounting two distinct components) but removing the first test cases the second to pass again 😕

The stack trace for the error seems to indicate it has something to do with your Flux dispatcher:

Stack trace:

at Object.<anonymous> (test.js:60:35)
      at Store.<anonymous> (test.js:25:7)
      at emitNone (events.js:86:13)
      at Store.emit (events.js:185:7)
      at Store._this.save (stores/Store.js:7:39)
      at Object.Store._this.handleActions (stores/Store.js:13:43)
      at Dispatcher._invokeCallback (node_modules/flux/lib/Dispatcher.js:198:24)
      at Dispatcher.dispatch (node_modules/flux/lib/Dispatcher.js:174:14)
      at Object.save (actions/Actions.js:4:50)
      at onClick (test.js:14:228)
      at Object.invokeGuardedCallback [as invokeGuardedCallbackWithCatch] (node_modules/react-dom/lib/ReactErrorUtils.js:26:5)
      at executeDispatch (node_modules/react-dom/lib/EventPluginUtils.js:83:21)
      at Object.executeDispatchesInOrder (node_modules/react-dom/lib/EventPluginUtils.js:108:5)
      at executeDispatchesAndRelease (node_modules/react-dom/lib/EventPluginHub.js:43:22)
      at executeDispatchesAndReleaseSimulated (node_modules/react-dom/lib/EventPluginHub.js:51:10)
      at forEachAccumulated (node_modules/react-dom/lib/forEachAccumulated.js:26:8)
      at Object.processEventQueue (node_modules/react-dom/lib/EventPluginHub.js:255:7)
      at node_modules/react-dom/lib/ReactTestUtils.js:340:22
      at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-dom/lib/Transaction.js:140:20)
      at Object.batchedUpdates (node_modules/react-dom/lib/ReactDefaultBatchingStrategy.js:62:26)
      at Object.batchedUpdates (node_modules/react-dom/lib/ReactUpdates.js:97:27)
      at node_modules/react-dom/lib/ReactTestUtils.js:338:18
      at ReactWrapper.<anonymous> (node_modules/enzyme/build/ReactWrapper.js:776:11)
      at ReactWrapper.single (node_modules/enzyme/build/ReactWrapper.js:1421:25)
      at ReactWrapper.simulate (node_modules/enzyme/build/ReactWrapper.js:769:14)
      at Object.<anonymous> (test.js:27:28)
      at process._tickCallback (internal/process/next_tick.js:103:7)

I suspect it's because of the first test being asynchronous and the second is synchronous. The test passes if you make the second test asynchronous and delay the mount assertions until the next tick:

process.nextTick(() => {
  const wrapper = mount(<Foo id="foo" />);
  expect(willMount.callCount).toEqual(1);
  expect(didMount.callCount).toEqual(1);
  expect(willUnmount.callCount).toEqual(0);
  wrapper.unmount();
  expect(willMount.callCount).toEqual(1);
  expect(didMount.callCount).toEqual(1);
  expect(willUnmount.callCount).toEqual(1);
  done()
})

@aweary aweary self-assigned this Feb 3, 2017
@OzTK
Copy link

OzTK commented Mar 28, 2018

Had the same issue. In my case simply making all of the tests asynchronous did the trick to have componentWillUnmount be called as expected

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants