@transferwise/components 0.0.0-experimental-e3e9aac → 0.0.0-experimental-b795207
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.js +180 -197
- package/build/index.js.map +1 -1
- package/build/index.mjs +174 -191
- package/build/index.mjs.map +1 -1
- package/build/types/accordion/AccordionItem/AccordionItem.d.ts.map +1 -1
- package/build/types/common/hooks/useMedia.d.ts.map +1 -1
- package/build/types/common/panel/Panel.d.ts.map +1 -1
- package/build/types/common/responsivePanel/ResponsivePanel.d.ts.map +1 -1
- package/build/types/dimmer/Dimmer.d.ts +1 -11
- package/build/types/dimmer/Dimmer.d.ts.map +1 -1
- package/build/types/drawer/Drawer.d.ts +4 -4
- package/build/types/index.d.ts +3 -2
- package/build/types/index.d.ts.map +1 -1
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/modal/Modal.d.ts.map +1 -1
- package/build/types/processIndicator/ProcessIndicator.d.ts +36 -19
- package/build/types/processIndicator/ProcessIndicator.d.ts.map +1 -1
- package/build/types/processIndicator/index.d.ts +2 -2
- package/build/types/processIndicator/index.d.ts.map +1 -1
- package/build/types/promoCard/PromoCard.d.ts.map +1 -1
- package/build/types/select/searchBox/SearchBox.d.ts +1 -1
- package/build/types/snackbar/Snackbar.d.ts +1 -3
- package/build/types/snackbar/Snackbar.d.ts.map +1 -1
- package/build/types/test-utils/wait.d.ts +2 -0
- package/build/types/test-utils/wait.d.ts.map +1 -0
- package/build/types/tooltip/Tooltip.d.ts +1 -1
- package/build/types/tooltip/Tooltip.d.ts.map +1 -1
- package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
- package/build/types/withDisplayFormat/WithDisplayFormat.d.ts.map +1 -1
- package/package.json +12 -16
- package/src/accordion/AccordionItem/AccordionItem.tsx +2 -4
- package/src/avatarWrapper/AvatarWrapper.story.tsx +1 -3
- package/src/button/Button.tsx +1 -1
- package/src/common/hooks/useConditionalListener/useConditionalListener.spec.js +1 -1
- package/src/common/hooks/useHasIntersected/useHasIntersected.spec.js +3 -3
- package/src/common/hooks/useMedia.spec.ts +1 -1
- package/src/common/hooks/useMedia.ts +1 -2
- package/src/common/panel/Panel.tsx +90 -92
- package/src/common/responsivePanel/ResponsivePanel.tsx +34 -38
- package/src/dateLookup/DateLookup.rtl.spec.tsx +181 -5
- package/src/dateLookup/DateLookup.testingLibrary.spec.js +171 -124
- package/src/drawer/Drawer.js +3 -3
- package/src/field/Field.tsx +3 -3
- package/src/index.ts +3 -2
- package/src/inputs/SelectInput.story.tsx +3 -2
- package/src/inputs/SelectInput.tsx +10 -2
- package/src/modal/Modal.tsx +1 -2
- package/src/processIndicator/ProcessIndicator.rtl.spec.tsx +45 -0
- package/src/processIndicator/ProcessIndicator.tsx +110 -0
- package/src/promoCard/PromoCard.tsx +1 -2
- package/src/radio/__snapshots__/Radio.rtl.spec.tsx.snap +0 -1
- package/src/snackbar/Snackbar.spec.js +112 -0
- package/src/snackbar/Snackbar.story.tsx +100 -18
- package/src/snackbar/Snackbar.tsx +13 -9
- package/src/tabs/Tabs.spec.js +46 -27
- package/src/test-utils/index.js +5 -7
- package/src/test-utils/jest.setup.js +9 -3
- package/src/test-utils/wait.ts +7 -0
- package/src/tooltip/Tooltip.tsx +44 -46
- package/src/tooltip/__snapshots__/Tooltip.spec.tsx.snap +2 -2
- package/src/upload/Upload.spec.js +34 -13
- package/src/uploadInput/UploadInput.spec.tsx +21 -23
- package/src/uploadInput/uploadItem/UploadItem.tsx +1 -3
- package/src/withDisplayFormat/WithDisplayFormat.spec.js +63 -32
- package/src/withDisplayFormat/WithDisplayFormat.tsx +4 -6
- package/src/dateLookup/DateLookup.keyboardEvents.spec.js +0 -180
- package/src/processIndicator/ProcessIndicator.js +0 -117
- package/src/processIndicator/ProcessIndicator.spec.js +0 -101
- package/src/snackbar/Snackbar.tests.story.tsx +0 -284
- /package/src/processIndicator/{index.js → index.ts} +0 -0
|
@@ -6,14 +6,14 @@ exports[`Tooltip Component renders an empty list when no items are passed 1`] =
|
|
|
6
6
|
class="tw-tooltip-container"
|
|
7
7
|
>
|
|
8
8
|
<span
|
|
9
|
-
aria-describedby="
|
|
9
|
+
aria-describedby=":r0:-tooltip"
|
|
10
10
|
>
|
|
11
11
|
Hover me
|
|
12
12
|
</span>
|
|
13
13
|
<div
|
|
14
14
|
aria-hidden="true"
|
|
15
15
|
class="np-tooltip np-panel"
|
|
16
|
-
id="
|
|
16
|
+
id=":r0:-tooltip"
|
|
17
17
|
role="tooltip"
|
|
18
18
|
style="position: absolute; left: 0px; top: 0px;"
|
|
19
19
|
>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { shallow, mount } from 'enzyme';
|
|
2
|
+
import { act } from 'react';
|
|
2
3
|
|
|
3
4
|
import { ANIMATION_DURATION_IN_MS } from '../processIndicator';
|
|
4
5
|
|
|
@@ -6,7 +7,6 @@ import { CompleteStep, UploadImageStep, MediaUploadStep, ProcessingStep } from '
|
|
|
6
7
|
|
|
7
8
|
import Upload from '.';
|
|
8
9
|
|
|
9
|
-
jest.useFakeTimers();
|
|
10
10
|
jest.mock('./utils/postData', () => ({
|
|
11
11
|
postData: async () => 'ServerResponse',
|
|
12
12
|
}));
|
|
@@ -15,12 +15,12 @@ jest.mock('./utils/asyncFileRead');
|
|
|
15
15
|
const { asyncFileRead } = require('./utils/asyncFileRead');
|
|
16
16
|
|
|
17
17
|
const defaultLocale = 'en-GB';
|
|
18
|
-
const formatMessage = (id) =>
|
|
18
|
+
const formatMessage = (id) => String(id);
|
|
19
19
|
jest.mock('react-intl', () => ({
|
|
20
20
|
injectIntl: (Component) =>
|
|
21
21
|
function (props) {
|
|
22
22
|
return (
|
|
23
|
-
<Component {...props} intl={{ locale: defaultLocale, formatMessage: (id) =>
|
|
23
|
+
<Component {...props} intl={{ locale: defaultLocale, formatMessage: (id) => String(id) }} />
|
|
24
24
|
);
|
|
25
25
|
},
|
|
26
26
|
useIntl: () => ({ formatMessage }),
|
|
@@ -87,11 +87,14 @@ const COMPLETED_STEP_PROPS = {
|
|
|
87
87
|
describe('Upload', () => {
|
|
88
88
|
let component;
|
|
89
89
|
beforeEach(() => {
|
|
90
|
+
jest.useFakeTimers();
|
|
90
91
|
component = shallow(<Upload {...props} />).dive();
|
|
91
92
|
asyncFileRead.mockImplementation(async () => 'a value');
|
|
92
93
|
});
|
|
93
94
|
|
|
94
|
-
afterEach(() => {
|
|
95
|
+
afterEach(async () => {
|
|
96
|
+
await jest.runOnlyPendingTimersAsync();
|
|
97
|
+
jest.useRealTimers();
|
|
95
98
|
jest.clearAllMocks();
|
|
96
99
|
jest.clearAllTimers();
|
|
97
100
|
});
|
|
@@ -213,6 +216,14 @@ describe('Upload', () => {
|
|
|
213
216
|
});
|
|
214
217
|
|
|
215
218
|
describe('when file is processed', () => {
|
|
219
|
+
const waitForUpload = async () => {
|
|
220
|
+
for (let i = 0; i < 4; i += 1) {
|
|
221
|
+
await act(async () => {
|
|
222
|
+
await jest.runOnlyPendingTimersAsync();
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
216
227
|
it('step changes from UploadImageStep to CompleteStep', async () => {
|
|
217
228
|
component = mount(<Upload {...props} />);
|
|
218
229
|
const upload = component.children();
|
|
@@ -220,8 +231,10 @@ describe('Upload', () => {
|
|
|
220
231
|
expect(upload.find(ProcessingStep)).toHaveLength(0);
|
|
221
232
|
expect(upload.find(CompleteStep)).toHaveLength(0);
|
|
222
233
|
|
|
223
|
-
await
|
|
224
|
-
|
|
234
|
+
await act(async () => {
|
|
235
|
+
await upload.instance().fileDropped(TEST_FILE);
|
|
236
|
+
});
|
|
237
|
+
await waitForUpload();
|
|
225
238
|
component.update();
|
|
226
239
|
|
|
227
240
|
expect(component.find(UploadImageStep)).toHaveLength(0);
|
|
@@ -236,8 +249,10 @@ describe('Upload', () => {
|
|
|
236
249
|
throw 'An error';
|
|
237
250
|
});
|
|
238
251
|
|
|
239
|
-
await
|
|
240
|
-
|
|
252
|
+
await act(async () => {
|
|
253
|
+
await upload.instance().fileDropped(TEST_FILE);
|
|
254
|
+
});
|
|
255
|
+
await waitForUpload();
|
|
241
256
|
component.update();
|
|
242
257
|
|
|
243
258
|
expect(component.find(CompleteStep).props()).toStrictEqual({
|
|
@@ -252,8 +267,10 @@ describe('Upload', () => {
|
|
|
252
267
|
it('onSuccess is called with response when httpOptions are provided', async () => {
|
|
253
268
|
component = mount(<Upload {...props} httpOptions={{ url: 'a-url' }} />).children();
|
|
254
269
|
|
|
255
|
-
await
|
|
256
|
-
|
|
270
|
+
await act(async () => {
|
|
271
|
+
await component.instance().fileDropped(TEST_FILE);
|
|
272
|
+
});
|
|
273
|
+
await waitForUpload();
|
|
257
274
|
|
|
258
275
|
expect(props.onSuccess).toHaveBeenCalledWith('ServerResponse', TEST_FILE.name);
|
|
259
276
|
});
|
|
@@ -261,11 +278,15 @@ describe('Upload', () => {
|
|
|
261
278
|
it('wont process new file while current process is in progress', async () => {
|
|
262
279
|
component = mount(<Upload {...props} httpOptions={{ url: 'a-url' }} />).children();
|
|
263
280
|
|
|
264
|
-
await
|
|
265
|
-
|
|
266
|
-
|
|
281
|
+
await act(async () => {
|
|
282
|
+
await component.instance().fileDropped(TEST_FILE);
|
|
283
|
+
});
|
|
284
|
+
const result = await act(async () => component.instance().fileDropped(TEST_FILE));
|
|
267
285
|
|
|
268
286
|
expect(result).toBe(false);
|
|
287
|
+
|
|
288
|
+
await waitForUpload();
|
|
289
|
+
|
|
269
290
|
expect(props.onSuccess).toHaveBeenCalledTimes(1);
|
|
270
291
|
});
|
|
271
292
|
});
|
|
@@ -7,8 +7,7 @@ import { mockMatchMedia, render, screen, waitFor, waitForElementToBeRemoved } fr
|
|
|
7
7
|
import UploadInput, { UploadInputProps } from './UploadInput';
|
|
8
8
|
import { TEST_IDS as UPLOAD_BUTTON_TEST_IDS } from './uploadButton/UploadButton';
|
|
9
9
|
import { TEST_IDS as UPLOAD_ITEM_TEST_IDS } from './uploadItem/UploadItem';
|
|
10
|
-
|
|
11
|
-
const spiedDateObject = jest.spyOn(global, 'Date');
|
|
10
|
+
import { act } from 'react';
|
|
12
11
|
|
|
13
12
|
mockMatchMedia();
|
|
14
13
|
|
|
@@ -42,43 +41,35 @@ describe('UploadInput', () => {
|
|
|
42
41
|
render(<UploadInput {...customProps} />);
|
|
43
42
|
|
|
44
43
|
beforeEach(() => {
|
|
45
|
-
|
|
46
|
-
getTime: jest.fn().mockReturnValue(Math.random()),
|
|
47
|
-
}));
|
|
44
|
+
jest.useFakeTimers();
|
|
48
45
|
});
|
|
49
46
|
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
afterEach(async () => {
|
|
48
|
+
await jest.runOnlyPendingTimersAsync();
|
|
49
|
+
jest.useRealTimers();
|
|
52
50
|
});
|
|
53
51
|
|
|
54
52
|
describe('single file upload', () => {
|
|
55
53
|
it('should trigger onUploadFiles & onFilesChange with a single FormData entry containing `file` field', async () => {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
(spiedDateObject as jest.Mock).mockImplementation(() => ({
|
|
59
|
-
getTime: jest
|
|
60
|
-
.fn()
|
|
61
|
-
.mockReturnValueOnce(mockTimeStampValue1)
|
|
62
|
-
.mockReturnValueOnce(mockTimeStampValue2),
|
|
63
|
-
}));
|
|
54
|
+
const date = Date.now();
|
|
55
|
+
jest.setSystemTime(date);
|
|
64
56
|
|
|
65
57
|
const onFilesChange = jest.fn();
|
|
66
58
|
renderComponent({ ...props, onFilesChange });
|
|
67
59
|
|
|
68
60
|
const input = screen.getByTestId(UPLOAD_BUTTON_TEST_IDS.uploadInput);
|
|
69
61
|
userEvent.upload(input, [pngFile, jpgFile]);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
expect(props.onUploadFile).toHaveBeenCalledTimes(1);
|
|
62
|
+
await act(async () => {
|
|
63
|
+
await jest.runOnlyPendingTimersAsync();
|
|
73
64
|
});
|
|
74
65
|
|
|
66
|
+
expect(props.onUploadFile).toHaveBeenCalledTimes(1);
|
|
75
67
|
expect(onFilesChange).toHaveBeenCalledTimes(2);
|
|
76
68
|
expect(onFilesChange).toHaveBeenNthCalledWith(1, [
|
|
77
69
|
{
|
|
78
70
|
filename: 'foo.png',
|
|
79
|
-
id: `foo.png_3_${
|
|
71
|
+
id: `foo.png_3_${date}`,
|
|
80
72
|
status: 'pending',
|
|
81
|
-
url: undefined,
|
|
82
73
|
},
|
|
83
74
|
]);
|
|
84
75
|
|
|
@@ -150,6 +141,10 @@ describe('UploadInput', () => {
|
|
|
150
141
|
|
|
151
142
|
const fileToDelete = screen.getAllByTestId(UPLOAD_ITEM_TEST_IDS.uploadItem)[0];
|
|
152
143
|
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
144
|
+
await act(async () => {
|
|
145
|
+
await jest.runOnlyPendingTimersAsync();
|
|
146
|
+
});
|
|
147
|
+
|
|
153
148
|
screen.getByText('Remove').click();
|
|
154
149
|
|
|
155
150
|
await waitForElementToBeRemoved(fileToDelete);
|
|
@@ -179,7 +174,7 @@ describe('UploadInput', () => {
|
|
|
179
174
|
]);
|
|
180
175
|
});
|
|
181
176
|
|
|
182
|
-
it('should delete file with failed state without modal confirmation', () => {
|
|
177
|
+
it('should delete file with failed state without modal confirmation', async () => {
|
|
183
178
|
const files = [
|
|
184
179
|
{
|
|
185
180
|
id: 1,
|
|
@@ -197,6 +192,9 @@ describe('UploadInput', () => {
|
|
|
197
192
|
|
|
198
193
|
const fileToDelete = screen.getAllByTestId(UPLOAD_ITEM_TEST_IDS.uploadItem)[0];
|
|
199
194
|
within(fileToDelete).getByLabelText('Remove file', { exact: false }).click();
|
|
195
|
+
await act(async () => {
|
|
196
|
+
await jest.runOnlyPendingTimersAsync();
|
|
197
|
+
});
|
|
200
198
|
|
|
201
199
|
expect(fileToDelete).not.toBeInTheDocument();
|
|
202
200
|
|
|
@@ -240,7 +238,7 @@ describe('UploadInput', () => {
|
|
|
240
238
|
onUploadFile: mockOnUploadFileFn,
|
|
241
239
|
});
|
|
242
240
|
|
|
243
|
-
mockOnUploadFileFn.mockImplementation((formData: FormData) => {
|
|
241
|
+
mockOnUploadFileFn.mockImplementation(async (formData: FormData) => {
|
|
244
242
|
const file = formData.get('file');
|
|
245
243
|
return Promise.resolve({ file, id: Math.random() });
|
|
246
244
|
});
|
|
@@ -268,7 +266,7 @@ describe('UploadInput', () => {
|
|
|
268
266
|
onUploadFile: mockOnUploadFileFn,
|
|
269
267
|
});
|
|
270
268
|
|
|
271
|
-
mockOnUploadFileFn.mockImplementation((formData: FormData) => {
|
|
269
|
+
mockOnUploadFileFn.mockImplementation(async (formData: FormData) => {
|
|
272
270
|
const file = formData.get('file');
|
|
273
271
|
return Promise.resolve({ file, id: Math.random() });
|
|
274
272
|
});
|
|
@@ -83,9 +83,7 @@ const UploadItem = ({
|
|
|
83
83
|
};
|
|
84
84
|
|
|
85
85
|
const getErrorMessage = () =>
|
|
86
|
-
|
|
87
|
-
error ||
|
|
88
|
-
formatMessage(MESSAGES.uploadingFailed);
|
|
86
|
+
typeof error === 'object' ? error.message : error || formatMessage(MESSAGES.uploadingFailed);
|
|
89
87
|
|
|
90
88
|
const getDescription = () => {
|
|
91
89
|
if (error || status === Status.FAILED) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mount } from 'enzyme/build';
|
|
2
|
+
import { act } from 'react';
|
|
2
3
|
|
|
3
4
|
import { HistoryNavigator } from '../common';
|
|
4
5
|
import { fakeKeyDownEventForKey } from '../common/fakeEvents';
|
|
@@ -6,8 +7,6 @@ import { Input } from '../inputs/Input';
|
|
|
6
7
|
|
|
7
8
|
import WithDisplayFormat from '.';
|
|
8
9
|
|
|
9
|
-
jest.useFakeTimers();
|
|
10
|
-
|
|
11
10
|
const REDO_EVENT = { ctrlKey: true, charCode: 'z', shiftKey: true, which: 90 };
|
|
12
11
|
const UNDO_EVENT = { ctrlKey: true, charCode: 'z', which: 90 };
|
|
13
12
|
|
|
@@ -36,11 +35,13 @@ describe('InputWithTextFormat', () => {
|
|
|
36
35
|
};
|
|
37
36
|
|
|
38
37
|
beforeEach(() => {
|
|
38
|
+
jest.useFakeTimers();
|
|
39
39
|
component = mountComponent(props);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
afterEach(() => {
|
|
43
|
-
jest.
|
|
42
|
+
afterEach(async () => {
|
|
43
|
+
await jest.runOnlyPendingTimersAsync();
|
|
44
|
+
jest.useRealTimers();
|
|
44
45
|
});
|
|
45
46
|
|
|
46
47
|
TESTS.forEach((test) => {
|
|
@@ -64,10 +65,12 @@ describe('InputWithTextFormat', () => {
|
|
|
64
65
|
});
|
|
65
66
|
|
|
66
67
|
describe('when Undo/Redo is preformed', () => {
|
|
67
|
-
it(`goes back/forward in input value's history`, () => {
|
|
68
|
+
it(`goes back/forward in input value's history`, async () => {
|
|
68
69
|
component.setProps({ displayPattern: '***' });
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
await act(async () => {
|
|
71
|
+
component.setState({
|
|
72
|
+
historyNavigator: new HistoryNavigator(['@', '@@', '@@@']),
|
|
73
|
+
});
|
|
71
74
|
});
|
|
72
75
|
|
|
73
76
|
componentInput().simulate('keyDown', UNDO_EVENT);
|
|
@@ -136,8 +139,10 @@ describe('InputWithTextFormat', () => {
|
|
|
136
139
|
expect(componentInput().props().value).toBe('12-3');
|
|
137
140
|
});
|
|
138
141
|
|
|
139
|
-
it(`performs an extra delete if next char is a separator`, () => {
|
|
140
|
-
|
|
142
|
+
it(`performs an extra delete if next char is a separator`, async () => {
|
|
143
|
+
await act(async () => {
|
|
144
|
+
component.setState({ selectionStart: 3, selectionEnd: 3 });
|
|
145
|
+
});
|
|
141
146
|
|
|
142
147
|
componentInput().simulate('change', { target: { value: '123' } });
|
|
143
148
|
expect(componentInput().props().value).toBe('13');
|
|
@@ -152,27 +157,41 @@ describe('InputWithTextFormat', () => {
|
|
|
152
157
|
});
|
|
153
158
|
});
|
|
154
159
|
|
|
155
|
-
it(`when entered a char`, () => {
|
|
156
|
-
|
|
160
|
+
it(`when entered a char`, async () => {
|
|
161
|
+
await act(async () => {
|
|
162
|
+
component.setState({ selectionStart: 4, selectionEnd: 4 });
|
|
163
|
+
});
|
|
157
164
|
componentInput().simulate('change', { target: { value: '13-4@' } });
|
|
158
|
-
|
|
165
|
+
await act(async () => {
|
|
166
|
+
await jest.runOnlyPendingTimersAsync();
|
|
167
|
+
});
|
|
159
168
|
expect(component.state().selectionStart).toBe(5);
|
|
160
169
|
});
|
|
161
170
|
|
|
162
|
-
it(`when entered a char before a symbol`, () => {
|
|
163
|
-
|
|
171
|
+
it(`when entered a char before a symbol`, async () => {
|
|
172
|
+
await act(async () => {
|
|
173
|
+
component.setState({ selectionStart: 2, selectionEnd: 2 });
|
|
174
|
+
});
|
|
164
175
|
componentInput().simulate('change', { target: { value: '13-@' } });
|
|
165
|
-
|
|
176
|
+
await act(async () => {
|
|
177
|
+
await jest.runOnlyPendingTimersAsync();
|
|
178
|
+
});
|
|
166
179
|
expect(component.state().selectionStart).toBe(4);
|
|
167
180
|
});
|
|
168
181
|
//
|
|
169
|
-
it(`when deleted a char before the symbol`, () => {
|
|
170
|
-
|
|
171
|
-
|
|
182
|
+
it(`when deleted a char before the symbol`, async () => {
|
|
183
|
+
await act(async () => {
|
|
184
|
+
component.setState({
|
|
185
|
+
triggerEvent: { ...triggerEventA, key: 'Backspace' },
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
await act(async () => {
|
|
189
|
+
component.setState({ selectionStart: 3, selectionEnd: 3 });
|
|
172
190
|
});
|
|
173
|
-
component.setState({ selectionStart: 3, selectionEnd: 3 });
|
|
174
191
|
componentInput().simulate('change', { target: { value: '13-45-6' } });
|
|
175
|
-
|
|
192
|
+
await act(async () => {
|
|
193
|
+
await jest.runOnlyPendingTimersAsync();
|
|
194
|
+
});
|
|
176
195
|
expect(component.state().selectionStart).toBe(1);
|
|
177
196
|
});
|
|
178
197
|
|
|
@@ -187,26 +206,38 @@ describe('InputWithTextFormat', () => {
|
|
|
187
206
|
expect(component.state().selectionStart).toBe(2);
|
|
188
207
|
});
|
|
189
208
|
|
|
190
|
-
it(`when pasted selection is entered after a symbol`, () => {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
209
|
+
it(`when pasted selection is entered after a symbol`, async () => {
|
|
210
|
+
await act(async () => {
|
|
211
|
+
component.setState({
|
|
212
|
+
triggerType: 'Paste',
|
|
213
|
+
pastedLength: 2,
|
|
214
|
+
});
|
|
194
215
|
});
|
|
195
216
|
|
|
196
|
-
|
|
217
|
+
await act(async () => {
|
|
218
|
+
component.setState({ selectionStart: 2, selectionEnd: 2 });
|
|
219
|
+
});
|
|
197
220
|
componentInput().simulate('change', { target: { value: '13-@@' } });
|
|
198
|
-
|
|
221
|
+
await act(async () => {
|
|
222
|
+
await jest.runOnlyPendingTimersAsync();
|
|
223
|
+
});
|
|
199
224
|
expect(component.state().selectionStart).toBe(5);
|
|
200
225
|
});
|
|
201
226
|
|
|
202
|
-
it(`when pasted selection is entered before a symbol`, () => {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
227
|
+
it(`when pasted selection is entered before a symbol`, async () => {
|
|
228
|
+
await act(async () => {
|
|
229
|
+
component.setState({
|
|
230
|
+
triggerType: 'Paste',
|
|
231
|
+
pastedLength: 2,
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
await act(async () => {
|
|
235
|
+
component.setState({ selectionStart: 1, selectionEnd: 1 });
|
|
206
236
|
});
|
|
207
|
-
component.setState({ selectionStart: 1, selectionEnd: 1 });
|
|
208
237
|
componentInput().simulate('change', { target: { value: '1@-@' } });
|
|
209
|
-
|
|
238
|
+
await act(async () => {
|
|
239
|
+
await jest.runOnlyPendingTimersAsync();
|
|
240
|
+
});
|
|
210
241
|
expect(component.state().selectionStart).toBe(4);
|
|
211
242
|
});
|
|
212
243
|
|
|
@@ -137,10 +137,9 @@ class WithDisplayFormat<T extends TextElementProps> extends Component<
|
|
|
137
137
|
return 'Backspace';
|
|
138
138
|
}
|
|
139
139
|
return triggerEvent.key;
|
|
140
|
-
} else {
|
|
141
|
-
// triggerEvent can be null only in case of "autofilling" (via password manager extension or browser build-in one) events
|
|
142
|
-
return 'Paste';
|
|
143
140
|
}
|
|
141
|
+
// triggerEvent can be null only in case of "autofilling" (via password manager extension or browser build-in one) events
|
|
142
|
+
return 'Paste';
|
|
144
143
|
};
|
|
145
144
|
|
|
146
145
|
resetEvent = () => {
|
|
@@ -273,6 +272,7 @@ class WithDisplayFormat<T extends TextElementProps> extends Component<
|
|
|
273
272
|
handleCursorPositioning = (action: string) => {
|
|
274
273
|
const { displayPattern } = this.props;
|
|
275
274
|
const { triggerEvent, selectionStart, selectionEnd, pastedLength } = this.state;
|
|
275
|
+
const target = triggerEvent?.currentTarget;
|
|
276
276
|
|
|
277
277
|
const cursorPosition = getCursorPositionAfterKeystroke(
|
|
278
278
|
action,
|
|
@@ -283,9 +283,7 @@ class WithDisplayFormat<T extends TextElementProps> extends Component<
|
|
|
283
283
|
);
|
|
284
284
|
|
|
285
285
|
setTimeout(() => {
|
|
286
|
-
|
|
287
|
-
(triggerEvent.target as HTMLTextElement).setSelectionRange(cursorPosition, cursorPosition);
|
|
288
|
-
}
|
|
286
|
+
target?.setSelectionRange(cursorPosition, cursorPosition);
|
|
289
287
|
this.setState({ selectionStart: cursorPosition, selectionEnd: cursorPosition });
|
|
290
288
|
}, 0);
|
|
291
289
|
};
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
/* eslint-disable jest/expect-expect */
|
|
2
|
-
import { mount } from 'enzyme';
|
|
3
|
-
|
|
4
|
-
import { fakeKeyDownEventForKey } from '../common/fakeEvents';
|
|
5
|
-
import { mockMatchMedia } from '../test-utils';
|
|
6
|
-
|
|
7
|
-
import { DateLookupWithoutInputAttributes as DateLookup } from './DateLookup';
|
|
8
|
-
|
|
9
|
-
mockMatchMedia();
|
|
10
|
-
|
|
11
|
-
const defaultLocale = 'en-GB';
|
|
12
|
-
const formatMessage = (id) => String(id);
|
|
13
|
-
jest.mock('react-intl', () => ({
|
|
14
|
-
injectIntl: (Component) =>
|
|
15
|
-
function (props) {
|
|
16
|
-
return <Component {...props} intl={{ locale: defaultLocale, formatMessage }} />;
|
|
17
|
-
},
|
|
18
|
-
useIntl: () => ({ locale: defaultLocale, formatMessage }),
|
|
19
|
-
defineMessages: (translations) => translations,
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
describe('DateLookup (keyboard events)', () => {
|
|
23
|
-
const date = new Date(2018, 11, 27);
|
|
24
|
-
let component;
|
|
25
|
-
let props;
|
|
26
|
-
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
props = { value: date, onChange: jest.fn() };
|
|
29
|
-
component = mount(<DateLookup {...props} />);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('can be opened by LEFT arrow', () => {
|
|
33
|
-
pressKey('ArrowLeft');
|
|
34
|
-
expect(component.instance().state.open).toBe(true);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('can be opened by UP arrow', () => {
|
|
38
|
-
pressKey('ArrowUp');
|
|
39
|
-
expect(component.instance().state.open).toBe(true);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('can be opened by RIGHT arrow', () => {
|
|
43
|
-
pressKey('ArrowRight');
|
|
44
|
-
expect(component.instance().state.open).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('can be opened by DOWN arrow', () => {
|
|
48
|
-
pressKey('ArrowDown');
|
|
49
|
-
expect(component.instance().state.open).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('can be closed by pressing ESCAPE', () => {
|
|
53
|
-
component.setState({ open: true });
|
|
54
|
-
pressKey('Escape');
|
|
55
|
-
expect(component.instance().state.open).toBe(false);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe('when open and in day mode', () => {
|
|
59
|
-
beforeEach(() => {
|
|
60
|
-
component.setState({ open: true, mode: 'day' });
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('moves 1 day back by pressing LEFT', () => {
|
|
64
|
-
pressKey('ArrowLeft');
|
|
65
|
-
onChangeCalledWith(new Date(2018, 11, 26));
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('moves 7 days back by pressing UP', () => {
|
|
69
|
-
pressKey('ArrowUp');
|
|
70
|
-
onChangeCalledWith(new Date(2018, 11, 20));
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('moves 1 day forward by pressing RIGHT', () => {
|
|
74
|
-
pressKey('ArrowRight');
|
|
75
|
-
onChangeCalledWith(new Date(2018, 11, 28));
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('moves 7 day forward by pressing DOWN', () => {
|
|
79
|
-
pressKey('ArrowDown');
|
|
80
|
-
onChangeCalledWith(new Date(2019, 0, 3));
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('resets to original date when escape key is pressed', () => {
|
|
84
|
-
pressKey('ArrowLeft');
|
|
85
|
-
pressKey('Escape');
|
|
86
|
-
onChangeCalledWith(date);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('resets to original date when clicking outside modal', () => {
|
|
90
|
-
pressKey('ArrowLeft');
|
|
91
|
-
component.find('.dimmer').simulate('click');
|
|
92
|
-
onChangeCalledWith(date);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
describe('when open and in month mode', () => {
|
|
97
|
-
beforeEach(() => {
|
|
98
|
-
component.setState({ open: true, mode: 'month' });
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('moves 1 month back by pressing LEFT', () => {
|
|
102
|
-
pressKey('ArrowLeft');
|
|
103
|
-
onChangeCalledWith(new Date(2018, 10, 27));
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('moves 4 months back by pressing UP', () => {
|
|
107
|
-
pressKey('ArrowUp');
|
|
108
|
-
onChangeCalledWith(new Date(2018, 7, 27));
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('moves 1 month forward by pressing RIGHT', () => {
|
|
112
|
-
pressKey('ArrowRight');
|
|
113
|
-
onChangeCalledWith(new Date(2019, 0, 27));
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('moves 4 months forward by pressing DOWN', () => {
|
|
117
|
-
pressKey('ArrowDown');
|
|
118
|
-
onChangeCalledWith(new Date(2019, 3, 27));
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe('when open and in year mode', () => {
|
|
123
|
-
beforeEach(() => {
|
|
124
|
-
component.setState({ open: true, mode: 'year' });
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('moves 1 year back by pressing LEFT', () => {
|
|
128
|
-
pressKey('ArrowLeft');
|
|
129
|
-
onChangeCalledWith(new Date(2017, 11, 27));
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('moves 4 years back by pressing UP', () => {
|
|
133
|
-
pressKey('ArrowUp');
|
|
134
|
-
onChangeCalledWith(new Date(2014, 11, 27));
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('moves 1 year forward by pressing RIGHT', () => {
|
|
138
|
-
pressKey('ArrowRight');
|
|
139
|
-
onChangeCalledWith(new Date(2019, 11, 27));
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('moves 4 year forward by pressing DOWN', () => {
|
|
143
|
-
pressKey('ArrowDown');
|
|
144
|
-
onChangeCalledWith(new Date(2022, 11, 27));
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
describe('when min and max provided', () => {
|
|
149
|
-
beforeEach(() => {
|
|
150
|
-
component.setState({
|
|
151
|
-
open: true,
|
|
152
|
-
mode: 'day',
|
|
153
|
-
min: new Date(2018, 11, 26),
|
|
154
|
-
max: new Date(2018, 11, 28),
|
|
155
|
-
});
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('makes sure that date is >= min', () => {
|
|
159
|
-
pressKey('ArrowLeft');
|
|
160
|
-
onChangeCalledWith(new Date(2018, 11, 26));
|
|
161
|
-
pressKey('ArrowLeft');
|
|
162
|
-
onChangeCalledWith(new Date(2018, 11, 26));
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('makes sure that date is <= max', () => {
|
|
166
|
-
pressKey('ArrowRight');
|
|
167
|
-
onChangeCalledWith(new Date(2018, 11, 28));
|
|
168
|
-
pressKey('ArrowRight');
|
|
169
|
-
onChangeCalledWith(new Date(2018, 11, 28));
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const pressKey = (key) => {
|
|
174
|
-
component.simulate('keyDown', fakeKeyDownEventForKey(key));
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
const onChangeCalledWith = (d) => {
|
|
178
|
-
expect(props.onChange).toHaveBeenLastCalledWith(d);
|
|
179
|
-
};
|
|
180
|
-
});
|