21

Is there a way to get the actual DOM node so I can the query it with the Dom api as opposed to being required to use enzyme's api, it's just for edge cases where for example I need to assert things about the dom node itself.

njorlsaga
  • 801
  • 2
  • 9
  • 21

6 Answers6

26

You can use wrapper.getDOMNode()

Enzyme docs

tonyjmnz
  • 536
  • 4
  • 13
13

Perhaps you are looking for enzyme's instance()?

const wrapper = mount(<input type="text" defaultValue="hello"/>)
console.log(wrapper.instance().value); // 'hello'

PS:

instance() should give you a ReactComponent, from which you can use ReactDOM.findDOMNode(ReactComponent) to get a DOMNode. However, when I did that, like the following, it was the exact same object as wrapper.instance():

import ReactDOM from 'react-dom'
const wrapper = mount(<input type="text" defaultValue="sup"/>)
console.log(ReactDOM.findDOMNode(wrapper.instance()) == wrapper.instance()) // true

I don't understand why that is. If you console.log() either one of those, you'll see a HTMLInputElement, but it will contain lots of non-native DOM node looking stuff:

HTMLInputElement {
  '__reactInternalInstance$yt1y6akr6yldi': 
   ReactDOMComponent {
     _currentElement: 
      { '$$typeof': Symbol(react.element),
        type: 'input',
        key: null,
        ref: null,
        props: [Object],
        _owner: [Object],
        _store: {} },
Tyler Collier
  • 11,489
  • 9
  • 73
  • 80
  • When I tried your technique, it seemed to work as expected. In other words, `ReactDOM.findDOMNode(wrapper.instance()) != wrapper.instance()`. FWIW, I'm using React 15 and Enzyme 2.3.0. – killthrush Jul 17 '16 at 16:38
  • I wonder if it's because I was using jsdom (or, I THINK I was. Foolish I don't have a permalink to the code I ran). Are you using jsdom? – Tyler Collier Jul 17 '16 at 16:52
  • Yes, I am using jsdom 9.1.0 - sorry I forgot to mention that – killthrush Jul 17 '16 at 17:17
  • This applies only for the root wrapper (of the React component `mount()`ed or `shallow()`ed). See @tonyjmnz' answer for a more broadly-applicable solution. – ericsoco Nov 28 '17 at 19:14
6

I ran into this same problem. In my case, I was testing something built with react-aria-modal, which renders the overlay div in a different part of the DOM than the initial element rendered with mount(). In order to test that this renders properly, I needed to look more globally at the DOM. For this, I used the attachTo option of render() to ensure that my test DOM looks like it should in a real browser. Here is a good general description of the technique from the docs.

Depending on what you need, you can use Tyler Collier's approach for more local parts of the DOM (findDOMNode using instance()) or mine for a more global view.

Here's a sample spec for my use case, showing how to setup/use/teardown the mock DOM:

import MyModalComponent from '../components/my-modal-component'
import React from 'react'
import { jsdom } from 'jsdom'
import { mount } from 'enzyme'

describe('<MyModalComponent /> Component', function(){

  let wrapper

  beforeEach(function(){
    window.document = jsdom('')
    document.body.appendChild(document.createElement('div'))
  })

  afterEach(function(){
    wrapper.detach()
    window.document = jsdom('')
  })

  it('renders the modal closed by default', () => {
    wrapper = mount(
      <MyModalComponent prop1={"foo"}
                        prop2={"bar"}
      />, { attachTo: document.body.firstChild }
    )
    expect(wrapper.html()).to.contain('Content in component')
    expect(document.body.innerHTML).to.not.contain('Content in overlay')
  })

})
killthrush
  • 4,859
  • 3
  • 35
  • 38
1

If you create a DOM using jsdom, something like this:

import jsdom from 'jsdom';
const doc = jsdom.jsdom('<!doctype html><html><body></body></html>');
global.document = doc;
global.window = doc.defaultView;

Then you can use enzyme's mount() to render whatever you wish to test.

You can then assert against the style you are looking for:

expect(wrapper).to.have.style("display", "none");

Ryan27
  • 453
  • 4
  • 16
  • I am using mount which uses jsdom as I understand, already but how would you get the actual wrapper's DOM node so I can use the dom api? for example to query className but *not* using prop('className') – njorlsaga Jun 10 '16 at 10:33
  • There may be a better way, but you could always call `.html()` on the element, and then use something like `DOMParser()`: http://stackoverflow.com/questions/3103962/converting-html-string-into-dom-elements – Ryan27 Jun 10 '16 at 12:08
0

You can use soemething like :

const dialog = component.find(Modal);
let modal = dialog.node._modal;
modal.getDialogElement().querySelector('#saveBtn')

based on the test for Modal in react-bootstrap web site

https://github.com/react-bootstrap/react-bootstrap/blob/master/test/ModalSpec.js

JPRLCol
  • 749
  • 11
  • 28
0

If you want to print out whole DOM,

const wrapper = shallow(<MyComponent/>);
console.log("DOM tree for humans", wrapper.text());
Smit Thakkar
  • 410
  • 2
  • 8
  • 16