@samitouri / QOS-React / commits / 669a70dab7

Rewrite SyntheticEvent tests using public APIs only (#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

Tim Jacobi committed Nov 20, 2017 at 14:29 UTC 669a70dab789d58a7c26ec8b4bb897eef37466fa
1 file changed +199 -53
packages/react-dom/src/events/__tests__/SyntheticEvent-test.js
+199 -53
@@ -9,79 +9,170 @@
9
10 'use strict';
11
12 -var SyntheticEvent;
12 var React;
13 var ReactDOM;
14 var ReactTestUtils;
15
16 describe('SyntheticEvent', () => {
18 - var createEvent;
17 + var container;
18
19 beforeEach(() => {
21 - // TODO: can we express this test with only public API?
22 - SyntheticEvent = require('events/SyntheticEvent').default;
20 React = require('react');
21 ReactDOM = require('react-dom');
22 ReactTestUtils = require('react-dom/test-utils');
23
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;
31 });
32
33 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);
56
37 - expect(syntheticEvent.target).toBe(target);
38 - expect(syntheticEvent.type).toBe(undefined);
57 + expect(expectedCount).toBe(1);
58 });
59
60 it('should be able to `preventDefault`', () => {
42 - var nativeEvent = {};
43 - var syntheticEvent = createEvent(nativeEvent);
61 + var node;
62 + var expectedCount = 0;
63
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);
73
49 - expect(syntheticEvent.defaultPrevented).toBe(true);
74 + var event = document.createEvent('Event');
75 + event.initEvent('click', true, true);
76 + node.dispatchEvent(event);
77
51 - expect(nativeEvent.returnValue).toBe(false);
78 + expect(expectedCount).toBe(1);
79 });
80
81 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);
112 });
113
114 it('should be able to `stopPropagation`', () => {
62 - var nativeEvent = {};
63 - var syntheticEvent = createEvent(nativeEvent);
115 + var node;
116 + var expectedCount = 0;
117
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);
122
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);
132 });
133
134 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);
148
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);
157 });
158
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', () => {
160 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 +
176 expect(syntheticEvent.type).toBe(null);
177 expect(syntheticEvent.nativeEvent).toBe(null);
178 expect(syntheticEvent.target).toBe(null);
@@ -95,14 +186,27 @@ describe('SyntheticEvent', () => {
186 'keep the original synthetic event around, use event.persist(). ' +
187 'See https://fb.me/react-event-pooling for more information.',
188 );
189 + expect(expectedCount).toBe(1);
190 });
191
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', () => {
193 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';
210 expectDev(console.error.calls.count()).toBe(1);
211 expectDev(console.error.calls.argsFor(0)[0]).toBe(
212 'Warning: This synthetic event is reused for performance reasons. If ' +
@@ -111,12 +215,25 @@ describe('SyntheticEvent', () => {
215 'keep the original synthetic event around, use event.persist(). ' +
216 'See https://fb.me/react-event-pooling for more information.',
217 );
218 + expect(expectedCount).toBe(1);
219 });
220
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', () => {
222 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 +
237 syntheticEvent.preventDefault();
238 expectDev(console.error.calls.count()).toBe(1);
239 expectDev(console.error.calls.argsFor(0)[0]).toBe(
@@ -126,12 +243,26 @@ describe('SyntheticEvent', () => {
243 'keep the original synthetic event around, use event.persist(). ' +
244 'See https://fb.me/react-event-pooling for more information.',
245 );
246 + expect(expectedCount).toBe(1);
247 });
248
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', () => {
250 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 +
266 syntheticEvent.stopPropagation();
267 expectDev(console.error.calls.count()).toBe(1);
268 expectDev(console.error.calls.argsFor(0)[0]).toBe(
@@ -141,6 +272,7 @@ describe('SyntheticEvent', () => {
272 'keep the original synthetic event around, use event.persist(). ' +
273 'See https://fb.me/react-event-pooling for more information.',
274 );
275 + expect(expectedCount).toBe(1);
276 });
277
278 // TODO: reenable this test. We are currently silencing these warnings when
@@ -153,8 +285,8 @@ describe('SyntheticEvent', () => {
285 function assignEvent(e) {
286 event = e;
287 }
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));
290 expectDev(console.error.calls.count()).toBe(0);
291
292 // access a property to cause the warning
@@ -172,9 +304,22 @@ describe('SyntheticEvent', () => {
304
305 it('should warn if Proxy is supported and the synthetic event is added a property', () => {
306 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 +
323 expect(syntheticEvent.foo).toBe('bar');
324 if (typeof Proxy === 'function') {
325 expectDev(console.error.calls.count()).toBe(1);
@@ -187,5 +332,6 @@ describe('SyntheticEvent', () => {
332 } else {
333 expectDev(console.error.calls.count()).toBe(0);
334 }
335 + expect(expectedCount).toBe(1);
336 });
337 });