Package detail

chai-enzyme

producthunt192.7kMIT1.0.0-beta.1

Chai.js assertions for enzyme

javascript, shallow rendering, shallowRender, test

readme

chai-enzyme

npm version License Build Status

Chai.js assertions for enzyme.

Table of Contents

  1. Installation
  2. Setup
  3. Debug output in assertion exceptions
  4. Assertions
    1. checked()
    2. className(str)
    3. contain(nodeOrNodes)
    4. containMatchingElement(node)
    5. descendants(selector)
      1. exactly()
    6. disabled()
    7. blank()
    8. present()
    9. html(str)
    10. id(str)
    11. match(selector)
    12. ref(key)
    13. selected()
    14. tagName(str)
    15. text(str)
    16. type(func)
    17. value(str)
    18. attr(key, [val])
    19. data(key, [val])
    20. style(key, [val])
    21. state(key, [val])
    22. prop(key, [val])
    23. props(key, [val])
  5. Development
  6. Contributing
  7. License

Installation

chai-enzyme depends on:

"peerDependencies": {
  "chai": "^3.0.0 || ^4.0.0",
  "cheerio": "0.19.x || 0.20.x || 0.22.x || ^1.0.0-0",
  "enzyme": "^2.7.0 || ^3.0.0",
  "react": "^0.14.0 || ^15.0.0-0 || ^16.0.0-0",
  "react-dom": "^0.14.0 || ^15.0.0-0 || ^16.0.0-0"
}

cheerio is already a dependency of enzyme, so most probably you will not have to install it manually

$ npm install chai-enzyme --save-dev

Setup

import chai from 'chai'
import chaiEnzyme from 'chai-enzyme'

chai.use(chaiEnzyme()) // Note the invocation at the end

Debug output in assertion exceptions

You can also provide a custom debug function that can print useful information about the wrapper that you are using.

The default one that chai-enzyme comes with, will pretty print the HTML of the wrapper under test.

  1) #text (text) (shallow): passes when the actual matches the expected:
     AssertionError: expected <Fixture /> to have text 'Test test', but it has 'Test'

     ---------- this is where the debug output starts ----------

     HTML:

     <span id="child">Test</span>

     ---------- this is where the debug output ends ----------

Here is how you can implement and configure one for yourself:

function myAwesomeDebug (wrapper) {
  let html = wrapper.html()
  // do something cool with the html
  return html
}

chai.use(chaiEnzyme(myAwesomeDebug))

Assertions

It's important to know that all assertions are registered with Chai's overwrite* methods and therefore this plugin can work next to other Chai.js plugins that have similar assertions, such as chai-jquery.

At the beginning of each assertion, we verify if the provided object is a ShallowWrapper, ReactWrapper or a cheerio object and if not we delegate to the next assertion that responds to the given method.

Note that not all assertions work with every rendering strategy.

If you are wondering what rendering mechanism to use when, refer to enzyme's documentation.

checked()

render mount shallow
yes yes yes

Assert that the given wrapper is checked:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div>
        <input id='checked' defaultChecked />
        <input id='not' defaultChecked={false} />
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('#checked')).to.be.checked()
expect(wrapper.find('#not')).to.not.be.checked()

className(str)

render mount shallow
yes yes yes

Assert that the wrapper has a given class:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div className='root top'>
        <span className='child bottom'>test</span>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('span')).to.have.className('child')
expect(wrapper.find('span')).to.not.have.className('root')

contain(nodeOrNodes)

render mount shallow
no yes yes

Assert that the wrapper contains a given node or array of nodes:

import React from 'react'
import {mount, render, shallow} from 'enzyme'
import PropTypes from 'prop-types';

class User extends React.Component {
  render () {
    return (
      <span>User {this.props.index}</span>
    )
  }
}

User.propTypes = {
  index: PropTypes.number.isRequired
}

class Fixture extends React.Component {
  render () {
    return (
      <div>
        <ul>
          <li><User index={1} /></li>
          <li>
            <User index={2} />
            <User index={3} />
          </li>
        </ul>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper).to.contain(<User index={1} />)
expect(wrapper).to.contain([<User index={2} />, <User index={3} />])
expect(wrapper).to.not.contain(<User index={3} />)

containMatchingElement(node)

render mount shallow
no yes yes

Assert that the wrapper contains a matching given node:

import React from 'react'
import {mount, render, shallow} from 'enzyme'
import PropTypes from 'prop-types';

class User extends React.Component {
  render () {
    return (
      <span>User {this.props.index} {this.props.name}</span>
    )
  }
}

User.propTypes = {
  index: PropTypes.number,
  name: PropTypes.string.isRequired
}

class Fixture extends React.Component {
  render () {
    return (
      <div>
        <ul>
          <li><User index={1} name='John' /></li>
          <li><User index={2} name='Doe' /></li>
        </ul>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper).to.containMatchingElement(<User name='John' />)
expect(wrapper).to.not.containMatchingElement(<User name='Conor' />)

descendants(selector)

render mount shallow
yes yes yes

Assert that the wrapper contains a descendant matching the given selector:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class User extends React.Component {
  render () {
    return (
      <span>User</span>
    )
  }
}

class Fixture extends React.Component {
  render () {
    return (
      <div id='root'>
        <User />
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper).to.have.descendants('#root')
expect(wrapper).to.have.descendants(User)

expect(wrapper).to.not.have.descendants('#root1')

exactly()

render mount shallow
yes yes yes

Assert that the wrapper contains an exact amount of descendants matching the given selector:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div id='root'>
        <span id='child'>
          <span class='item'></span>
          <span class='item'></span>
        </span>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper).to.have.exactly(2).descendants('.item')

disabled()

render mount shallow
yes yes yes

Assert that the given wrapper is disabled:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div>
        <input id='disabled' disabled />
        <input id='not' />
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('#disabled')).to.be.disabled()
expect(wrapper.find('#not')).to.not.be.disabled()

blank()

render mount shallow
yes yes yes

Assert that the given wrapper is empty:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div id='parent'>
        <div id='child'>
        </div>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('#child')).to.be.blank()
expect(wrapper.find('#parent')).to.not.be.blank()

expect(wrapper.find('#child')).to.be.empty // an alias
expect(wrapper.find('#parent')).to.not.be.empty // an alias

class NullFixture extends React.Component {
  render () {
    return null
  }
}

const nullWrapper = mount(<NullFixture />) // mount/render/shallow when applicable

expect(nullWrapper).to.be.blank()
expect(nullWrapper).to.be.empty // an alias

present()

render mount shallow
yes yes yes

Assert that the given wrapper exists:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div id='parent'></div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('#parent')).to.be.present()
expect(wrapper.find('#parent')).to.exist // an alias

class NullFixture extends React.Component {
  render () {
    return null
  }
}

const nullWrapper = mount(<NullFixture />) // mount/render/shallow when applicable

expect(nullWrapper).to.be.present()
expect(nullWrapper).to.exist // an alias

html(str)

render mount shallow
yes yes yes

Assert that the wrapper has given html:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div id='root'>
        <span id='child'>Test</span>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('#child')).to.have.html('<span id="child">Test</span>')

expect(wrapper.find('#child')).to.not.have.html('<span id="child">Test 1</span>')

expect(wrapper.find('#child')).to.have.html().match(/Test/)

id(str)

render mount shallow
yes yes yes

Assert that the wrapper has given ID attribute:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div id='root'>
        <span id='child'>test</span>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper).to.have.id('root')
expect(wrapper).to.not.have.id('child')

match(selector)

render mount shallow
yes yes yes

Assert that the wrapper matches given selector:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div id='root'>
        <span id='child'>test</span>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('span')).to.match('#child')
expect(wrapper.find('#root')).to.not.match('#child')

ref(key)

render mount shallow
no yes no
import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div>
        <input ref='test' />
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper).to.have.ref('test')
expect(wrapper).to.have.ref('random')

selected()

render mount shallow
yes yes no

Assert that the given wrapper is selected:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <select defaultValue='test1'>
        <option id='test1' value='test1'>Test 1</option>
        <option id='test2' value='test2'>Test 1</option>
      </select>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('#test1')).to.be.selected()
expect(wrapper.find('#test2')).to.not.be.selected()

tagName(str)

render mount shallow
yes yes yes

Assert that the given wrapper has the tag name:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div>
        <span />
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper).to.have.tagName('div')
expect(wrapper.find('span')).to.have.tagName('span')

expect(wrapper).to.not.have.tagName('a')
expect(wrapper.find('span')).to.not.have.tagName('a')

text(str)

render mount shallow
yes yes yes

Assert that the given wrapper has the supplied text:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div id='root'>
        <span id='child'>Test</span>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('#child')).to.have.text('Test')

expect(wrapper.find('#child')).to.contain.text('Te')
expect(wrapper.find('#child')).to.include.text('Te') // include is an alias of contain

expect(wrapper.find('#child')).to.not.have.text('Other text')
expect(wrapper.find('#child')).to.not.include.text('Other text') // include is an alias of contain

expect(wrapper.find('#child')).to.have.text().match(/Test/)

type(func)

render mount shallow
no yes yes

Assert that the given wrapper has a given type:

import React from 'react'
import {shallow} from 'enzyme'

class Foo extends React.Component {
  render () {
    return (
      <div>Foo</div>
    )
  }
}

class Bar extends React.Component {
  render () {
    return (
      <div>Bar</div>
    )
  }
}

class Fixture extends React.Component {
  render () {
    return (
      <Foo />
    )
  }
}

const shallowWrapper = shallow(<Fixture />)
const mountWrapper = mount(<Fixture />)

expect(shallowWrapper).to.have.type(Foo)
expect(shallowWrapper).to.not.have.type(Bar)

expect(mountWrapper).to.have.type(Fixture)
expect(mountWrapper).to.not.have.type(Bar)

value(str)

render mount shallow
yes yes yes

Assert that the given wrapper has given value:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div>
        <input defaultValue='test' />
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('input')).to.have.value('test')
expect(wrapper.find('input')).to.not.have.value('other')

attr(key, [val])

render mount shallow
yes yes yes

Assert that the wrapper has given attribute [with value]:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div id='root'>
        <span id='child'>test</span>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find('span')).to.have.attr('id')
expect(wrapper).to.not.have.attr('disabled')

expect(wrapper).to.have.attr('id', 'root')
expect(wrapper).to.not.have.attr('id', 'invalid')

expect(wrapper).to.have.attr('id').equal('root')

data(key, [val])

render mount shallow
yes yes yes

Assert that the wrapper has a given data attribute [with value]:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div data-name='root'>
        <span data-name='child'>test</span>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper).to.have.data('name')
expect(wrapper).to.not.have.data('random')

expect(wrapper).to.have.data('name', 'root')
expect(wrapper).to.not.have.data('name', 'invalid')

expect(wrapper).to.have.data('name').equal('root')

style(key, [val])

render mount shallow
yes yes yes

Assert that the wrapper has given style:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  render () {
    return (
      <div style={{ border: 1 }}>
        <span style={{ color: 'red' }}>test</span>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper).to.have.style('border')
expect(wrapper).to.not.have.style('color')
expect(wrapper).to.have.style('margin-top') // do not use camelCase keys as you would do in your React component

expect(wrapper).to.have.style('border', '1px')
expect(wrapper).to.not.have.style('border', '2px')

expect(wrapper).to.have.style('border').equal('1px')

state(key, [val])

render mount shallow
no yes yes

Assert that the wrapper has given state [with value]:

import React from 'react'
import {mount, render, shallow} from 'enzyme'

class Fixture extends React.Component {
  constructor () {
    super()
    this.state = { foo: 'bar' }
  }

  render () {
    return (
      <div id='root'>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper).to.have.state('foo')
expect(wrapper).to.not.have.state('bar')


expect(wrapper).to.have.state('foo', 'bar')
expect(wrapper).to.not.have.state('foo', 'baz')

expect(wrapper).to.have.state('foo').equal('bar')

prop(key, [val])

render mount shallow
no yes yes

Assert that the wrapper has given prop [with value]:

import React from 'react'
import {mount, render, shallow} from 'enzyme'
import PropTypes from 'prop-types';

class User extends React.Component {
  render () {
    return (
      <span>User {this.props.index}</span>
    )
  }
}

User.propTypes = {
  index: PropTypes.number.isRequired
}

class Fixture extends React.Component {
  render () {
    return (
      <div>
        <ul>
          <li><User index={1} user={{name: 'Jane'}} /></li>
          <li><User index={2} /></li>
        </ul>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find(User).first()).to.have.prop('index')
expect(wrapper.find(User).first()).to.not.have.prop('invalid')


expect(wrapper.find(User).first()).to.have.prop('index', 1)
expect(wrapper.find(User).first()).to.not.have.prop('index', 2)

expect(wrapper.find(User).first()).to.have.prop('index').equal(1)
expect(wrapper.find(User).first()).to.have.prop('user').deep.equal({name: 'Jane'})

props(key, [val])

render mount shallow
no yes yes

Assert that the wrapper has given set of props [with values]:

import React from 'react'
import {mount, render, shallow} from 'enzyme'
import PropTypes from 'prop-types';

class User extends React.Component {
  render () {
    return (
      <span>User {this.props.index}</span>
    )
  }
}

User.propTypes = {
  index: PropTypes.number.isRequired
}

class Fixture extends React.Component {
  render () {
    return (
      <div>
        <ul>
          <li><User index={1} user={{name: 'Jane'}} /></li>
          <li><User index={2} /></li>
        </ul>
      </div>
    )
  }
}

const wrapper = mount(<Fixture />) // mount/render/shallow when applicable

expect(wrapper.find(User).first()).to.have.props([ 'index', 'user' ])
expect(wrapper.find(User).first()).to.not.have.props([ 'invalid' ])


expect(wrapper.find(User).first()).to.have.props({ index: 1 })
expect(wrapper.find(User).first()).to.not.have.props({ index: 2 })

expect(wrapper.find(User).first()).to.have.props([ 'index', 'user' ]).deep.equal([ 1, { name: 'Jane' } ])

Development

Setup

$ git clone <this repo>
$ cd chai-enzyme
$ npm install

Tests

Linters:

$ npm run test:lint

Tests:

$ npm run test:unit

All:

$ npm test

Contributing

We want to make this assertion library as robust and complete as possible. If you think that there are missing features/assertions, please open a GitHub issue or even better - a PR.

Bug reports and pull requests are welcome on GitHub. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

Product Hunt

 _________________
< The MIT License >
 -----------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changelog

1.0.0 / Unreleased

  • [feature] Add support for enzyme ^3.0.0 (which implies React 16 support)
  • [feature] Support an array of nodes in contain
  • [breaking] If you are using cheerio 1.0, there's' a possibility you will have to wrap your React components with a div wrapper.
<div id='parent'>
  <div id='child' />
<div>
// Enzyme 2
wrapper.find('#parent').length //=> 1
wrapper.is('#parent') //=> false

// Enzyme 3
wrapper.find('#parent').length //=> 0
wrapper.is('#parent') //=> true

The new version returns a cheerio wrapper with a type of tag that IS the parent element.
Before it returned a wrapper with a type root that contains the parent element.
  • [fix] Add support for components with a symbol as display name
  • [feature] Only show one-level-deep components in error messages when shallow rendering

0.8.0 / June 29 2017

  • [feature] Add support for chai ^4.0.0
  • [fix] Protect against duplicate plugin use

0.7.1 / May 24 2017

  • [fix] Don't repeat enzyme's peer dependencies

0.7.0 / May 22 2017

  • [breaking] Upgrade Enzyme dependency to 2.3.x or above
  • [feature] add containMatchingElement support
  • [fix] Handle .exactly(0)
  • [fix] Add support for undefined argument values

0.6.1 / November 18 2016

  • [fix] React 15.4.x support

0.6.0 / November 5 2016

  • [fix] Fix cross-browser issue when using text assertions
  • [fix] Delegate to Enzyme wrapper .is for match assertions
  • [feature] props assertion
  • [feature] add contain/include support for html assertions
  • [feature] type assertion

0.5.2 / September 30 2016

  • [fix] Loosen up cheerio peer dependency

0.5.1 / August 23 2016

  • [fix] Add exactly to TOC
  • [fix] Bump html dependency for less deprecation warnings

0.5.0 / June 13 2016

  • [feature] Add textarea support for contain assertions
  • [feature] Add select support for value assertions
  • [feature] Improve failure message for contain assertions
  • [fix] Truthy-ness values

0.4.2 / April 8 2016

  • [fix] Support React 15.0.x
  • [fix] Fixes a bug in IE, because function.name is not available

0.4.1 / February 19 2016

  • [fix] Loosen up peer dependencies
  • [fix] Make the assertion messages lazy for shallow rendering

0.4.0 / February 8 2016

  • [feature] exactly matcher
  • [fix] Loosen cheerio dependency

0.3.0 / February 1 2016

  • [feature] Add support for components that return null
  • [feature] Throw if the passed objects are not an enzyme wrapper
  • [fix] Don't export to Babel's named default

0.2.2 / January 19 2016

  • [fix] Don't create el in constructor for shallow

0.2.1 / January 14 2016

  • [fix] Make the assertion messages lazy

0.2.0 / January 11 2016

  • [feature] Introduce aliases of empty/exist
  • [feature] tagName matcher

0.1.0 / January 6 2016

  • Initial implementation