diff --git a/src/forms/TextInput.jsx b/src/forms/TextInput.jsx index 366398f72..c43bd4f90 100644 --- a/src/forms/TextInput.jsx +++ b/src/forms/TextInput.jsx @@ -5,80 +5,66 @@ import cx from 'classnames'; /** * @module TextInput */ -class TextInput extends React.Component { +const TextInput = (props) => { - constructor(props) { - super(props); - this.state = { - value: props.value || '', - }; - this.onChange = this.onChange.bind(this); - } + const { + name, + value, + label, + labelClassName, + className, + children, + error, + placeholder, + required, + id, + onChange, + isSearch, + maxLength, + pattern, + disabled, + ...other + } = props; - onChange(e) { - this.setState({ value: e.target.value }); - if (this.props.onChange) { - this.props.onChange(e); - } - } + const classNames = cx( + { 'field--error': error }, + className + ); - render() { - const { - name, - value, // eslint-disable-line no-unused-vars - label, - labelClassName, - className, - children, - error, - placeholder, - required, - id, - onChange, // eslint-disable-line no-unused-vars - isSearch, - maxLength, - pattern, - disabled - } = this.props; + const labelClassNames = cx( + 'label--field', + { required, disabled }, + labelClassName + ); - const classNames = cx( - { 'field--error': error }, - className - ); + return ( +
+ {label && + + } + - const labelClassNames = cx( - 'label--field', - { required, disabled }, - labelClassName - ); + { maxLength &&

{value.length} / {maxLength}

} - return ( -
- {label && - - } - - - { this.props.maxLength &&

{this.state.value.length} / {this.props.maxLength}

} - - { error &&

{error}

} - {children} -
- ); - } -} + { error &&

{error}

} + {children} +
+ ); +}; TextInput.propTypes = { name: PropTypes.string.isRequired, diff --git a/src/forms/textInput.test.jsx b/src/forms/textInput.test.jsx index d016644f4..5baa4aec8 100644 --- a/src/forms/textInput.test.jsx +++ b/src/forms/textInput.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; import TestUtils from 'react-addons-test-utils'; +import { TestWrapper } from '../utils/testUtils'; import TextInput from './TextInput'; describe('TextInput', function() { @@ -21,12 +22,14 @@ describe('TextInput', function() { required: true, }; textInputComponent = TestUtils.renderIntoDocument( - + + + ); inputEl = TestUtils.findRenderedDOMComponentWithTag(textInputComponent, 'input'); @@ -57,12 +60,14 @@ describe('TextInput', function() { it('should have input type search if `isSearch` is set to true', () => { textInputComponent = TestUtils.renderIntoDocument( - + + + ); inputEl = TestUtils.findRenderedDOMComponentWithTag(textInputComponent, 'input'); @@ -72,12 +77,14 @@ describe('TextInput', function() { it('should have a disabled attribute when specified', () => { textInputComponent = TestUtils.renderIntoDocument( - + + + ); inputEl = TestUtils.findRenderedDOMComponentWithTag(textInputComponent, 'input'); @@ -102,43 +109,17 @@ describe('TextInput', function() { expect(inputEl.getAttribute('maxLength')).toEqual(MAX_LEN); }); - it('should set its value on input change', function() { - const newValue = `${VALUE}r`; - expect(inputEl.value).toEqual(VALUE); - TestUtils.Simulate.change(inputEl, { target: { value: newValue } }); - expect(inputEl.value).toEqual(newValue); - }); - - it('should call onChange and setState with input change', function() { - const newValue = `${VALUE}r`; - const changeSpy = spyOn(TextInput.prototype, 'onChange').and.callThrough(); - const stateSpy = spyOn(TextInput.prototype, 'setState').and.callThrough(); - - const boundComponent = TestUtils.renderIntoDocument( - - ); - - inputEl = TestUtils.findRenderedDOMComponentWithTag(boundComponent, 'input'); - TestUtils.Simulate.change(inputEl, { target: { value: newValue } }); - - expect(changeSpy).toHaveBeenCalled(); - expect(stateSpy).toHaveBeenCalledWith({ value: newValue }); - }); - it('should call onChange `props` function when input is changed', () => { const newValue = `${VALUE}r`; const boundComponent = TestUtils.renderIntoDocument( - + + + ); inputEl = TestUtils.findRenderedDOMComponentWithTag(boundComponent, 'input'); TestUtils.Simulate.change(inputEl, { target: { value: newValue } }); diff --git a/src/utils/testUtils.js b/src/utils/testUtils.js index d5085b98e..d5e97b3cd 100644 --- a/src/utils/testUtils.js +++ b/src/utils/testUtils.js @@ -1,4 +1,5 @@ import React from 'react'; +import createReactClass from 'create-react-class'; import TestUtils from 'react-addons-test-utils'; export const variantTest = (FoundationComponent, className, variants) => { @@ -32,3 +33,13 @@ export const hasRoleAttribute = (el, roleName) => { export const componentHasProperty = (component, prop, value) => { expect(component && component.props && component.props[prop] === value).toBe(true); }; + +// Note: functional components need to be +// wrapped it in a stateful component to use TestUtils effectively +export const TestWrapper = createReactClass({ + render: function() { + return ( +
{this.props.children}
+ ); + } +}); diff --git a/yarn.lock b/yarn.lock index 1b3deddc9..51df245c1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3685,14 +3685,14 @@ js-tokens@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" -js-yaml@3.6.1, js-yaml@^3.4.3, js-yaml@^3.5.1: +js-yaml@3.6.1, js-yaml@^3.5.1: version "3.6.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" dependencies: argparse "^1.0.7" esprima "^2.6.0" -js-yaml@^3.7.0, js-yaml@~3.7.0: +js-yaml@^3.4.3, js-yaml@^3.7.0, js-yaml@~3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" dependencies: