From e91135cf19b275deff679349bcc5e0d4ccedaac2 Mon Sep 17 00:00:00 2001
From: Victor Marin <36818606+mdvictor@users.noreply.github.com>
Date: Tue, 18 Oct 2022 16:59:34 +0300
Subject: [PATCH] Fix NumberInput empty values (#57142)
* Fix NumberInput empty values
* tests
* tests
---
.../components/OptionsUI/NumberInput.test.tsx | 110 ++++++++++++++++++
.../core/components/OptionsUI/NumberInput.tsx | 36 +++---
2 files changed, 127 insertions(+), 19 deletions(-)
create mode 100644 public/app/core/components/OptionsUI/NumberInput.test.tsx
diff --git a/public/app/core/components/OptionsUI/NumberInput.test.tsx b/public/app/core/components/OptionsUI/NumberInput.test.tsx
new file mode 100644
index 00000000000..2538f17aa14
--- /dev/null
+++ b/public/app/core/components/OptionsUI/NumberInput.test.tsx
@@ -0,0 +1,110 @@
+import { render, screen, fireEvent } from '@testing-library/react';
+import React from 'react';
+
+import { NumberInput } from './NumberInput';
+
+const setup = (min?: number, max?: number) => {
+ const onChange = jest.fn();
+ render();
+ return {
+ input: screen.getByTestId('input-wrapper').firstChild?.firstChild as HTMLInputElement,
+ onChange,
+ };
+};
+
+describe('NumberInput', () => {
+ it('updated input correctly', () => {
+ const data = setup();
+
+ const tests = [
+ {
+ value: '-10',
+ expected: -10,
+ onChangeCalledWith: -10,
+ },
+ {
+ value: '',
+ expected: null,
+ onChangeCalledWith: undefined,
+ },
+ {
+ value: '100',
+ expected: 100,
+ onChangeCalledWith: 100,
+ },
+ {
+ value: '1asd',
+ expected: null,
+ onChangeCalledWith: undefined,
+ },
+ {
+ value: -100,
+ expected: -100,
+ onChangeCalledWith: -100,
+ },
+ {
+ value: 20,
+ expected: 20,
+ onChangeCalledWith: 20,
+ },
+ {
+ value: 0,
+ expected: 0,
+ onChangeCalledWith: 0,
+ },
+ {
+ value: '0',
+ expected: 0,
+ onChangeCalledWith: 0,
+ },
+ ];
+
+ tests.forEach((test, i) => {
+ fireEvent.blur(data.input, { target: { value: test.value } });
+ expect(data.onChange).toBeCalledWith(test.onChangeCalledWith);
+ expect(data.onChange).toBeCalledTimes(i + 1);
+ expect(data.input).toHaveValue(test.expected);
+ });
+ });
+
+ it('corrects input as per min and max', async () => {
+ const data = setup(-10, 10);
+ let input = data.input;
+
+ const tests = [
+ {
+ value: '-10',
+ expected: -10,
+ onChangeCalledWith: -10,
+ },
+ {
+ value: '-100',
+ expected: -10,
+ onChangeCalledWith: -10,
+ },
+ {
+ value: '10',
+ expected: 10,
+ onChangeCalledWith: 10,
+ },
+ {
+ value: '100',
+ expected: 10,
+ onChangeCalledWith: 10,
+ },
+ {
+ value: '5',
+ expected: 5,
+ onChangeCalledWith: 5,
+ },
+ ];
+
+ tests.forEach((test, i) => {
+ input = screen.getByTestId('input-wrapper').firstChild?.firstChild as HTMLInputElement;
+ fireEvent.blur(input, { target: { value: test.value } });
+ expect(data.onChange).toBeCalledWith(test.onChangeCalledWith);
+ expect(data.onChange).toBeCalledTimes(i + 1);
+ expect(screen.getByTestId('input-wrapper').firstChild?.firstChild).toHaveValue(test.expected);
+ });
+ });
+});
diff --git a/public/app/core/components/OptionsUI/NumberInput.tsx b/public/app/core/components/OptionsUI/NumberInput.tsx
index 2cd0007b0c7..c507b421f48 100644
--- a/public/app/core/components/OptionsUI/NumberInput.tsx
+++ b/public/app/core/components/OptionsUI/NumberInput.tsx
@@ -50,33 +50,31 @@ export class NumberInput extends PureComponent {
let newValue = '';
const min = this.props.min;
const max = this.props.max;
- const currentValue = txt && +txt;
+ let currentValue = txt !== '' ? Number(txt) : undefined;
- if (currentValue) {
- if (!Number.isNaN(currentValue)) {
- if (min != null && currentValue < min) {
- newValue = min.toString();
- corrected = true;
- } else if (max != null && currentValue > max) {
- newValue = max.toString();
- corrected = true;
- } else {
- newValue = txt;
- }
+ if (currentValue && !Number.isNaN(currentValue)) {
+ if (min != null && currentValue < min) {
+ newValue = min.toString();
+ corrected = true;
+ } else if (max != null && currentValue > max) {
+ newValue = max.toString();
+ corrected = true;
+ } else {
+ newValue = txt ?? '';
}
this.setState({
- text: newValue || '',
+ text: newValue,
inputCorrected: corrected,
});
+ }
- if (corrected) {
- this.updateValueDebounced();
- }
+ if (corrected) {
+ this.updateValueDebounced();
+ }
- if (!isNaN(currentValue) && currentValue !== this.props.value) {
- this.props.onChange(currentValue);
- }
+ if (!Number.isNaN(currentValue) && currentValue !== this.props.value) {
+ this.props.onChange(currentValue);
}
};