[react-events] Split out mixed event responder tests (#16608)
Dominic Gannaway committed
Aug 29, 2019 at 16:13 UTC
4e544cffee19e9403753bdafa35e70db06d4190a
5 files changed
+403
-419
packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js
+64
@@ -994,4 +994,68 @@ describe('DOMEventResponderSystem', () => {
994
dispatchClickEvent(ref.current);
995
expect(log).toEqual([{counter: 1}]);
996
});
997
+
998
+ it('should correctly pass through event properties', () => {
999
+ const timeStamps = [];
1000
+ const ref = React.createRef();
1001
+ const eventLog = [];
1002
+ const logEvent = event => {
1003
+ const propertiesWeCareAbout = {
1004
+ counter: event.counter,
1005
+ target: event.target,
1006
+ timeStamp: event.timeStamp,
1007
+ type: event.type,
1008
+ };
1009
+ timeStamps.push(event.timeStamp);
1010
+ eventLog.push(propertiesWeCareAbout);
1011
+ };
1012
+ let counter = 0;
1013
+
1014
+ const TestResponder = createEventResponder({
1015
+ targetEventTypes: ['click'],
1016
+ onEvent(event, context, props) {
1017
+ const obj = {
1018
+ counter,
1019
+ timeStamp: context.getTimeStamp(),
1020
+ target: event.responderTarget,
1021
+ type: 'click-test',
1022
+ };
1023
+ context.dispatchEvent(obj, props.onClick, DiscreteEvent);
1024
+ },
1025
+ });
1026
+
1027
+ const Component = () => {
1028
+ const listener = React.unstable_useResponder(TestResponder, {
1029
+ onClick: logEvent,
1030
+ });
1031
+ return <button ref={ref} listeners={listener} />;
1032
+ };
1033
+ ReactDOM.render(<Component />, container);
1034
+ dispatchClickEvent(ref.current);
1035
+ counter++;
1036
+ dispatchClickEvent(ref.current);
1037
+ counter++;
1038
+ dispatchClickEvent(ref.current);
1039
+ expect(typeof timeStamps[0] === 'number').toBe(true);
1040
+ expect(eventLog).toEqual([
1041
+ {
1042
+ counter: 0,
1043
+ target: ref.current,
1044
+ timeStamp: timeStamps[0],
1045
+ type: 'click-test',
1046
+ },
1047
+ {
1048
+ counter: 1,
1049
+ target: ref.current,
1050
+ timeStamp: timeStamps[1],
1051
+ type: 'click-test',
1052
+ },
1053
+ {
1054
+ counter: 2,
1055
+ target: ref.current,
1056
+ timeStamp: timeStamps[2],
1057
+ type: 'click-test',
1058
+ },
1059
+ ]);
1060
+ });
1061
});
packages/react-events/src/dom/__tests__/Input-test.internal.js
-92
@@ -14,7 +14,6 @@ let ReactFeatureFlags;
14
let ReactDOM;
15
let InputResponder;
16
let useInput;
17
-let usePress;
17
let Scheduler;
18
19
const setUntrackedChecked = Object.getOwnPropertyDescriptor(
@@ -42,7 +41,6 @@ const modulesInit = () => {
41
Scheduler = require('scheduler');
42
InputResponder = require('react-events/input').InputResponder;
43
useInput = require('react-events/input').useInput;
45
- usePress = require('react-events/press').usePress;
44
};
45
46
describe('Input event responder', () => {
@@ -948,96 +946,6 @@ describe('Input event responder', () => {
946
// Value should be the controlled value, not the original one
947
expect(textarea.value).toBe('changed [!]');
948
});
951
-
952
- it('is async for non-input events', () => {
953
- const root = ReactDOM.unstable_createRoot(container);
954
- let input;
955
-
956
- let ops = [];
957
-
958
- function Component({
959
- innerRef,
960
- onChange,
961
- controlledValue,
962
- pressListener,
963
- }) {
964
- const inputListener = useInput({
965
- onChange,
966
- });
967
- return (
968
- <input
969
- type="text"
970
- ref={innerRef}
971
- value={controlledValue}
972
- listeners={[inputListener, pressListener]}
973
- />
974
- );
975
- }
976
-
977
- function PressWrapper({innerRef, onPress, onChange, controlledValue}) {
978
- const pressListener = usePress({
979
- onPress,
980
- });
981
- return (
982
- <Component
983
- onChange={onChange}
984
- innerRef={el => (input = el)}
985
- controlledValue={controlledValue}
986
- pressListener={pressListener}
987
- />
988
- );
989
- }
990
-
991
- class ControlledInput extends React.Component {
992
- state = {value: 'initial'};
993
- onChange = event => this.setState({value: event.target.value});
994
- reset = () => {
995
- this.setState({value: ''});
996
- };
997
- render() {
998
- ops.push(`render: ${this.state.value}`);
999
- const controlledValue =
1000
- this.state.value === 'changed' ? 'changed [!]' : this.state.value;
1001
- return (
1002
- <PressWrapper
1003
- onPress={this.reset}
1004
- onChange={this.onChange}
1005
- innerRef={el => (input = el)}
1006
- controlledValue={controlledValue}
1007
- />
1008
- );
1009
- }
1010
- }
1011
-
1012
- // Initial mount. Test that this is async.
1013
- root.render(<ControlledInput />);
1014
- // Should not have flushed yet.
1015
- expect(ops).toEqual([]);
1016
- expect(input).toBe(undefined);
1017
- // Flush callbacks.
1018
- Scheduler.unstable_flushAll();
1019
- expect(ops).toEqual(['render: initial']);
1020
- expect(input.value).toBe('initial');
1021
-
1022
- ops = [];
1023
-
1024
- // Trigger a click event
1025
- input.dispatchEvent(
1026
- new MouseEvent('mousedown', {bubbles: true, cancelable: true}),
1027
- );
1028
- input.dispatchEvent(
1029
- new MouseEvent('mouseup', {bubbles: true, cancelable: true}),
1030
- );
1031
- // Nothing should have changed
1032
- expect(ops).toEqual([]);
1033
- expect(input.value).toBe('initial');
1034
-
1035
- // Flush callbacks.
1036
- Scheduler.unstable_flushAll();
1037
- // Now the click update has flushed.
1038
- expect(ops).toEqual(['render: ']);
1039
- expect(input.value).toBe('');
1040
- });
949
});
950
});
951
packages/react-events/src/dom/__tests__/MixedResponders-test-internal.js
new
+326
@@ -0,0 +1,326 @@
1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @emails react-core
8
+ */
9
+
10
+'use strict';
11
+
12
+import {createEventTarget} from '../testing-library';
13
+
14
+let React;
15
+let ReactFeatureFlags;
16
+let ReactDOM;
17
+let Scheduler;
18
+
19
+describe('mixing responders with the heritage event system', () => {
20
+ let container;
21
+
22
+ beforeEach(() => {
23
+ ReactFeatureFlags = require('shared/ReactFeatureFlags');
24
+ ReactFeatureFlags.enableFlareAPI = true;
25
+ React = require('react');
26
+ ReactDOM = require('react-dom');
27
+ Scheduler = require('scheduler');
28
+ container = document.createElement('div');
29
+ document.body.appendChild(container);
30
+ });
31
+
32
+ afterEach(() => {
33
+ document.body.removeChild(container);
34
+ container = null;
35
+ });
36
+
37
+ it('should properly only flush sync once when the event systems are mixed', () => {
38
+ const usePress = require('react-events/press').usePress;
39
+ const ref = React.createRef();
40
+ let renderCounts = 0;
41
+
42
+ function MyComponent() {
43
+ const [, updateCounter] = React.useState(0);
44
+ renderCounts++;
45
+
46
+ function handlePress() {
47
+ updateCounter(count => count + 1);
48
+ }
49
+
50
+ const listener = usePress({
51
+ onPress: handlePress,
52
+ });
53
+
54
+ return (
55
+ <div>
56
+ <button
57
+ ref={ref}
58
+ listeners={listener}
59
+ onClick={() => {
60
+ updateCounter(count => count + 1);
61
+ }}>
62
+ Press me
63
+ </button>
64
+ </div>
65
+ );
66
+ }
67
+
68
+ const newContainer = document.createElement('div');
69
+ const root = ReactDOM.unstable_createRoot(newContainer);
70
+ document.body.appendChild(newContainer);
71
+ root.render(<MyComponent />);
72
+ Scheduler.unstable_flushAll();
73
+
74
+ const target = createEventTarget(ref.current);
75
+ target.pointerdown({timeStamp: 100});
76
+ target.pointerup({timeStamp: 100});
77
+ target.click({timeStamp: 100});
78
+
79
+ if (__DEV__) {
80
+ expect(renderCounts).toBe(2);
81
+ } else {
82
+ expect(renderCounts).toBe(1);
83
+ }
84
+ Scheduler.unstable_flushAll();
85
+ if (__DEV__) {
86
+ expect(renderCounts).toBe(4);
87
+ } else {
88
+ expect(renderCounts).toBe(2);
89
+ }
90
+
91
+ target.pointerdown({timeStamp: 100});
92
+ target.pointerup({timeStamp: 100});
93
+ // Ensure the timeStamp logic works
94
+ target.click({timeStamp: 101});
95
+
96
+ if (__DEV__) {
97
+ expect(renderCounts).toBe(6);
98
+ } else {
99
+ expect(renderCounts).toBe(3);
100
+ }
101
+
102
+ Scheduler.unstable_flushAll();
103
+ document.body.removeChild(newContainer);
104
+ });
105
+
106
+ it('should properly flush sync when the event systems are mixed with unstable_flushDiscreteUpdates', () => {
107
+ const usePress = require('react-events/press').usePress;
108
+ const ref = React.createRef();
109
+ let renderCounts = 0;
110
+
111
+ function MyComponent() {
112
+ const [, updateCounter] = React.useState(0);
113
+ renderCounts++;
114
+
115
+ function handlePress() {
116
+ updateCounter(count => count + 1);
117
+ }
118
+
119
+ const listener = usePress({
120
+ onPress: handlePress,
121
+ });
122
+
123
+ return (
124
+ <div>
125
+ <button
126
+ ref={ref}
127
+ listeners={listener}
128
+ onClick={() => {
129
+ // This should flush synchronously
130
+ ReactDOM.unstable_flushDiscreteUpdates();
131
+ updateCounter(count => count + 1);
132
+ }}>
133
+ Press me
134
+ </button>
135
+ </div>
136
+ );
137
+ }
138
+
139
+ const newContainer = document.createElement('div');
140
+ const root = ReactDOM.unstable_createRoot(newContainer);
141
+ document.body.appendChild(newContainer);
142
+ root.render(<MyComponent />);
143
+ Scheduler.unstable_flushAll();
144
+
145
+ const target = createEventTarget(ref.current);
146
+ target.pointerdown({timeStamp: 100});
147
+ target.pointerup({timeStamp: 100});
148
+
149
+ if (__DEV__) {
150
+ expect(renderCounts).toBe(4);
151
+ } else {
152
+ expect(renderCounts).toBe(2);
153
+ }
154
+ Scheduler.unstable_flushAll();
155
+ if (__DEV__) {
156
+ expect(renderCounts).toBe(6);
157
+ } else {
158
+ expect(renderCounts).toBe(3);
159
+ }
160
+
161
+ target.pointerdown({timeStamp: 100});
162
+ // Ensure the timeStamp logic works
163
+ target.pointerup({timeStamp: 101});
164
+
165
+ if (__DEV__) {
166
+ expect(renderCounts).toBe(8);
167
+ } else {
168
+ expect(renderCounts).toBe(4);
169
+ }
170
+
171
+ Scheduler.unstable_flushAll();
172
+ document.body.removeChild(newContainer);
173
+ });
174
+
175
+ it(
176
+ 'should only flush before outermost discrete event handler when mixing ' +
177
+ 'event systems',
178
+ async () => {
179
+ const {useState} = React;
180
+ const usePress = require('react-events/press').usePress;
181
+
182
+ const button = React.createRef();
183
+
184
+ const ops = [];
185
+
186
+ function MyComponent() {
187
+ const [pressesCount, updatePressesCount] = useState(0);
188
+ const [clicksCount, updateClicksCount] = useState(0);
189
+
190
+ function handlePress() {
191
+ // This dispatches a synchronous, discrete event in the legacy event
192
+ // system. However, because it's nested inside the new event system,
193
+ // its updates should not flush until the end of the outer handler.
194
+ const target = createEventTarget(button.current);
195
+ target.click();
196
+ // Text context should not have changed
197
+ ops.push(newContainer.textContent);
198
+ updatePressesCount(pressesCount + 1);
199
+ }
200
+
201
+ const listener = usePress({
202
+ onPress: handlePress,
203
+ });
204
+
205
+ return (
206
+ <div>
207
+ <button
208
+ listeners={listener}
209
+ ref={button}
210
+ onClick={() => updateClicksCount(clicksCount + 1)}>
211
+ Presses: {pressesCount}, Clicks: {clicksCount}
212
+ </button>
213
+ </div>
214
+ );
215
+ }
216
+
217
+ const newContainer = document.createElement('div');
218
+ document.body.appendChild(newContainer);
219
+ const root = ReactDOM.unstable_createRoot(newContainer);
220
+
221
+ root.render(<MyComponent />);
222
+ Scheduler.unstable_flushAll();
223
+ expect(newContainer.textContent).toEqual('Presses: 0, Clicks: 0');
224
+
225
+ const target = createEventTarget(button.current);
226
+ target.pointerdown({timeStamp: 100});
227
+ target.pointerup({timeStamp: 100});
228
+
229
+ Scheduler.unstable_flushAll();
230
+ expect(newContainer.textContent).toEqual('Presses: 1, Clicks: 1');
231
+
232
+ expect(ops).toEqual(['Presses: 0, Clicks: 0']);
233
+ },
234
+ );
235
+
236
+ describe('mixing the Input and Press repsonders', () => {
237
+ it('is async for non-input events', () => {
238
+ ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
239
+ ReactFeatureFlags.enableUserBlockingEvents = true;
240
+ const usePress = require('react-events/press').usePress;
241
+ const useInput = require('react-events/input').useInput;
242
+ const root = ReactDOM.unstable_createRoot(container);
243
+ let input;
244
+
245
+ let ops = [];
246
+
247
+ function Component({innerRef, onChange, controlledValue, pressListener}) {
248
+ const inputListener = useInput({
249
+ onChange,
250
+ });
251
+ return (
252
+ <input
253
+ type="text"
254
+ ref={innerRef}
255
+ value={controlledValue}
256
+ listeners={[inputListener, pressListener]}
257
+ />
258
+ );
259
+ }
260
+
261
+ function PressWrapper({innerRef, onPress, onChange, controlledValue}) {
262
+ const pressListener = usePress({
263
+ onPress,
264
+ });
265
+ return (
266
+ <Component
267
+ onChange={onChange}
268
+ innerRef={el => (input = el)}
269
+ controlledValue={controlledValue}
270
+ pressListener={pressListener}
271
+ />
272
+ );
273
+ }
274
+
275
+ class ControlledInput extends React.Component {
276
+ state = {value: 'initial'};
277
+ onChange = event => this.setState({value: event.target.value});
278
+ reset = () => {
279
+ this.setState({value: ''});
280
+ };
281
+ render() {
282
+ ops.push(`render: ${this.state.value}`);
283
+ const controlledValue =
284
+ this.state.value === 'changed' ? 'changed [!]' : this.state.value;
285
+ return (
286
+ <PressWrapper
287
+ onPress={this.reset}
288
+ onChange={this.onChange}
289
+ innerRef={el => (input = el)}
290
+ controlledValue={controlledValue}
291
+ />
292
+ );
293
+ }
294
+ }
295
+
296
+ // Initial mount. Test that this is async.
297
+ root.render(<ControlledInput />);
298
+ // Should not have flushed yet.
299
+ expect(ops).toEqual([]);
300
+ expect(input).toBe(undefined);
301
+ // Flush callbacks.
302
+ Scheduler.unstable_flushAll();
303
+ expect(ops).toEqual(['render: initial']);
304
+ expect(input.value).toBe('initial');
305
+
306
+ ops = [];
307
+
308
+ // Trigger a click event
309
+ input.dispatchEvent(
310
+ new MouseEvent('mousedown', {bubbles: true, cancelable: true}),
311
+ );
312
+ input.dispatchEvent(
313
+ new MouseEvent('mouseup', {bubbles: true, cancelable: true}),
314
+ );
315
+ // Nothing should have changed
316
+ expect(ops).toEqual([]);
317
+ expect(input.value).toBe('initial');
318
+
319
+ // Flush callbacks.
320
+ Scheduler.unstable_flushAll();
321
+ // Now the click update has flushed.
322
+ expect(ops).toEqual(['render: ']);
323
+ expect(input.value).toBe('');
324
+ });
325
+ });
326
+});
packages/react-events/src/dom/__tests__/Press-test.internal.js
-327
@@ -1120,334 +1120,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
1120
target.pointerdown();
1121
});
1122
1123
- it('should correctly pass through event properties', () => {
1124
- const timeStamps = [];
1125
- const ref = React.createRef();
1126
- const eventLog = [];
1127
- const logEvent = event => {
1128
- const propertiesWeCareAbout = {
1129
- pageX: event.pageX,
1130
- pageY: event.pageY,
1131
- screenX: event.screenX,
1132
- screenY: event.screenY,
1133
- clientX: event.clientX,
1134
- clientY: event.clientY,
1135
- pointerType: event.pointerType,
1136
- target: event.target,
1137
- timeStamp: event.timeStamp,
1138
- type: event.type,
1139
- };
1140
- timeStamps.push(event.timeStamp);
1141
- eventLog.push(propertiesWeCareAbout);
1142
- };
1143
-
1144
- const Component = () => {
1145
- const listener = usePress({
1146
- onPressStart: logEvent,
1147
- onPressEnd: logEvent,
1148
- onPressMove: logEvent,
1149
- onPress: logEvent,
1150
- });
1151
- return <button ref={ref} listeners={listener} />;
1152
- };
1153
- ReactDOM.render(<Component />, container);
1154
-
1155
- const target = createEventTarget(ref.current);
1156
- target.setBoundingClientRect({x: 10, y: 10, width: 100, height: 100});
1157
- target.pointerdown({
1158
- pointerType: 'mouse',
1159
- pageX: 15,
1160
- pageY: 16,
1161
- x: 30,
1162
- y: 31,
1163
- });
1164
- target.pointermove({
1165
- pointerType: 'mouse',
1166
- pageX: 16,
1167
- pageY: 17,
1168
- x: 31,
1169
- y: 32,
1170
- });
1171
- target.pointerup({
1172
- pointerType: 'mouse',
1173
- pageX: 17,
1174
- pageY: 18,
1175
- x: 32,
1176
- y: 33,
1177
- });
1178
- target.pointerdown({
1179
- pointerType: 'mouse',
1180
- pageX: 18,
1181
- pageY: 19,
1182
- x: 33,
1183
- y: 34,
1184
- });
1185
- expect(typeof timeStamps[0] === 'number').toBe(true);
1186
- expect(eventLog).toEqual([
1187
- {
1188
- pointerType: 'mouse',
1189
- pageX: 15,
1190
- pageY: 16,
1191
- screenX: 30,
1192
- screenY: 81,
1193
- clientX: 30,
1194
- clientY: 31,
1195
- target: ref.current,
1196
- timeStamp: timeStamps[0],
1197
- type: 'pressstart',
1198
- },
1199
- {
1200
- pointerType: 'mouse',
1201
- pageX: 16,
1202
- pageY: 17,
1203
- screenX: 31,
1204
- screenY: 82,
1205
- clientX: 31,
1206
- clientY: 32,
1207
- target: ref.current,
1208
- timeStamp: timeStamps[1],
1209
- type: 'pressmove',
1210
- },
1211
- {
1212
- pointerType: 'mouse',
1213
- pageX: 17,
1214
- pageY: 18,
1215
- screenX: 32,
1216
- screenY: 83,
1217
- clientX: 32,
1218
- clientY: 33,
1219
- target: ref.current,
1220
- timeStamp: timeStamps[2],
1221
- type: 'pressend',
1222
- },
1223
- {
1224
- pointerType: 'mouse',
1225
- pageX: 17,
1226
- pageY: 18,
1227
- screenX: 32,
1228
- screenY: 83,
1229
- clientX: 32,
1230
- clientY: 33,
1231
- target: ref.current,
1232
- timeStamp: timeStamps[3],
1233
- type: 'press',
1234
- },
1235
- {
1236
- pointerType: 'mouse',
1237
- pageX: 18,
1238
- pageY: 19,
1239
- screenX: 33,
1240
- screenY: 84,
1241
- clientX: 33,
1242
- clientY: 34,
1243
- target: ref.current,
1244
- timeStamp: timeStamps[4],
1245
- type: 'pressstart',
1246
- },
1247
- ]);
1248
- });
1249
-
1123
if (hasPointerEvents) {
1251
- // TODO(T46067442): move these tests to core
1252
- /*
1253
- it('should properly only flush sync once when the event systems are mixed', () => {
1254
- const ref = React.createRef();
1255
- let renderCounts = 0;
1256
-
1257
- function MyComponent() {
1258
- const [, updateCounter] = React.useState(0);
1259
- renderCounts++;
1260
-
1261
- function handlePress() {
1262
- updateCounter(count => count + 1);
1263
- }
1264
-
1265
- const listener = usePress({
1266
- onPress: handlePress,
1267
- });
1268
-
1269
- return (
1270
- <div>
1271
- <button
1272
- ref={ref}
1273
- listeners={listener}
1274
- onClick={() => {
1275
- updateCounter(count => count + 1);
1276
- }}>
1277
- Press me
1278
- </button>
1279
- </div>
1280
- );
1281
- }
1282
-
1283
- const newContainer = document.createElement('div');
1284
- const root = ReactDOM.unstable_createRoot(newContainer);
1285
- document.body.appendChild(newContainer);
1286
- root.render(<MyComponent />);
1287
- Scheduler.unstable_flushAll();
1288
-
1289
- const target = ref.current;
1290
- target.dispatchEvent(pointerdown({timeStamp: 100}));
1291
- target.dispatchEvent(pointerup({timeStamp: 100}));
1292
- target.dispatchEvent(click({timeStamp: 100}));
1293
-
1294
- if (__DEV__) {
1295
- expect(renderCounts).toBe(2);
1296
- } else {
1297
- expect(renderCounts).toBe(1);
1298
- }
1299
- Scheduler.unstable_flushAll();
1300
- if (__DEV__) {
1301
- expect(renderCounts).toBe(4);
1302
- } else {
1303
- expect(renderCounts).toBe(2);
1304
- }
1305
-
1306
- target.dispatchEvent(pointerdown({timeStamp: 100}));
1307
- target.dispatchEvent(pointerup({timeStamp: 100}));
1308
- // Ensure the timeStamp logic works
1309
- target.dispatchEvent(click({timeStamp: 101}));
1310
-
1311
- if (__DEV__) {
1312
- expect(renderCounts).toBe(6);
1313
- } else {
1314
- expect(renderCounts).toBe(3);
1315
- }
1316
-
1317
- Scheduler.unstable_flushAll();
1318
- document.body.removeChild(newContainer);
1319
- });
1320
-
1321
- it('should properly flush sync when the event systems are mixed with unstable_flushDiscreteUpdates', () => {
1322
- const ref = React.createRef();
1323
- let renderCounts = 0;
1324
-
1325
- function MyComponent() {
1326
- const [, updateCounter] = React.useState(0);
1327
- renderCounts++;
1328
-
1329
- function handlePress() {
1330
- updateCounter(count => count + 1);
1331
- }
1332
-
1333
- const listener = usePress({
1334
- onPress: handlePress,
1335
- });
1336
-
1337
- return (
1338
- <div>
1339
- <button
1340
- ref={ref}
1341
- listeners={listener}
1342
- onClick={() => {
1343
- // This should flush synchronously
1344
- ReactDOM.unstable_flushDiscreteUpdates();
1345
- updateCounter(count => count + 1);
1346
- }}>
1347
- Press me
1348
- </button>
1349
- </div>
1350
- );
1351
- }
1352
-
1353
- const newContainer = document.createElement('div');
1354
- const root = ReactDOM.unstable_createRoot(newContainer);
1355
- document.body.appendChild(newContainer);
1356
- root.render(<MyComponent />);
1357
- Scheduler.unstable_flushAll();
1358
-
1359
- const target = ref.current;
1360
- target.dispatchEvent(pointerdown({timeStamp: 100}));
1361
- target.dispatchEvent(pointerup({timeStamp: 100}));
1362
- target.dispatchEvent(click({timeStamp: 100}));
1363
-
1364
- if (__DEV__) {
1365
- expect(renderCounts).toBe(4);
1366
- } else {
1367
- expect(renderCounts).toBe(2);
1368
- }
1369
- Scheduler.unstable_flushAll();
1370
- if (__DEV__) {
1371
- expect(renderCounts).toBe(6);
1372
- } else {
1373
- expect(renderCounts).toBe(3);
1374
- }
1375
-
1376
- target.dispatchEvent(pointerdown({timeStamp: 100}));
1377
- target.dispatchEvent(pointerup({timeStamp: 100}));
1378
- // Ensure the timeStamp logic works
1379
- target.dispatchEvent(click({timeStamp: 101}));
1380
-
1381
- if (__DEV__) {
1382
- expect(renderCounts).toBe(8);
1383
- } else {
1384
- expect(renderCounts).toBe(4);
1385
- }
1386
-
1387
- Scheduler.unstable_flushAll();
1388
- document.body.removeChild(newContainer);
1389
- });
1390
-
1391
- it(
1392
- 'should only flush before outermost discrete event handler when mixing ' +
1393
- 'event systems',
1394
- async () => {
1395
- const {useState} = React;
1396
-
1397
- const button = React.createRef();
1398
-
1399
- const ops = [];
1400
-
1401
- function MyComponent() {
1402
- const [pressesCount, updatePressesCount] = useState(0);
1403
- const [clicksCount, updateClicksCount] = useState(0);
1404
-
1405
- function handlePress() {
1406
- // This dispatches a synchronous, discrete event in the legacy event
1407
- // system. However, because it's nested inside the new event system,
1408
- // its updates should not flush until the end of the outer handler.
1409
- button.current.click();
1410
- // Text context should not have changed
1411
- ops.push(newContainer.textContent);
1412
- updatePressesCount(pressesCount + 1);
1413
- }
1414
-
1415
- const listener = usePress({
1416
- onPress: handlePress,
1417
- });
1418
-
1419
- return (
1420
- <div>
1421
- <button
1422
- listeners={listener}
1423
- ref={button}
1424
- onClick={() => updateClicksCount(clicksCount + 1)}>
1425
- Presses: {pressesCount}, Clicks: {clicksCount}
1426
- </button>
1427
- </div>
1428
- );
1429
- }
1430
-
1431
- const newContainer = document.createElement('div');
1432
- document.body.appendChild(newContainer);
1433
- const root = ReactDOM.unstable_createRoot(newContainer);
1434
-
1435
- root.render(<MyComponent />);
1436
- Scheduler.unstable_flushAll();
1437
- expect(newContainer.textContent).toEqual('Presses: 0, Clicks: 0');
1438
-
1439
- const target = button.current;
1440
- target.dispatchEvent(pointerdown({timeStamp: 100}));
1441
- target.dispatchEvent(pointerup({timeStamp: 100}));
1442
- target.dispatchEvent(click({timeStamp: 100}));
1443
-
1444
- Scheduler.unstable_flushAll();
1445
- expect(newContainer.textContent).toEqual('Presses: 1, Clicks: 1');
1446
-
1447
- expect(ops).toEqual(['Presses: 0, Clicks: 0']);
1448
- },
1449
- );
1450
- */
1124
it('should work correctly with stopPropagation set to true', () => {
1125
const ref = React.createRef();
1126
const pointerDownEvent = jest.fn();
packages/react-events/src/dom/testing-library/domEvents.js
+13
@@ -37,6 +37,9 @@ function createEvent(type, data = {}) {
37
if (data != null) {
38
Object.keys(data).forEach(key => {
39
const value = data[key];
40
+ if (key === 'timeStamp' && !value) {
41
+ return;
42
+ }
43
Object.defineProperty(event, key, {value});
44
});
45
}
@@ -83,6 +86,7 @@ function createPointerEvent(
86
tangentialPressure = 0,
87
tiltX = 0,
88
tiltY = 0,
89
+ timeStamp,
90
twist = 0,
91
width,
92
x = 0,
@@ -122,6 +126,7 @@ function createPointerEvent(
126
tangentialPressure,
127
tiltX,
128
tiltY,
129
+ timeStamp,
130
twist,
131
width: isMouse ? 1 : width != null ? width : defaultPointerSize,
132
});
@@ -171,6 +176,7 @@ function createMouseEvent(
176
screenX,
177
screenY,
178
shiftKey = false,
179
+ timeStamp,
180
x = 0,
181
y = 0,
182
} = {},
@@ -198,6 +204,7 @@ function createMouseEvent(
204
screenX: screenX === 0 ? screenX : x,
205
screenY: screenY === 0 ? screenY : y + defaultBrowserChromeSize,
206
shiftKey,
207
+ timeStamp,
208
});
209
}
210
@@ -209,6 +216,8 @@ function createTouchEvent(type, payload) {
216
let metaKey = false;
217
let preventDefault = emptyFunction;
218
let shiftKey = false;
219
+ let timeStamp;
220
+
221
if (firstTouch != null) {
222
if (firstTouch.altKey != null) {
223
altKey = firstTouch.altKey;
@@ -225,6 +234,9 @@ function createTouchEvent(type, payload) {
234
if (firstTouch.shiftKey != null) {
235
shiftKey = firstTouch.shiftKey;
236
}
237
+ if (firstTouch.timeStamp != null) {
238
+ timeStamp = firstTouch.timeStamp;
239
+ }
240
}
241
242
const touches = touchesPayload.map(
@@ -268,6 +280,7 @@ function createTouchEvent(type, payload) {
280
firesTouchEvents: true,
281
},
282
targetTouches: activeTouches,
283
+ timeStamp,
284
touches: activeTouches,
285
});
286
}