Skip to content

Commit d8c760a

Browse files
committed
Add debounce timeout to account for user typing
1 parent a7eac5f commit d8c760a

2 files changed

Lines changed: 37 additions & 22 deletions

File tree

src/components/date_picker/super_date_picker/date_popover/absolute_tab.test.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import React from 'react';
10-
import { fireEvent } from '@testing-library/react';
10+
import { act, fireEvent } from '@testing-library/react';
1111
import { render } from '../../../../test/rtl';
1212

1313
import { EuiAbsoluteTab } from './absolute_tab';
@@ -29,15 +29,23 @@ describe('EuiAbsoluteTab', () => {
2929
};
3030

3131
describe('user input', () => {
32+
beforeAll(() => jest.useFakeTimers());
33+
afterAll(() => jest.useRealTimers());
34+
35+
const changeInput = (input: HTMLElement, value: string) => {
36+
fireEvent.change(input, { target: { value } });
37+
act(() => {
38+
jest.advanceTimersByTime(1000); // Debounce timer
39+
});
40+
};
41+
3242
it('parses the passed `dateFormat` prop', () => {
3343
const { getByTestSubject } = render(
3444
<EuiAbsoluteTab {...props} dateFormat="MMM Do YY" />
3545
);
3646
const input = getByTestSubject('superDatePickerAbsoluteDateInput');
3747

38-
fireEvent.change(input, {
39-
target: { value: 'Jan 31st 01' },
40-
});
48+
changeInput(input, 'Jan 31st 01');
4149
expect(input).not.toBeInvalid();
4250
expect(input).toHaveValue('Jan 31st 01');
4351
});
@@ -52,9 +60,7 @@ describe('EuiAbsoluteTab', () => {
5260
const { getByTestSubject } = render(<EuiAbsoluteTab {...props} />);
5361
const input = getByTestSubject('superDatePickerAbsoluteDateInput');
5462

55-
fireEvent.change(input, {
56-
target: { value: '1970-01-01T12:00:00+00:00' },
57-
});
63+
changeInput(input, '1970-01-01T12:00:00+00:00');
5864
expect(input).not.toBeInvalid();
5965
assertOutput(input as HTMLInputElement);
6066
});
@@ -63,9 +69,7 @@ describe('EuiAbsoluteTab', () => {
6369
const { getByTestSubject } = render(<EuiAbsoluteTab {...props} />);
6470
const input = getByTestSubject('superDatePickerAbsoluteDateInput');
6571

66-
fireEvent.change(input, {
67-
target: { value: 'Thu, 1 Jan 1970 12:00:00 +0000' },
68-
});
72+
changeInput(input, 'Thu, 1 Jan 1970 12:00:00 +0000');
6973
expect(input).not.toBeInvalid();
7074
assertOutput(input as HTMLInputElement);
7175
});
@@ -74,10 +78,10 @@ describe('EuiAbsoluteTab', () => {
7478
const { getByTestSubject } = render(<EuiAbsoluteTab {...props} />);
7579
const input = getByTestSubject('superDatePickerAbsoluteDateInput');
7680

77-
fireEvent.change(input, { target: { value: Date.now().toString() } });
81+
changeInput(input, Date.now().toString());
7882
expect(input).not.toBeInvalid();
7983

80-
fireEvent.change(input, { target: { value: '43200' } });
84+
changeInput(input, '43200');
8185
expect(input).not.toBeInvalid();
8286
assertOutput(input as HTMLInputElement);
8387
});
@@ -87,15 +91,15 @@ describe('EuiAbsoluteTab', () => {
8791
const { getByTestSubject } = render(<EuiAbsoluteTab {...props} />);
8892
const input = getByTestSubject('superDatePickerAbsoluteDateInput');
8993

90-
fireEvent.change(input, { target: { value: '01-01-1970' } });
94+
changeInput(input, '01-01-1970');
9195
expect(input).toHaveValue('01-01-1970');
9296
expect(input).toBeInvalid();
9397

94-
fireEvent.change(input, { target: { value: 'asdfasdf' } });
98+
changeInput(input, 'asdfasdf');
9599
expect(input).toHaveValue('asdfasdf');
96100
expect(input).toBeInvalid();
97101

98-
fireEvent.change(input, { target: { value: '' } });
102+
changeInput(input, '');
99103
expect(input).toHaveValue('');
100104
expect(input).toBeInvalid();
101105
});

src/components/date_picker/super_date_picker/date_popover/absolute_tab.tsx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Side Public License, v 1.
77
*/
88

9-
import React, { Component, ChangeEventHandler } from 'react';
9+
import React, { Component, ChangeEvent } from 'react';
1010

1111
import moment, { Moment, LocaleSpecifier } from 'moment'; // eslint-disable-line import/named
1212

@@ -84,26 +84,37 @@ export class EuiAbsoluteTab extends Component<
8484
});
8585
};
8686

87-
handleTextChange: ChangeEventHandler<HTMLInputElement> = (event) => {
87+
debouncedTypeTimeout: ReturnType<typeof setTimeout> | undefined;
88+
89+
handleTextChange = (event: ChangeEvent<HTMLInputElement>) => {
90+
this.setState({ textInputValue: event.target.value });
91+
92+
// Add a debouncer that gives the user some time to finish typing
93+
// before attempting to parse the text as a timestamp. Otherwise,
94+
// typing a single digit gets parsed as a unix timestamp 😬
95+
clearTimeout(this.debouncedTypeTimeout);
96+
this.debouncedTypeTimeout = setTimeout(this.parseUserDateInput, 1000); // 1 second debounce
97+
};
98+
99+
parseUserDateInput = () => {
88100
const { onChange, dateFormat } = this.props;
89-
const userInput = event.target.value;
101+
const { textInputValue } = this.state;
90102

91103
const invalidDateState = {
92-
textInputValue: userInput,
93104
isTextInvalid: true,
94105
valueAsMoment: null,
95106
};
96-
if (!userInput) {
107+
if (!textInputValue) {
97108
return this.setState(invalidDateState);
98109
}
99110

100111
// Attempt to parse with passed `dateFormat`
101-
let valueAsMoment = moment(userInput, dateFormat, true);
112+
let valueAsMoment = moment(textInputValue, dateFormat, true);
102113
let dateIsValid = valueAsMoment.isValid();
103114

104115
// If not valid, try a few other other standardized formats
105116
if (!dateIsValid) {
106-
valueAsMoment = moment(userInput, ALLOWED_USER_DATE_FORMATS, true);
117+
valueAsMoment = moment(textInputValue, ALLOWED_USER_DATE_FORMATS, true);
107118
dateIsValid = valueAsMoment.isValid();
108119
}
109120

0 commit comments

Comments
 (0)