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

setState causes Invariant Violation when it changes markup #58

Closed
silvenon opened this issue Dec 7, 2015 · 9 comments
Closed

setState causes Invariant Violation when it changes markup #58

silvenon opened this issue Dec 7, 2015 · 9 comments
Assignees

Comments

@silvenon
Copy link
Contributor

silvenon commented Dec 7, 2015

I'm aware of #27, mine happens on React v0.14 and it crushes my soul as well 😞

As far as I've tested (AFAIT?), this only happens when the state alters markup:

import React from 'react';
import { mount, describeWithDOM } from 'enzyme';

const Component = React.createClass({
  getInitialState() {
    return { flag: false };
  },

  render() {
    return this.state.flag ? <a /> : <div />
  }
});

describeWithDOM('<Component />', () => {
  it('turns on the flag', () => {
    const wrapper = mount(<Component />);
    wrapper.setState({ flag: true });
  });
});
Error: Invariant Violation: dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use ReactDOMServer.renderToString() for server rendering.

This does not happen if both elements are the same (e.g. this.state.flag ? <div /> : <div />).

Jest seemed to have solved this issue, it doesn't happen there, so it might be worth looking how they did it. I can take a look later, but I was wondering if you knew what's causing this.

This SO answer might help, though I'm not sure if it's related.

@lelandrichardson
Copy link
Collaborator

Hmm. Surprised this is happening. I will look into it as soon as I get a sec.

@lelandrichardson
Copy link
Collaborator

@silvenon I'm looking into this but it looks like React 0.14 has a hard dependency on document.createElement at require-time in order to get this to work properly, where-as React 0.13 did not. There may be a way around this, but I'm not sure what it is yet.

In the mean time, you should be able to get this working by requiring jsdom and leak it to the global object before requiring enzyme (which is what jest is doing, FWIW).

global.document = require('jsdom').jsdom('');
var { mount } = require('enzyme');

// use `mount` here like normal, but don't use `describeWithDOM`...

note that the usage of require over import here is intentional, since the first statement must be executed before enzyme (and thus react) get's required.

I'm working on a less brittle way to fix this...

@silvenon
Copy link
Contributor Author

silvenon commented Dec 7, 2015

I managed to keep my precious imports by adding this helper:

// test/global.js
import jsdom from 'jsdom';

global.document = jsdom.jsdom('');
global.window = document.defaultView;
global.navigator = window.navigator;

And passing --require ./test/global to Mocha, which ensured that it will be loaded first.

I also had to define window and navigator. navigator because react-dom was calling navigator.userAgent.indexOf(), which was throwing.

Thanks, it works now 😃

@silvenon
Copy link
Contributor Author

silvenon commented Dec 7, 2015

I realized that my solution only initializes the document once, is this bad?

@lelandrichardson
Copy link
Collaborator

@silvenon it depends. Doing so can simplify a lot of things. some libraries will cache a reference to the document at require time (like jquery) and thus you have to jump through a lot of hoops to have code work when using a new document for every test. We plan on using only a single document for our entire test suite at airbnb soon, but we don't yet.

As far as react goes, enzyme's mount() uses TestUtils.renderIntoDocument internally which doesn't even attach itself to the main document, so it has pretty limited side effects that could affect other tests, but you still need to be conscious about some DOM APIs that will have side effects across tests.

Also, you should be able to refresh the document later on in your tests and react will work just fine with it. React doesn't cache any document references AFAICT, it just uses whatever document is off the global.

@silvenon
Copy link
Contributor Author

silvenon commented Dec 7, 2015

Thanks for the detailed explanation 👍 Learning so much from you guys.

@lelandrichardson
Copy link
Collaborator

Closing this issue as it should now be "fixed". This problem should no longer exist so long as you have a global document object prior to requiring react for the first time.

kire321 added a commit to lab-coop/hashticle that referenced this issue Nov 25, 2016
golya added a commit to lab-coop/hashticle that referenced this issue Nov 30, 2016
…rouslyReplaceNodeWithMarkup

See enzymejs/enzyme#58

Signed-off-by: Erik Wyatt <kire321@gmail.com>
Signed-off-by: Ádám Gólya <adam.stork@gmail.com>
golya added a commit to lab-coop/hashticle that referenced this issue Dec 1, 2016
…rouslyReplaceNodeWithMarkup

See enzymejs/enzyme#58

Signed-off-by: Erik Wyatt <kire321@gmail.com>
Signed-off-by: Ádám Gólya <adam.stork@gmail.com>
golya added a commit to lab-coop/hashticle that referenced this issue Dec 2, 2016
…rouslyReplaceNodeWithMarkup

See enzymejs/enzyme#58

Signed-off-by: Erik Wyatt <kire321@gmail.com>
Signed-off-by: Ádám Gólya <adam.stork@gmail.com>
@carlosble
Copy link

Polluting the global document causes side effects among tests, they basically share the DOM thus causing nasty behaviors when running multiple tests with Mocha for example. So that workaround fixes one problem but causes others

@zazaian
Copy link

zazaian commented Jul 11, 2017

Hey all - just for reference, requiring jsdom prior to requiring enzyme fixed this issue for me as well. Thanks to all for the assistance here.

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