Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save scmx/d98cc058a7c3dfef7890 to your computer and use it in GitHub Desktop.
Save scmx/d98cc058a7c3dfef7890 to your computer and use it in GitHub Desktop.
Make React PropType warnings throw errors with mocha.js, enzyme.js and sinon.js

Make React PropType warnings throw errors with enzyme.js + sinon.js + mocha.js

A simple stateless functional component that we want to test that it renders without propType warnings.

import React, { PropTypes } from 'react'

let VersionListItem = function ({ active, version }) {
  return (
    <a href='#' className={`list-group-item ${active}`}>
      <strong
        className='list-group-item-heading'>
        Version {version}
      </strong>
    </a>
  )
}
VersionListItem.propTypes = {
  active: PropTypes.string,
  version: PropTypes.number
}
export default VersionListItem
import { describe, it, before, after } from 'mocha'
import sinon from 'sinon'
import React from 'react'
import { shallow } from 'enzyme'
import VersionListItem from './version-list-item'

// Since react will console.error propType warnings, that which we'd rather have
// as errors, we use sinon.js to stub it into throwing these warning as errors
// instead.
before(() => {
  sinon.stub(console, 'error', (warning) => { throw new Error(warning) })
})
// While not forgetting to restore it afterwards
after(() => { console.error.restore() })

describe('<VersionListItem />', () => {
  const props = {
    active: 'active',
    version: 1
  }

  it('renders without error', () => {
    shallow(<VersionListItem {...props} />)
    // In this case there is no need for an assertion since we're only
    // interested in not getting any errors. And mocha will mark the test as a
    // failure if an error is thrown. :)
  })
})

Related reading:

@jgkingston
Copy link

jgkingston commented Dec 6, 2017

FWIW (and a bite late to the conversation), but I found this to be helpful in our test setup/helper file

import sinon from 'sinon';

const propTypeWarningMatch = sinon.match((warning) => {
  return typeof(warning) === 'string' &&
    warning.indexOf('Warning: Failed prop type:') > -1;
});

sinon.stub(console, 'error');

console.error.withArgs(propTypeWarningMatch).callsFake((warning) => {
  throw new ReferenceError(warning);
});

console.error.callThrough();

The .callThrough() is necessary to ensure console.error()'s default behavior is used for all warnings that don't match the custom match function.

@fatso83
Copy link

fatso83 commented Mar 14, 2018

@hulkish: that snippet doesn't actually fail any of my tests. Removing the process.nextTick fixes it.

Also, we removed the third parameter to #stub in Sinon 2 in favor of #callThrough(). @jgkingston's snippet is the way to go nowadays.

@lucasfcosta
Copy link

lucasfcosta commented Feb 14, 2019

To anyone a bit puzzled reading this in 2019

The process.nextTick will work, but it does not get triggered automatically since you are enqueueing that failure.

It's also important to notice that you shouldn't simply stub all the error messages as that would cause infinite recursion due to errors being thrown inside components which then get caught by boundaries. Boundaries then use using console.error, triggering themselves infinitely.

@jgkingston's approach is more accurate if you want to catch propType warnings only, however, remember to throw in a context which is not the component one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment