mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
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
This commit is contained in:
1 parent
bd9dbd5d60
commit
669a70dab7
1 file changed
+199
-53
+199
-53
@@ -9,79 +9,170 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var SyntheticEvent;
|
||||
var React;
|
||||
var ReactDOM;
|
||||
var ReactTestUtils;
|
||||
|
||||
describe('SyntheticEvent', () => {
|
||||
var createEvent;
|
||||
var container;
|
||||
|
||||
beforeEach(() => {
|
||||
// TODO: can we express this test with only public API?
|
||||
SyntheticEvent = require('events/SyntheticEvent').default;
|
||||
React = require('react');
|
||||
ReactDOM = require('react-dom');
|
||||
ReactTestUtils = require('react-dom/test-utils');
|
||||
|
||||
createEvent = function(nativeEvent) {
|
||||
var target = require('../getEventTarget').default(nativeEvent);
|
||||
return SyntheticEvent.getPooled({}, '', nativeEvent, target);
|
||||
};
|
||||
container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.removeChild(container);
|
||||
container = null;
|
||||
});
|
||||
|
||||
it('should normalize `target` from the nativeEvent', () => {
|
||||
var target = document.createElement('div');
|
||||
var syntheticEvent = createEvent({srcElement: target});
|
||||
var node;
|
||||
var expectedCount = 0;
|
||||
|
||||
expect(syntheticEvent.target).toBe(target);
|
||||
expect(syntheticEvent.type).toBe(undefined);
|
||||
var eventHandler = syntheticEvent => {
|
||||
expect(syntheticEvent.target).toBe(node);
|
||||
|
||||
expectedCount++;
|
||||
};
|
||||
node = ReactDOM.render(<div onClick={eventHandler} />, container);
|
||||
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
// Emulate IE8
|
||||
Object.defineProperty(event, 'target', {
|
||||
get() {},
|
||||
});
|
||||
Object.defineProperty(event, 'srcElement', {
|
||||
get() {
|
||||
return node;
|
||||
},
|
||||
});
|
||||
node.dispatchEvent(event);
|
||||
|
||||
expect(expectedCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should be able to `preventDefault`', () => {
|
||||
var nativeEvent = {};
|
||||
var syntheticEvent = createEvent(nativeEvent);
|
||||
var node;
|
||||
var expectedCount = 0;
|
||||
|
||||
expect(syntheticEvent.isDefaultPrevented()).toBe(false);
|
||||
syntheticEvent.preventDefault();
|
||||
expect(syntheticEvent.isDefaultPrevented()).toBe(true);
|
||||
var eventHandler = syntheticEvent => {
|
||||
expect(syntheticEvent.isDefaultPrevented()).toBe(false);
|
||||
syntheticEvent.preventDefault();
|
||||
expect(syntheticEvent.isDefaultPrevented()).toBe(true);
|
||||
expect(syntheticEvent.defaultPrevented).toBe(true);
|
||||
|
||||
expect(syntheticEvent.defaultPrevented).toBe(true);
|
||||
expectedCount++;
|
||||
};
|
||||
node = ReactDOM.render(<div onClick={eventHandler} />, container);
|
||||
|
||||
expect(nativeEvent.returnValue).toBe(false);
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
node.dispatchEvent(event);
|
||||
|
||||
expect(expectedCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should be prevented if nativeEvent is prevented', () => {
|
||||
expect(createEvent({defaultPrevented: true}).isDefaultPrevented()).toBe(
|
||||
true,
|
||||
);
|
||||
expect(createEvent({returnValue: false}).isDefaultPrevented()).toBe(true);
|
||||
var node;
|
||||
var expectedCount = 0;
|
||||
|
||||
var eventHandler = syntheticEvent => {
|
||||
expect(syntheticEvent.isDefaultPrevented()).toBe(true);
|
||||
|
||||
expectedCount++;
|
||||
};
|
||||
node = ReactDOM.render(<div onClick={eventHandler} />, container);
|
||||
|
||||
var event;
|
||||
event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
event.preventDefault();
|
||||
node.dispatchEvent(event);
|
||||
|
||||
event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
// Emulate IE8
|
||||
Object.defineProperty(event, 'defaultPrevented', {
|
||||
get() {},
|
||||
});
|
||||
Object.defineProperty(event, 'returnValue', {
|
||||
get() {
|
||||
return false;
|
||||
},
|
||||
});
|
||||
node.dispatchEvent(event);
|
||||
|
||||
expect(expectedCount).toBe(2);
|
||||
});
|
||||
|
||||
it('should be able to `stopPropagation`', () => {
|
||||
var nativeEvent = {};
|
||||
var syntheticEvent = createEvent(nativeEvent);
|
||||
var node;
|
||||
var expectedCount = 0;
|
||||
|
||||
expect(syntheticEvent.isPropagationStopped()).toBe(false);
|
||||
syntheticEvent.stopPropagation();
|
||||
expect(syntheticEvent.isPropagationStopped()).toBe(true);
|
||||
var eventHandler = syntheticEvent => {
|
||||
expect(syntheticEvent.isPropagationStopped()).toBe(false);
|
||||
syntheticEvent.stopPropagation();
|
||||
expect(syntheticEvent.isPropagationStopped()).toBe(true);
|
||||
|
||||
expect(nativeEvent.cancelBubble).toBe(true);
|
||||
expectedCount++;
|
||||
};
|
||||
node = ReactDOM.render(<div onClick={eventHandler} />, container);
|
||||
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
node.dispatchEvent(event);
|
||||
|
||||
expect(expectedCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should be able to `persist`', () => {
|
||||
var syntheticEvent = createEvent({});
|
||||
var node;
|
||||
var expectedCount = 0;
|
||||
var syntheticEvent;
|
||||
|
||||
expect(syntheticEvent.isPersistent()).toBe(false);
|
||||
syntheticEvent.persist();
|
||||
expect(syntheticEvent.isPersistent()).toBe(true);
|
||||
var eventHandler = e => {
|
||||
expect(e.isPersistent()).toBe(false);
|
||||
e.persist();
|
||||
syntheticEvent = e;
|
||||
expect(e.isPersistent()).toBe(true);
|
||||
|
||||
expectedCount++;
|
||||
};
|
||||
node = ReactDOM.render(<div onClick={eventHandler} />, container);
|
||||
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
node.dispatchEvent(event);
|
||||
|
||||
expect(syntheticEvent.type).toBe('click');
|
||||
expect(syntheticEvent.bubbles).toBe(true);
|
||||
expect(syntheticEvent.cancelable).toBe(true);
|
||||
expect(expectedCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should be nullified if the synthetic event has called destructor and log warnings', () => {
|
||||
it('should be nullified and log warnings if the synthetic event has not been persisted', () => {
|
||||
spyOn(console, 'error');
|
||||
var target = document.createElement('div');
|
||||
var syntheticEvent = createEvent({srcElement: target});
|
||||
syntheticEvent.destructor();
|
||||
var node;
|
||||
var expectedCount = 0;
|
||||
var syntheticEvent;
|
||||
|
||||
var eventHandler = e => {
|
||||
syntheticEvent = e;
|
||||
|
||||
expectedCount++;
|
||||
};
|
||||
node = ReactDOM.render(<div onClick={eventHandler} />, container);
|
||||
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
node.dispatchEvent(event);
|
||||
|
||||
expect(syntheticEvent.type).toBe(null);
|
||||
expect(syntheticEvent.nativeEvent).toBe(null);
|
||||
expect(syntheticEvent.target).toBe(null);
|
||||
@@ -95,14 +186,27 @@ describe('SyntheticEvent', () => {
|
||||
'keep the original synthetic event around, use event.persist(). ' +
|
||||
'See https://fb.me/react-event-pooling for more information.',
|
||||
);
|
||||
expect(expectedCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should warn when setting properties of a destructored synthetic event', () => {
|
||||
it('should warn when setting properties of a synthetic event that has not been persisted', () => {
|
||||
spyOn(console, 'error');
|
||||
var target = document.createElement('div');
|
||||
var syntheticEvent = createEvent({srcElement: target});
|
||||
syntheticEvent.destructor();
|
||||
expect((syntheticEvent.type = 'MouseEvent')).toBe('MouseEvent');
|
||||
var node;
|
||||
var expectedCount = 0;
|
||||
var syntheticEvent;
|
||||
|
||||
var eventHandler = e => {
|
||||
syntheticEvent = e;
|
||||
|
||||
expectedCount++;
|
||||
};
|
||||
node = ReactDOM.render(<div onClick={eventHandler} />, container);
|
||||
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
node.dispatchEvent(event);
|
||||
|
||||
syntheticEvent.type = 'MouseEvent';
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
'Warning: This synthetic event is reused for performance reasons. If ' +
|
||||
@@ -111,12 +215,25 @@ describe('SyntheticEvent', () => {
|
||||
'keep the original synthetic event around, use event.persist(). ' +
|
||||
'See https://fb.me/react-event-pooling for more information.',
|
||||
);
|
||||
expect(expectedCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should warn if the synthetic event has been released when calling `preventDefault`', () => {
|
||||
it('should warn when calling `preventDefault` if the synthetic event has not been persisted', () => {
|
||||
spyOn(console, 'error');
|
||||
var syntheticEvent = createEvent({});
|
||||
SyntheticEvent.release(syntheticEvent);
|
||||
var node;
|
||||
var expectedCount = 0;
|
||||
var syntheticEvent;
|
||||
|
||||
var eventHandler = e => {
|
||||
syntheticEvent = e;
|
||||
expectedCount++;
|
||||
};
|
||||
node = ReactDOM.render(<div onClick={eventHandler} />, container);
|
||||
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
node.dispatchEvent(event);
|
||||
|
||||
syntheticEvent.preventDefault();
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
@@ -126,12 +243,26 @@ describe('SyntheticEvent', () => {
|
||||
'keep the original synthetic event around, use event.persist(). ' +
|
||||
'See https://fb.me/react-event-pooling for more information.',
|
||||
);
|
||||
expect(expectedCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should warn if the synthetic event has been released when calling `stopPropagation`', () => {
|
||||
it('should warn when calling `stopPropagation` if the synthetic event has not been persisted', () => {
|
||||
spyOn(console, 'error');
|
||||
var syntheticEvent = createEvent({});
|
||||
SyntheticEvent.release(syntheticEvent);
|
||||
var node;
|
||||
var expectedCount = 0;
|
||||
var syntheticEvent;
|
||||
|
||||
var eventHandler = e => {
|
||||
syntheticEvent = e;
|
||||
expectedCount++;
|
||||
};
|
||||
node = ReactDOM.render(<div onClick={eventHandler} />, container);
|
||||
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
|
||||
node.dispatchEvent(event);
|
||||
|
||||
syntheticEvent.stopPropagation();
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
expectDev(console.error.calls.argsFor(0)[0]).toBe(
|
||||
@@ -141,6 +272,7 @@ describe('SyntheticEvent', () => {
|
||||
'keep the original synthetic event around, use event.persist(). ' +
|
||||
'See https://fb.me/react-event-pooling for more information.',
|
||||
);
|
||||
expect(expectedCount).toBe(1);
|
||||
});
|
||||
|
||||
// TODO: reenable this test. We are currently silencing these warnings when
|
||||
@@ -153,8 +285,8 @@ describe('SyntheticEvent', () => {
|
||||
function assignEvent(e) {
|
||||
event = e;
|
||||
}
|
||||
var instance = ReactDOM.render(<div onClick={assignEvent} />, element);
|
||||
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance));
|
||||
var node = ReactDOM.render(<div onClick={assignEvent} />, element);
|
||||
ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(node));
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
|
||||
// access a property to cause the warning
|
||||
@@ -172,9 +304,22 @@ describe('SyntheticEvent', () => {
|
||||
|
||||
it('should warn if Proxy is supported and the synthetic event is added a property', () => {
|
||||
spyOn(console, 'error');
|
||||
var syntheticEvent = createEvent({});
|
||||
syntheticEvent.foo = 'bar';
|
||||
SyntheticEvent.release(syntheticEvent);
|
||||
var node;
|
||||
var expectedCount = 0;
|
||||
var syntheticEvent;
|
||||
|
||||
var eventHandler = e => {
|
||||
e.foo = 'bar';
|
||||
syntheticEvent = e;
|
||||
expectedCount++;
|
||||
};
|
||||
node = ReactDOM.render(<div onClick={eventHandler} />, container);
|
||||
|
||||
var event = document.createEvent('Event');
|
||||
event.initEvent('click', true, true);
|
||||
|
||||
node.dispatchEvent(event);
|
||||
|
||||
expect(syntheticEvent.foo).toBe('bar');
|
||||
if (typeof Proxy === 'function') {
|
||||
expectDev(console.error.calls.count()).toBe(1);
|
||||
@@ -187,5 +332,6 @@ describe('SyntheticEvent', () => {
|
||||
} else {
|
||||
expectDev(console.error.calls.count()).toBe(0);
|
||||
}
|
||||
expect(expectedCount).toBe(1);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user