Skip to content

Commit 79d2f9a

Browse files
timjacobiEthan-Arrowood
authored andcommitted
Rewrite SyntheticEvent tests using public APIs only (facebook#11525)
* generate synthetics events using public API * rewritten createEvent to use public APIs * removed all references SyntheticEvent.release In order to test under realistic circumstances I had to move the expectations into a callback in mosts tests to overcome the effects of event pooling. * run prettier * remove empty line * don't use ReactTestUtils * run prettier and fix linter issues * remove duplicate test * remove invalid calls to expect The removed `expect` calls verified the correct behaviour based on missing `preventDefault` and `stopPropagation` methods. The was correct as we used plain objects to simulate events. Since we switched to the public API we're using native events which do have these methods. * set event.defaultPrevented to undefined This was missed when the test was first migrated. When emulating IE8 not only has returnValue to be false. In addition defaultPrevented must not be defined. * run all tests and format code * rename instance variable to node * remove backtick * only simulate IE in normalisation test * include assignment in definition * add missing `persist` test * use method instead of field to prevent default * expect properties to be unchanged on persisted event * optimise tests that deal with event persitence * declare and assign `event` on the same line if not reassigned later
1 parent d6cf925 commit 79d2f9a

File tree

1 file changed

+199
-53
lines changed

1 file changed

+199
-53
lines changed

packages/react-dom/src/events/__tests__/SyntheticEvent-test.js

Lines changed: 199 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9,79 +9,170 @@
99

1010
'use strict';
1111

12-
var SyntheticEvent;
1312
var React;
1413
var ReactDOM;
1514
var ReactTestUtils;
1615

1716
describe('SyntheticEvent', () => {
18-
var createEvent;
17+
var container;
1918

2019
beforeEach(() => {
21-
// TODO: can we express this test with only public API?
22-
SyntheticEvent = require('events/SyntheticEvent').default;
2320
React = require('react');
2421
ReactDOM = require('react-dom');
2522
ReactTestUtils = require('react-dom/test-utils');
2623

27-
createEvent = function(nativeEvent) {
28-
var target = require('../getEventTarget').default(nativeEvent);
29-
return SyntheticEvent.getPooled({}, '', nativeEvent, target);
30-
};
24+
container = document.createElement('div');
25+
document.body.appendChild(container);
26+
});
27+
28+
afterEach(() => {
29+
document.body.removeChild(container);
30+
container = null;
3131
});
3232

3333
it('should normalize `target` from the nativeEvent', () => {
34-
var target = document.createElement('div');
35-
var syntheticEvent = createEvent({srcElement: target});
34+
var node;
35+
var expectedCount = 0;
36+
37+
var eventHandler = syntheticEvent => {
38+
expect(syntheticEvent.target).toBe(node);
39+
40+
expectedCount++;
41+
};
42+
node = ReactDOM.render(<div onClick={eventHandler} />, container);
43+
44+
var event = document.createEvent('Event');
45+
event.initEvent('click', true, true);
46+
// Emulate IE8
47+
Object.defineProperty(event, 'target', {
48+
get() {},
49+
});
50+
Object.defineProperty(event, 'srcElement', {
51+
get() {
52+
return node;
53+
},
54+
});
55+
node.dispatchEvent(event);
3656

37-
expect(syntheticEvent.target).toBe(target);
38-
expect(syntheticEvent.type).toBe(undefined);
57+
expect(expectedCount).toBe(1);
3958
});
4059

4160
it('should be able to `preventDefault`', () => {
42-
var nativeEvent = {};
43-
var syntheticEvent = createEvent(nativeEvent);
61+
var node;
62+
var expectedCount = 0;
4463

45-
expect(syntheticEvent.isDefaultPrevented()).toBe(false);
46-
syntheticEvent.preventDefault();
47-
expect(syntheticEvent.isDefaultPrevented()).toBe(true);
64+
var eventHandler = syntheticEvent => {
65+
expect(syntheticEvent.isDefaultPrevented()).toBe(false);
66+
syntheticEvent.preventDefault();
67+
expect(syntheticEvent.isDefaultPrevented()).toBe(true);
68+
expect(syntheticEvent.defaultPrevented).toBe(true);
69+
70+
expectedCount++;
71+
};
72+
node = ReactDOM.render(<div onClick={eventHandler} />, container);
4873

49-
expect(syntheticEvent.defaultPrevented).toBe(true);
74+
var event = document.createEvent('Event');
75+
event.initEvent('click', true, true);
76+
node.dispatchEvent(event);
5077

51-
expect(nativeEvent.returnValue).toBe(false);
78+
expect(expectedCount).toBe(1);
5279
});
5380

5481
it('should be prevented if nativeEvent is prevented', () => {
55-
expect(createEvent({defaultPrevented: true}).isDefaultPrevented()).toBe(
56-
true,
57-
);
58-
expect(createEvent({returnValue: false}).isDefaultPrevented()).toBe(true);
82+
var node;
83+
var expectedCount = 0;
84+
85+
var eventHandler = syntheticEvent => {
86+
expect(syntheticEvent.isDefaultPrevented()).toBe(true);
87+
88+
expectedCount++;
89+
};
90+
node = ReactDOM.render(<div onClick={eventHandler} />, container);
91+
92+
var event;
93+
event = document.createEvent('Event');
94+
event.initEvent('click', true, true);
95+
event.preventDefault();
96+
node.dispatchEvent(event);
97+
98+
event = document.createEvent('Event');
99+
event.initEvent('click', true, true);
100+
// Emulate IE8
101+
Object.defineProperty(event, 'defaultPrevented', {
102+
get() {},
103+
});
104+
Object.defineProperty(event, 'returnValue', {
105+
get() {
106+
return false;
107+
},
108+
});
109+
node.dispatchEvent(event);
110+
111+
expect(expectedCount).toBe(2);
59112
});
60113

61114
it('should be able to `stopPropagation`', () => {
62-
var nativeEvent = {};
63-
var syntheticEvent = createEvent(nativeEvent);
115+
var node;
116+
var expectedCount = 0;
64117

65-
expect(syntheticEvent.isPropagationStopped()).toBe(false);
66-
syntheticEvent.stopPropagation();
67-
expect(syntheticEvent.isPropagationStopped()).toBe(true);
118+
var eventHandler = syntheticEvent => {
119+
expect(syntheticEvent.isPropagationStopped()).toBe(false);
120+
syntheticEvent.stopPropagation();
121+
expect(syntheticEvent.isPropagationStopped()).toBe(true);
68122

69-
expect(nativeEvent.cancelBubble).toBe(true);
123+
expectedCount++;
124+
};
125+
node = ReactDOM.render(<div onClick={eventHandler} />, container);
126+
127+
var event = document.createEvent('Event');
128+
event.initEvent('click', true, true);
129+
node.dispatchEvent(event);
130+
131+
expect(expectedCount).toBe(1);
70132
});
71133

72134
it('should be able to `persist`', () => {
73-
var syntheticEvent = createEvent({});
135+
var node;
136+
var expectedCount = 0;
137+
var syntheticEvent;
138+
139+
var eventHandler = e => {
140+
expect(e.isPersistent()).toBe(false);
141+
e.persist();
142+
syntheticEvent = e;
143+
expect(e.isPersistent()).toBe(true);
144+
145+
expectedCount++;
146+
};
147+
node = ReactDOM.render(<div onClick={eventHandler} />, container);
74148

75-
expect(syntheticEvent.isPersistent()).toBe(false);
76-
syntheticEvent.persist();
77-
expect(syntheticEvent.isPersistent()).toBe(true);
149+
var event = document.createEvent('Event');
150+
event.initEvent('click', true, true);
151+
node.dispatchEvent(event);
152+
153+
expect(syntheticEvent.type).toBe('click');
154+
expect(syntheticEvent.bubbles).toBe(true);
155+
expect(syntheticEvent.cancelable).toBe(true);
156+
expect(expectedCount).toBe(1);
78157
});
79158

80-
it('should be nullified if the synthetic event has called destructor and log warnings', () => {
159+
it('should be nullified and log warnings if the synthetic event has not been persisted', () => {
81160
spyOn(console, 'error');
82-
var target = document.createElement('div');
83-
var syntheticEvent = createEvent({srcElement: target});
84-
syntheticEvent.destructor();
161+
var node;
162+
var expectedCount = 0;
163+
var syntheticEvent;
164+
165+
var eventHandler = e => {
166+
syntheticEvent = e;
167+
168+
expectedCount++;
169+
};
170+
node = ReactDOM.render(<div onClick={eventHandler} />, container);
171+
172+
var event = document.createEvent('Event');
173+
event.initEvent('click', true, true);
174+
node.dispatchEvent(event);
175+
85176
expect(syntheticEvent.type).toBe(null);
86177
expect(syntheticEvent.nativeEvent).toBe(null);
87178
expect(syntheticEvent.target).toBe(null);
@@ -95,14 +186,27 @@ describe('SyntheticEvent', () => {
95186
'keep the original synthetic event around, use event.persist(). ' +
96187
'See https://fb.me/react-event-pooling for more information.',
97188
);
189+
expect(expectedCount).toBe(1);
98190
});
99191

100-
it('should warn when setting properties of a destructored synthetic event', () => {
192+
it('should warn when setting properties of a synthetic event that has not been persisted', () => {
101193
spyOn(console, 'error');
102-
var target = document.createElement('div');
103-
var syntheticEvent = createEvent({srcElement: target});
104-
syntheticEvent.destructor();
105-
expect((syntheticEvent.type = 'MouseEvent')).toBe('MouseEvent');
194+
var node;
195+
var expectedCount = 0;
196+
var syntheticEvent;
197+
198+
var eventHandler = e => {
199+
syntheticEvent = e;
200+
201+
expectedCount++;
202+
};
203+
node = ReactDOM.render(<div onClick={eventHandler} />, container);
204+
205+
var event = document.createEvent('Event');
206+
event.initEvent('click', true, true);
207+
node.dispatchEvent(event);
208+
209+
syntheticEvent.type = 'MouseEvent';
106210
expectDev(console.error.calls.count()).toBe(1);
107211
expectDev(console.error.calls.argsFor(0)[0]).toBe(
108212
'Warning: This synthetic event is reused for performance reasons. If ' +
@@ -111,12 +215,25 @@ describe('SyntheticEvent', () => {
111215
'keep the original synthetic event around, use event.persist(). ' +
112216
'See https://fb.me/react-event-pooling for more information.',
113217
);
218+
expect(expectedCount).toBe(1);
114219
});
115220

116-
it('should warn if the synthetic event has been released when calling `preventDefault`', () => {
221+
it('should warn when calling `preventDefault` if the synthetic event has not been persisted', () => {
117222
spyOn(console, 'error');
118-
var syntheticEvent = createEvent({});
119-
SyntheticEvent.release(syntheticEvent);
223+
var node;
224+
var expectedCount = 0;
225+
var syntheticEvent;
226+
227+
var eventHandler = e => {
228+
syntheticEvent = e;
229+
expectedCount++;
230+
};
231+
node = ReactDOM.render(<div onClick={eventHandler} />, container);
232+
233+
var event = document.createEvent('Event');
234+
event.initEvent('click', true, true);
235+
node.dispatchEvent(event);
236+
120237
syntheticEvent.preventDefault();
121238
expectDev(console.error.calls.count()).toBe(1);
122239
expectDev(console.error.calls.argsFor(0)[0]).toBe(
@@ -126,12 +243,26 @@ describe('SyntheticEvent', () => {
126243
'keep the original synthetic event around, use event.persist(). ' +
127244
'See https://fb.me/react-event-pooling for more information.',
128245
);
246+
expect(expectedCount).toBe(1);
129247
});
130248

131-
it('should warn if the synthetic event has been released when calling `stopPropagation`', () => {
249+
it('should warn when calling `stopPropagation` if the synthetic event has not been persisted', () => {
132250
spyOn(console, 'error');
133-
var syntheticEvent = createEvent({});
134-
SyntheticEvent.release(syntheticEvent);
251+
var node;
252+
var expectedCount = 0;
253+
var syntheticEvent;
254+
255+
var eventHandler = e => {
256+
syntheticEvent = e;
257+
expectedCount++;
258+
};
259+
node = ReactDOM.render(<div onClick={eventHandler} />, container);
260+
261+
var event = document.createEvent('Event');
262+
event.initEvent('click', true, true);
263+
264+
node.dispatchEvent(event);
265+
135266
syntheticEvent.stopPropagation();
136267
expectDev(console.error.calls.count()).toBe(1);
137268
expectDev(console.error.calls.argsFor(0)[0]).toBe(
@@ -141,6 +272,7 @@ describe('SyntheticEvent', () => {
141272
'keep the original synthetic event around, use event.persist(). ' +
142273
'See https://fb.me/react-event-pooling for more information.',
143274
);
275+
expect(expectedCount).toBe(1);
144276
});
145277

146278
// TODO: reenable this test. We are currently silencing these warnings when
@@ -153,8 +285,8 @@ describe('SyntheticEvent', () => {
153285
function assignEvent(e) {
154286
event = e;
155287
}
156-
var instance = ReactDOM.render(<div onClick={assignEvent} />, element);
157-
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance));
288+
var node = ReactDOM.render(<div onClick={assignEvent} />, element);
289+
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(node));
158290
expectDev(console.error.calls.count()).toBe(0);
159291

160292
// access a property to cause the warning
@@ -172,9 +304,22 @@ describe('SyntheticEvent', () => {
172304

173305
it('should warn if Proxy is supported and the synthetic event is added a property', () => {
174306
spyOn(console, 'error');
175-
var syntheticEvent = createEvent({});
176-
syntheticEvent.foo = 'bar';
177-
SyntheticEvent.release(syntheticEvent);
307+
var node;
308+
var expectedCount = 0;
309+
var syntheticEvent;
310+
311+
var eventHandler = e => {
312+
e.foo = 'bar';
313+
syntheticEvent = e;
314+
expectedCount++;
315+
};
316+
node = ReactDOM.render(<div onClick={eventHandler} />, container);
317+
318+
var event = document.createEvent('Event');
319+
event.initEvent('click', true, true);
320+
321+
node.dispatchEvent(event);
322+
178323
expect(syntheticEvent.foo).toBe('bar');
179324
if (typeof Proxy === 'function') {
180325
expectDev(console.error.calls.count()).toBe(1);
@@ -187,5 +332,6 @@ describe('SyntheticEvent', () => {
187332
} else {
188333
expectDev(console.error.calls.count()).toBe(0);
189334
}
335+
expect(expectedCount).toBe(1);
190336
});
191337
});

0 commit comments

Comments
 (0)