/
NumberInput.test.tsx
194 lines (169 loc) · 7.01 KB
/
NumberInput.test.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { act } from 'react-dom/test-utils';
import {
checkAccessibility,
itSupportsSystemProps,
itSupportsInputProps,
itSupportsFocusEvents,
} from '@mantine/tests';
import { NumberInput, NumberInputHandlers, NumberInputProps } from './NumberInput';
const defaultProps: NumberInputProps = {};
const getRightSection = (container: HTMLElement) =>
container.querySelector('.mantine-NumberInput-rightSection');
const clickIncrement = (container: HTMLElement) =>
userEvent.click(container.querySelector('.mantine-NumberInput-controlUp'));
const clickDecrement = (container: HTMLElement) =>
userEvent.click(container.querySelector('.mantine-NumberInput-controlDown'));
const getInput = () => screen.getByRole('textbox');
const enterText = (text: string) => userEvent.type(getInput(), text);
const expectValue = (value: string) => expect(getInput()).toHaveValue(value);
const blurInput = () => fireEvent.blur(getInput());
describe('@mantine/core/NumberInput', () => {
checkAccessibility([
<NumberInput {...defaultProps} label="test" />,
<NumberInput {...defaultProps} aria-label="test" />,
]);
itSupportsSystemProps({
component: NumberInput,
props: defaultProps,
displayName: '@mantine/core/NumberInput',
refType: HTMLInputElement,
othersSelector: 'input',
providerName: 'NumberInput',
});
itSupportsInputProps(NumberInput, defaultProps, 'NumberInput');
itSupportsFocusEvents(NumberInput, defaultProps, 'input');
it('does not render rightSection if input is disabled, variant is unstyled or controls are hidden', () => {
const { container: regular } = render(<NumberInput {...defaultProps} />);
const { container: disabled } = render(<NumberInput {...defaultProps} disabled />);
const { container: controlsHidden } = render(<NumberInput {...defaultProps} hideControls />);
const { container: unstyled } = render(<NumberInput {...defaultProps} variant="unstyled" />);
expect(getRightSection(regular)).not.toBe(null);
expect(getRightSection(disabled)).toBe(null);
expect(getRightSection(controlsHidden)).toBe(null);
expect(getRightSection(unstyled)).toBe(null);
});
it('increments and decrements value with controls', async () => {
const spy = jest.fn();
const { container } = render(<NumberInput value={0} step={10} onChange={spy} />);
await clickIncrement(container);
expect(spy).toHaveBeenLastCalledWith(10);
await clickDecrement(container);
await clickDecrement(container);
expect(spy).toHaveBeenLastCalledWith(-10);
});
it('does not increment or decrements out of min and max', async () => {
const spy = jest.fn();
const { container } = render(
<NumberInput value={5} max={10} min={0} step={6} onChange={spy} />
);
await clickIncrement(container);
expect(spy).toHaveBeenLastCalledWith(10);
await clickDecrement(container);
await clickDecrement(container);
expect(spy).toHaveBeenLastCalledWith(0);
});
it('exposes increment/decrement handlers with handlersRef prop', () => {
const ref = React.createRef<NumberInputHandlers>();
const spy = jest.fn();
render(<NumberInput {...defaultProps} value={10} step={2} onChange={spy} handlersRef={ref} />);
expect(typeof ref.current.decrement).toBe('function');
expect(typeof ref.current.increment).toBe('function');
act(() => ref.current.decrement());
expect(spy).toHaveBeenLastCalledWith(8);
act(() => ref.current.increment());
expect(spy).toHaveBeenLastCalledWith(10);
});
it('returns undefined when input is empty', async () => {
const spy = jest.fn();
render(<NumberInput value={5} max={10} min={0} step={6} onChange={spy} />);
expectValue('5');
await enterText('{backspace}');
expect(spy).toHaveBeenLastCalledWith(undefined);
expectValue('');
});
it('clears input on blur when input is empty and a string is entered', async () => {
const spy = jest.fn();
render(<NumberInput max={10} min={0} step={6} onChange={spy} />);
await enterText('6');
expect(spy).toHaveBeenLastCalledWith(6);
await enterText('test');
blurInput();
expect(getInput()).toHaveValue('6');
expect(spy).toHaveBeenLastCalledWith(6);
});
it('supports changing decimal separator', async () => {
const spy = jest.fn();
render(<NumberInput max={10} min={0} step={6} onChange={spy} decimalSeparator="," />);
await enterText('6,54');
expect(spy).toHaveBeenLastCalledWith(6.54);
blurInput();
expect(getInput()).toHaveValue('7');
});
it('sets input value with a given precision', async () => {
const spy = jest.fn();
render(<NumberInput max={10} min={0} step={6} precision={2} onChange={spy} />);
await enterText('6.123');
expect(spy).toHaveBeenLastCalledWith(6.123);
blurInput();
expectValue('6.12');
expect(spy).toHaveBeenLastCalledWith(6.12);
});
it('supports removing trailing zeros with precision', async () => {
const spy = jest.fn();
render(<NumberInput precision={8} removePrecisionTrailingZeros onChange={spy} />);
await enterText('6.12300000');
expect(spy).toHaveBeenLastCalledWith(6.123);
blurInput();
expectValue('6.123');
expect(spy).toHaveBeenLastCalledWith(6.123);
});
it('sets state to min if input is empty and is incremented/decremented', async () => {
const spy = jest.fn();
const { container } = render(<NumberInput max={10} min={0} step={6} onChange={spy} />);
await clickIncrement(container);
expectValue('0');
expect(spy).toHaveBeenLastCalledWith(0);
await enterText('{backspace}');
await clickDecrement(container);
expectValue('0');
});
it('steps value with controls on hold keydown without stepHoldInterval', async () => {
const spy = jest.fn();
render(<NumberInput step={10} onChange={spy} defaultValue={0} />);
await enterText('{arrowup}');
expectValue('10');
expect(spy).toHaveBeenLastCalledWith(10);
await enterText('{arrowdown}');
expectValue('0');
expect(spy).toHaveBeenLastCalledWith(0);
});
it('allows "-" in an empty NumberInput', async () => {
const spy = jest.fn();
render(<NumberInput onChange={spy} />);
await enterText('-');
expect(getInput()).toHaveValue('-');
blurInput();
expect(getInput()).toHaveValue('');
await enterText('-1');
expect(spy).toHaveBeenLastCalledWith(-1);
});
it('only triggers onChange when value really changes', async () => {
const spy = jest.fn();
render(<NumberInput min={-3} onChange={spy} />);
await enterText('-');
expect(spy).not.toBeCalled();
await enterText('3');
expect(spy).toHaveBeenLastCalledWith(-3);
await enterText('{arrowdown}');
expect(spy).toBeCalledTimes(1);
});
it('uses startValue as first value when no initial value was set', async () => {
const spy = jest.fn();
render(<NumberInput startValue={3} onChange={spy} />);
await enterText('{arrowup}');
expect(getInput()).toHaveValue('3');
});
});