From be150158b05c0d5b2f1f4057582d9278c9f4c8d8 Mon Sep 17 00:00:00 2001 From: Luis Correia Date: Mon, 11 Feb 2019 18:00:40 +0000 Subject: [PATCH] fix(widget-number): fix empty value handling for number input (#2077) --- .../src/NumberControl.js | 10 +- .../src/__tests__/number.spec.js | 120 ++++++++++++++++++ 2 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 packages/netlify-cms-widget-number/src/__tests__/number.spec.js diff --git a/packages/netlify-cms-widget-number/src/NumberControl.js b/packages/netlify-cms-widget-number/src/NumberControl.js index be6e7c61..78aa970d 100644 --- a/packages/netlify-cms-widget-number/src/NumberControl.js +++ b/packages/netlify-cms-widget-number/src/NumberControl.js @@ -26,12 +26,12 @@ export default class NumberControl extends React.Component { handleChange = e => { const valueType = this.props.field.get('valueType'); const { onChange } = this.props; - if (valueType === 'int') { - onChange(parseInt(e.target.value, 10)); - } else if (valueType === 'float') { - onChange(parseFloat(e.target.value)); + const value = valueType === 'float' ? parseFloat(e.target.value) : parseInt(e.target.value, 10); + + if (!isNaN(value)) { + onChange(value); } else { - onChange(e.target.value); + onChange(''); } }; diff --git a/packages/netlify-cms-widget-number/src/__tests__/number.spec.js b/packages/netlify-cms-widget-number/src/__tests__/number.spec.js new file mode 100644 index 00000000..00fc8f04 --- /dev/null +++ b/packages/netlify-cms-widget-number/src/__tests__/number.spec.js @@ -0,0 +1,120 @@ +import React from 'react'; +import { fromJS } from 'immutable'; +import { render, fireEvent } from 'react-testing-library'; +import 'react-testing-library/cleanup-after-each'; +import 'jest-dom/extend-expect'; +import { NumberControl } from '../'; + +const fieldSettings = { + min: -20, + max: 20, + step: 1, + valueType: 'int', +}; + +class NumberController extends React.Component { + state = { + value: this.props.defaultValue, + }; + + handleOnChange = jest.fn(value => { + this.setState({ value }); + }); + + componentDidUpdate() { + this.props.onStateChange(this.state); + } + + render() { + return this.props.children({ + value: this.state.value, + handleOnChange: this.handleOnChange, + }); + } +} + +function setup({ field, defaultValue }) { + let renderArgs; + const stateChangeSpy = jest.fn(); + const setActiveSpy = jest.fn(); + const setInactiveSpy = jest.fn(); + + const helpers = render( + + {({ value, handleOnChange }) => { + renderArgs = { value, onChangeSpy: handleOnChange }; + return ( + + ); + }} + , + ); + + const input = helpers.container.querySelector('input'); + + return { + ...helpers, + ...renderArgs, + stateChangeSpy, + setActiveSpy, + setInactiveSpy, + input, + }; +} + +describe('Number widget', () => { + it('should call onChange when input changes', () => { + const field = fromJS(fieldSettings); + const testValue = Math.floor(Math.random() * (20 - -20 + 1)) + -20; + const { input, onChangeSpy } = setup({ field }); + + fireEvent.focus(input); + fireEvent.change(input, { target: { value: String(testValue) } }); + + expect(onChangeSpy).toHaveBeenCalledTimes(1); + expect(onChangeSpy).toHaveBeenCalledWith(testValue); + }); + + it('should call onChange with empty string when no value is set', () => { + const field = fromJS(fieldSettings); + const { input, onChangeSpy } = setup({ field, defaultValue: 20 }); + + fireEvent.focus(input); + fireEvent.change(input, { target: { value: '' } }); + + expect(onChangeSpy).toHaveBeenCalledTimes(1); + expect(onChangeSpy).toHaveBeenCalledWith(''); + }); + + it('should call onChange with empty string when a non numeric value is set', () => { + const field = fromJS(fieldSettings); + const { input, onChangeSpy } = setup({ field, defaultValue: 20 }); + + fireEvent.focus(input); + fireEvent.change(input, { target: { value: 'invalid' } }); + + expect(onChangeSpy).toHaveBeenCalledTimes(1); + expect(onChangeSpy).toHaveBeenCalledWith(''); + }); + + it('should parse float numbers as integers', () => { + const field = fromJS(fieldSettings); + const testValue = (Math.random() * (20 - -20 + 1) + -20).toFixed(2); + const { input, onChangeSpy } = setup({ field }); + + fireEvent.focus(input); + fireEvent.change(input, { target: { value: String(testValue) } }); + + expect(onChangeSpy).toHaveBeenCalledTimes(1); + expect(onChangeSpy).toHaveBeenCalledWith(parseInt(testValue, 10)); + }); +});