Skip to content

Instantly share code, notes, and snippets.

@cirocosta
Last active September 15, 2016 09:05
Show Gist options
  • Save cirocosta/71046452d3ace8c11bb5 to your computer and use it in GitHub Desktop.
Save cirocosta/71046452d3ace8c11bb5 to your computer and use it in GitHub Desktop.
propTypes validation mixin - ReactJS
'use strict';
require('harmony-reflect');
/**
* Here we should not use 'harmony-reflect', but
* es6 proxies directly from a harmony
* implementation. Traceur-compiler /
* react-tools es6 transform dont provide
* proxies as the implementation would affect
* other things performance.
*/
var PropertyValidationMixin = {
getInitialState () {
var propTypes = this._descriptor.type.propTypes;
var rawProps = this.props;
var component = this;
this.props = new Proxy(rawProps, {
get: (obj, prop, receiver) => {
if (prop === 'ref' || prop === 'key')
throw new Error('Shouldn\'t be defining props for ' + prop);
if (!(prop in propTypes))
throw new Error(prop + ' not specified in propTypes.');
return Reflect.get(obj, prop, receiver);
}
});
return {};
}
};
module.exports = PropertyValidationMixin;
/**
* @jsx React.DOM
*/
'use strict';
jest.dontMock('../src/SwapCheckbox.jsx');
jest.dontMock('harmony-reflect');
describe('SwapCheckbox', function() {
it('should change the text after click', function() {
var React = require('react/addons');
var SwapCheckbox = require('../src/SwapCheckbox.jsx');
var TestUtils = React.addons.TestUtils;
var checkbox = TestUtils.renderIntoDocument(
<SwapCheckbox labelOn="On"
labelOff="Off" />
);
var label = TestUtils.findRenderedDOMComponentWithTag(
checkbox,
'label'
);
expect(label.getDOMNode().textContent).toEqual('Off');
});
});
/**
* @jsx React.DOM
*/
'use strict';
var React = require('react/addons');
var PropertyValidationMixin = require('./PropertyValidationMixin.jsx');
var SwapCheckbox = React.createClass({
propTypes: {
labelOn: React.PropTypes.string.isRequired,
// labelOff: React.PropTypes.string.isRequired
},
getInitialState () {
return {
isChecked: false
};
},
mixins: (() => {
return process.env.NODE_ENV === 'development' ?
[PropertyValidationMixin] :
[];
})(),
handleChange () {
this.setState({
isChecked: !this.state.isChecked
});
},
render () {
return (
<label>
<input type="checkbox"
checked={this.state.isChecked}
onChange={this.handleChange} />
{this.state.isChecked ? this.props.labelOn : this.props.labelOff }
</label>
);
}
});
module.exports = SwapCheckbox;
@cirocosta
Copy link
Author

Removing labelOff propType will lead our tests to fail (if running our tests with NODE_ENV=development ./node_modules/jest/bin/jest), as expected
fail

The interesting part of this is that it makes cli-ready, which let's us automate the process of checking if we are defining properly the propTypes for our components

@cirocosta
Copy link
Author

If we'd like to avoid the previous construction, using mixins and relying on Proxy, we could simply check in our tests (supposing that we are actually implementing a reasonable coverage of tests):

  it('should have implemented all propTypes',() => {
    var instance = TestUtils.renderIntoDocument(
      <SwapCheckbox labelOn="On"
                    labelOff="Off" />
    );

    var propTypes = Object.keys(instance.constructor.propTypes);
    var not = Object.keys(instance.props).filter((elem) =>
      !~propTypes.indexOf(elem));

    expect(not.length).toEqual(0);
  });

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