Skip to content

Commit

Permalink
fix: Input blur with invalidate value should back of validate one and…
Browse files Browse the repository at this point in the history
… trigger onChange (#589)

* fix: blur should back of value

* test: add test case
  • Loading branch information
zombieJ authored Aug 1, 2023
1 parent ebb8466 commit c242065
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 31 deletions.
10 changes: 7 additions & 3 deletions src/InputNumber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,10 @@ export interface InputNumberProps<T extends ValueType = ValueType>
// size?: ISize;
}

type InternalInputNumberProps = Omit<InputNumberProps, 'prefix' | 'suffix'>;

const InternalInputNumber = React.forwardRef(
(props: InputNumberProps, ref: React.Ref<HTMLInputElement>) => {
(props: InternalInputNumberProps, ref: React.Ref<HTMLInputElement>) => {
const {
prefixCls = 'rc-input-number',
className,
Expand Down Expand Up @@ -449,7 +451,9 @@ const InternalInputNumber = React.forwardRef(

// ============================ Flush =============================
/**
* Flush current input content to trigger value change & re-formatter input if needed
* Flush current input content to trigger value change & re-formatter input if needed.
* This will always flush input value for update.
* If it's invalidate, will fallback to last validate value.
*/
const flushInputValue = (userTyping: boolean) => {
const parsedValue = getMiniDecimal(mergedParser(inputValue));
Expand All @@ -460,7 +464,7 @@ const InternalInputNumber = React.forwardRef(
// Reassign the formatValue within ranged of trigger control
formatValue = triggerValueUpdate(parsedValue, userTyping);
} else {
formatValue = decimalValue;
formatValue = triggerValueUpdate(decimalValue, userTyping);
}

if (value !== undefined) {
Expand Down
86 changes: 58 additions & 28 deletions tests/input.test.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import React from 'react';
import { render, fireEvent } from './util/wrapper';
import KeyCode from 'rc-util/lib/KeyCode';
import React from 'react';
import InputNumber, { InputNumberProps } from '../src';
import { fireEvent, render } from './util/wrapper';

describe('InputNumber.Input', () => {
function loopInput(input: HTMLElement, text: string) {
for (let i = 0; i < text.length; i += 1) {
const inputTxt = text.slice(0, i + 1);
fireEvent.change(input, { target: { value: inputTxt } });
}
}

describe('InputNumber.Input', () => {
function prepareWrapper(text: string, props?: Partial<InputNumberProps>, skipInputCheck = false) {
function prepareWrapper(text: string, props?: Partial<InputNumberProps>, skipInputCheck = false) {
const { container } = render(<InputNumber {...props} />);
const input = container.querySelector('input')
fireEvent.focus(input)
const input = container.querySelector('input');
fireEvent.focus(input);
for (let i = 0; i < text.length; i += 1) {
const inputTxt = text.slice(0, i + 1);
fireEvent.change(input, { target: { value: inputTxt } });
Expand All @@ -16,8 +23,8 @@ describe('InputNumber.Input', () => {
if (!skipInputCheck) {
expect(input.value).toEqual(text);
}
fireEvent.blur(input)
return input
fireEvent.blur(input);
return input;
}

it('input valid number', () => {
Expand Down Expand Up @@ -59,28 +66,28 @@ describe('InputNumber.Input', () => {
});

it('negative min with higher precision', () => {
const wrapper = prepareWrapper('-4', {min: -3.5, precision: 0});
const wrapper = prepareWrapper('-4', { min: -3.5, precision: 0 });
expect(wrapper.value).toEqual('-3');
});

it('positive min with higher precision', () => {
const wrapper = prepareWrapper('4', {min: 3.5, precision: 0});
const wrapper = prepareWrapper('4', { min: 3.5, precision: 0 });
expect(wrapper.value).toEqual('4');
});

it('negative max with higher precision', () => {
const wrapper = prepareWrapper('-4', {max: -3.5, precision: 0});
const wrapper = prepareWrapper('-4', { max: -3.5, precision: 0 });
expect(wrapper.value).toEqual('-4');
});

it('positive max with higher precision', () => {
const wrapper = prepareWrapper('4', {max: 3.5, precision: 0});
const wrapper = prepareWrapper('4', { max: 3.5, precision: 0 });
expect(wrapper.value).toEqual('3');
});

// https://github.com/ant-design/ant-design/issues/9439
it('input negative zero', async () => {
const wrapper = await prepareWrapper('-0', {}, true);
const wrapper = await prepareWrapper('-0', {}, true);
expect(wrapper.value).toEqual('0');
});

Expand Down Expand Up @@ -108,8 +115,12 @@ describe('InputNumber.Input', () => {

it('pressEnter works', () => {
const onPressEnter = jest.fn();
const { container } = render(<InputNumber onPressEnter={onPressEnter} defaultValue={'5'}/>);
fireEvent.keyDown(container.querySelector('.rc-input-number'), { key: "Enter", keyCode: KeyCode.ENTER ,which:KeyCode.ENTER})
const { container } = render(<InputNumber onPressEnter={onPressEnter} defaultValue={'5'} />);
fireEvent.keyDown(container.querySelector('.rc-input-number'), {
key: 'Enter',
keyCode: KeyCode.ENTER,
which: KeyCode.ENTER,
});
expect(onPressEnter).toHaveBeenCalled();
expect(onPressEnter).toHaveBeenCalledTimes(1);
});
Expand All @@ -130,13 +141,13 @@ describe('InputNumber.Input', () => {
};

const { container } = render(<Demo />);
const input = container.querySelector('input')
fireEvent.focus(input)
const input = container.querySelector('input');
fireEvent.focus(input);
fireEvent.change(input, { target: { value: '3' } });
fireEvent.keyDown(input,{ which: KeyCode.ENTER })
fireEvent.keyDown(input, { which: KeyCode.ENTER });
expect(input.value).toEqual('3');
fireEvent.change(input, { target: { value: '5' } });
fireEvent.keyDown(input,{ which: KeyCode.ENTER })
fireEvent.keyDown(input, { which: KeyCode.ENTER });
expect(input.value).toEqual('5');
});

Expand All @@ -146,39 +157,58 @@ describe('InputNumber.Input', () => {
const Demo = () => {
const [value, setValue] = React.useState<string | number>(1);
outSetValue = setValue;
return <InputNumber autoFocus value={value} onChange={val => setValue(val)} />;
return <InputNumber autoFocus value={value} onChange={(val) => setValue(val)} />;
};

const { container } = render(<Demo />);
const input = container.querySelector('input')
fireEvent.keyDown(input,{ which: KeyCode.TAB })
fireEvent.blur(input)
const input = container.querySelector('input');
fireEvent.keyDown(input, { which: KeyCode.TAB });
fireEvent.blur(input);
expect(input.value).toEqual('1');
outSetValue(5);
fireEvent.focus(input)
fireEvent.focus(input);
expect(input.value).toEqual('5');
});

// https://github.com/ant-design/ant-design/issues/40733
it('input combo should be correct', () => {
const onChange = jest.fn();
const input = prepareWrapper('', {
onChange,
precision: 0,
});

onChange.mockReset();

fireEvent.focus(input);
loopInput(input, '1.55.55');
expect(onChange).not.toHaveBeenCalledWith(2);

fireEvent.blur(input);
expect(input.value).toEqual('2');
expect(onChange).toHaveBeenCalledWith(2);
});

describe('empty on blur should trigger null', () => {
it('basic', () => {
const onChange = jest.fn();
const { container } = render(<InputNumber defaultValue="1" onChange={onChange} />);
const input = container.querySelector('input')
const input = container.querySelector('input');
fireEvent.change(input, { target: { value: '' } });
expect(onChange).toHaveBeenCalledWith(null);

fireEvent.blur(input)
fireEvent.blur(input);
expect(onChange).toHaveBeenLastCalledWith(null);
});

it('min range', () => {
const onChange = jest.fn();
const { container } = render(<InputNumber min="1" defaultValue="11" onChange={onChange} />);
const input = container.querySelector('input')
const input = container.querySelector('input');
fireEvent.change(input, { target: { value: '' } });
expect(onChange).toHaveBeenCalled();

fireEvent.blur(input)
fireEvent.blur(input);
expect(onChange).toHaveBeenLastCalledWith(null);
});
});
Expand Down

1 comment on commit c242065

@vercel
Copy link

@vercel vercel bot commented on c242065 Aug 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.