jest + enzyme, using mount(), document.getElementById() returns null on component which appear after _method call
Found the solution thanks to https://stackoverflow.com/users/853560/lewis-chung and gods of Google:
Attached my component to DOM via
attachTo
param:const result = mount( <App />, { attachTo: document.body });
Changed buggy string in my method to string which works with element Object
agentToMod.location = locationSelect.options[locationSelect.selectedIndex].text;` : _modifyAgentStatus () { const { currentAgentProfile, agentsDatabase } = this.state; const agentToMod = currentAgentProfile; if (agentToMod.status === 'Free') { this.setState({ infoDisplayContent: 'mission' }); agentToMod.status = 'Waiting'; } else if (agentToMod.status === 'Waiting') { const locationSelect = document.getElementById('missionLocationSelect'); agentToMod.location = agentToMod.location = locationSelect.options[locationSelect.selectedIndex].text; agentToMod.status = 'On Mission'; this.setState({ infoDisplayContent: 'profile' }); } }
attachTo: document.body
will generate a warning:
Warning: render(): Rendering components directly into document.body is discouraged, since its children are often manipulated by third-party scripts and browser extensions. This may lead to subtle reconciliation issues. Try rendering into a container element created for your app.
So just attach to a container element instead of document.body
, and no need to add it to the global Window object
before(() => { // Avoid `attachTo: document.body` Warning const div = document.createElement('div'); div.setAttribute('id', 'container'); document.body.appendChild(div);});after(() => { const div = document.getElementById('container'); if (div) { document.body.removeChild(div); }});it('should display all contents', () => { const wrapper = mount(<YourComponent/>,{ attachTo: document.getElementById('container') });});
Attached your component to DOM via attachTo
param.
import { mount} from 'enzyme';// Avoid Warning: render(): Rendering components directly into document.body is discouraged.beforeAll(() => { const div = document.createElement('div'); window.domNode = div; document.body.appendChild(div);})test("Test component with mount + document query selector",()=>{ const wrapper = mount(<YourComponent/>,{ attachTo: window.domNode });});
why we need this?
mount
only render component to div element not attached it to DOM tree.
// Enzyme code of mount renderer. createMountRenderer(options) { assertDomAvailable('mount'); const domNode = options.attachTo || global.document.createElement('div'); let instance = null; return { render(el, context, callback) { if (instance === null) { const ReactWrapperComponent = createMountWrapper(el, options); const wrappedEl = React.createElement(ReactWrapperComponent, { Component: el.type, props: el.props, context, }); instance = ReactDOM.render(wrappedEl, domNode); if (typeof callback === 'function') { callback(); } } else { instance.setChildProps(el.props, context, callback); } }, unmount() { ReactDOM.unmountComponentAtNode(domNode); instance = null; }, getNode() { return instance ? instanceToTree(instance._reactInternalInstance).rendered : null; }, simulateEvent(node, event, mock) { const mappedEvent = mapNativeEventNames(event); const eventFn = TestUtils.Simulate[mappedEvent]; if (!eventFn) { throw new TypeError(`ReactWrapper::simulate() event '${event}' does not exist`); } // eslint-disable-next-line react/no-find-dom-node eventFn(ReactDOM.findDOMNode(node.instance), mock); }, batchedUpdates(fn) { return ReactDOM.unstable_batchedUpdates(fn); }, }; }