Enzyme: Method “text” is only meant to be run on a single node. 0 found instead
Asked Answered
N

5

16

I'm using React v15.4, babel-jest v18 and enzyme v2.5.1

I have a simple React Component:

import React, {Component} from 'react'
import {FormattedRelative} from 'react-intl'
import pageWithIntl from '../components/PageWithIntl'
import Layout from '../components/Layout'

class About extends Component {
  static async getInitialProps ({req}) {
    return {someDate: Date.now()}
  }

  render () {
    return (
      <Layout>
        <h1>About</h1>
        <p>
          <FormattedRelative
            value={this.props.someDate}
            updateInterval={1000}
          />
        </p>
      </Layout>
    )
  }
}

export default pageWithIntl(About)

And a simple Jest/Enzyme Test:

/* global it, expect, describe */

import React from 'react'
import { shallow } from 'enzyme'
import renderer from 'react-test-renderer'
import About from '../pages/about.js'

describe('With Enzyme', () => {
  it('App shows "About"', () => {
    const about = shallow(
      <About />
    )
    expect(about.find('h1').text()).toEqual('About')
  })
})

The Jest test should pass but I'm getting an error:

Method “text” is only meant to be run on a single node. 0 found instead.

What am I missing?

=== Update

The snapshot test passes:

describe('With Snapshot Testing', () => {
  it('About shows "About"', () => {
    const component = renderer.create(<About />)
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
  })
})

Is there a way to integrate the enzyme expect test inside the snapshot test? And how?

Norse answered 28/3, 2017 at 15:12 Comment(0)
W
16

Its caused by the fact that shallow does not render child componnets and your component been wrapped by a function. So shallow only returns a representation of the function not of the component. You can use dive() to reach the real component

/* global it, expect, describe */

import React from 'react'
import { shallow } from 'enzyme'
import renderer from 'react-test-renderer'
import About from '../pages/about.js'

describe('With Enzyme', () => {
  it('App shows "About"', () => {
    const about = shallow(
      <About />
    ).dive()
    expect(about.find('h1').text()).toEqual('About')
  })
})
Wintertime answered 28/3, 2017 at 15:36 Comment(5)
I still get the error message: Method “text” is only meant to be run on a single node. 0 found instead. at ShallowWrapper.single (node_modules/enzyme/build/ShallowWrapper.js:1502:17) at ShallowWrapper.text (node_modules/enzyme/build/ShallowWrapper.js:744:21) at Object.<anonymous> (__tests__/about.test.js:13:29) With Enzyme ✕ App shows "About" (11ms)Norse
Could it be that pageWithIntl wraps it with another function. What helps me to find out whats going is to render it in a snapshot to actually see the rendered output.Distinct
Can you elaborate on how you would render it in a snapshot? Snapshot test with const component = renderer.create(<About />); const tree = component.toJSON(); expect(tree).toMatchSnapshot(); passes but with the same expect statement from above fails with same error message.Norse
just like this:expect(shallow(<About />).dive()).toMatchSnapshot() then you can add another dive() until you reach you real component.Distinct
getting below error after I use dive() TypeError: ShallowWrapper::dive() can not be called on Host ComponentsBarrington
L
4

Use .first()

example const wrapper = shallow()

wrapper.find('h1 or p or .ClassName or #id').first();

import React from 'react'
import { shallow } from 'enzyme'
import renderer from 'react-test-renderer'
import About from '../pages/about.js'

describe('With Enzyme', () => {
  it('App shows "About"', () => {
    const about = shallow(
      <About />
   )
  expect(about.find('h1').first().text()).toEqual('About')
 })
})
Landlubber answered 12/6, 2018 at 16:39 Comment(0)
M
4

Please see this link on how to use the .findWhere on a shallow copy: https://blogs.sequoiainc.com/an-enzyme-gotcha/

Below is an example looking for nodes/html-elements of type "p" that contain the desired text which represents a salary "$100,000.00".

displayemployee = shallow(<DisplayEmployee employeeData={employee}

it('renders the employees salary', () => {
  expect(
    displayemployee.findWhere(
    n => n.type() === 'p' && n.contains('$100,000.00')
  )
)

The shallow copy returns all the nodes that the react component returns, and I'm searching through those nodes with .findWhere rather than .text. This is because .text expects to look through a single node; .text doesn't know how to scan through many nodes.

Muddler answered 13/8, 2018 at 7:25 Comment(0)
D
0

You can also 'export class' along with 'export default' and import component in test with the destructuring import version.

For example:

import React, {Component} from 'react'
import {FormattedRelative} from 'react-intl'
import pageWithIntl from '../components/PageWithIntl'
import Layout from '../components/Layout'

export class About extends Component {
  static async getInitialProps ({req}) {
    return {someDate: Date.now()}
  }

  render () {
    return (
      <Layout>
        <h1>About</h1>
        <p>
          <FormattedRelative
            value={this.props.someDate}
            updateInterval={1000}
          />
        </p>
      </Layout>
    )
  }
}

export default pageWithIntl(About)

And the test:

/* global it, expect, describe */

import React from 'react'
import { shallow } from 'enzyme'
import renderer from 'react-test-renderer'
import { About } from '../pages/about.js'

describe('With Enzyme', () => {
  it('App shows "About"', () => {
    const about = shallow(
      <About />
    )
    expect(about.find('h1').text()).toEqual('About')
  })
})
Diuretic answered 2/4, 2019 at 21:44 Comment(0)
V
0

To drill into the child components

Use mount instead of shallow

Veroniqueverras answered 30/12, 2022 at 10:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.