-
Notifications
You must be signed in to change notification settings - Fork 47.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite SyntheticEvent tests using public APIs only #11525
Changes from 14 commits
7236c56
c4cdb2a
8d6f118
ff7a9ea
fb0e822
cf2ac41
220d369
b83719b
1758de2
613e878
0697458
850d368
2005d08
7341de0
4fc11e9
f39999b
0421e59
bf69039
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,114 +9,234 @@ | |
|
||
'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; | ||
|
||
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(syntheticEvent.target).toBe(target); | ||
expect(syntheticEvent.type).toBe(undefined); | ||
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); | ||
|
||
expectedCount++; | ||
}; | ||
node = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
expect(syntheticEvent.defaultPrevented).toBe(true); | ||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
node.dispatchEvent(event); | ||
|
||
expect(nativeEvent.returnValue).toBe(false); | ||
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); | ||
Object.defineProperty(event, 'defaultPrevented', { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be |
||
get() { | ||
return true; | ||
}, | ||
}); | ||
node.dispatchEvent(event); | ||
|
||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
// Emulate IE8 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does this test have to do with IE8? The test title says "should be prevented if nativeEvent is prevented". To test this, remove these properties and just call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The previous version of this test had two expectations. On where |
||
Object.defineProperty(event, 'defaultPrevented', { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes sense to me now, thanks for explaining. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just realized that we have dropped support for IE8 and IE9 doesn't use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I want to keep the test for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In other words I'd like to leave this part tested. |
||
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; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
node.dispatchEvent(event); | ||
|
||
expect(expectedCount).toBe(1); | ||
}); | ||
|
||
it('should be able to `persist`', () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this test missing? |
||
var syntheticEvent = createEvent({}); | ||
var node; | ||
var expectedCount = 0; | ||
|
||
var eventHandler = syntheticEvent => { | ||
expect(syntheticEvent.isPersistent()).toBe(false); | ||
syntheticEvent.persist(); | ||
expect(syntheticEvent.isPersistent()).toBe(true); | ||
|
||
expect(syntheticEvent.isPersistent()).toBe(false); | ||
syntheticEvent.persist(); | ||
expect(syntheticEvent.isPersistent()).toBe(true); | ||
expectedCount++; | ||
}; | ||
node = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
node.dispatchEvent(event); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice to test that we can still access Let's save |
||
expect(expectedCount).toBe(1); | ||
}); | ||
|
||
it('should be nullified if the synthetic event has called destructor and log warnings', () => { | ||
spyOn(console, 'error'); | ||
var target = document.createElement('div'); | ||
var syntheticEvent = createEvent({srcElement: target}); | ||
syntheticEvent.destructor(); | ||
expect(syntheticEvent.type).toBe(null); | ||
expect(syntheticEvent.nativeEvent).toBe(null); | ||
expect(syntheticEvent.target).toBe(null); | ||
// once for each property accessed | ||
expectDev(console.error.calls.count()).toBe(3); | ||
// assert the first warning for accessing `type` | ||
expectDev(console.error.calls.argsFor(0)[0]).toBe( | ||
'Warning: This synthetic event is reused for performance reasons. If ' + | ||
"you're seeing this, you're accessing the property `type` on a " + | ||
'released/nullified synthetic event. This is set to null. If you must ' + | ||
'keep the original synthetic event around, use event.persist(). ' + | ||
'See https://fb.me/react-event-pooling for more information.', | ||
); | ||
var node; | ||
var expectedCount = 0; | ||
|
||
var eventHandler = syntheticEvent => { | ||
syntheticEvent.destructor(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a private API. Instead of triggering it explicitly we should save the synthetic event to a variable. Then we should assert at the end of the test (after dispatching events) that accessing them does not work. |
||
expect(syntheticEvent.type).toBe(null); | ||
expect(syntheticEvent.nativeEvent).toBe(null); | ||
expect(syntheticEvent.target).toBe(null); | ||
// once for each property accessed | ||
expectDev(console.error.calls.count()).toBe(3); | ||
// assert the first warning for accessing `type` | ||
expectDev(console.error.calls.argsFor(0)[0]).toBe( | ||
'Warning: This synthetic event is reused for performance reasons. If ' + | ||
"you're seeing this, you're accessing the property `type` on a " + | ||
'released/nullified synthetic event. This is set to null. If you must ' + | ||
'keep the original synthetic event around, use event.persist(). ' + | ||
'See https://fb.me/react-event-pooling for more information.', | ||
); | ||
|
||
expectedCount++; | ||
}; | ||
node = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
node.dispatchEvent(event); | ||
|
||
expect(expectedCount).toBe(1); | ||
}); | ||
|
||
it('should warn when setting properties of a destructored synthetic event', () => { | ||
spyOn(console, 'error'); | ||
var target = document.createElement('div'); | ||
var syntheticEvent = createEvent({srcElement: target}); | ||
syntheticEvent.destructor(); | ||
expect((syntheticEvent.type = 'MouseEvent')).toBe('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 ' + | ||
"you're seeing this, you're setting the property `type` on a " + | ||
'released/nullified synthetic event. This is effectively a no-op. If you must ' + | ||
'keep the original synthetic event around, use event.persist(). ' + | ||
'See https://fb.me/react-event-pooling for more information.', | ||
); | ||
var node; | ||
var expectedCount = 0; | ||
|
||
var eventHandler = syntheticEvent => { | ||
syntheticEvent.destructor(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same |
||
expect((syntheticEvent.type = 'MouseEvent')).toBe('MouseEvent'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this asserting? I don't understand this line. |
||
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 ' + | ||
"you're seeing this, you're setting the property `type` on a " + | ||
'released/nullified synthetic event. This is effectively a no-op. If you must ' + | ||
'keep the original synthetic event around, use event.persist(). ' + | ||
'See https://fb.me/react-event-pooling for more information.', | ||
); | ||
|
||
expectedCount++; | ||
}; | ||
node = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
node.dispatchEvent(event); | ||
|
||
expect(expectedCount).toBe(1); | ||
}); | ||
|
||
it('should warn if the synthetic event has been released when calling `preventDefault`', () => { | ||
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; | ||
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 +246,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 if the synthetic event has been released when calling `stopPropagation`', () => { | ||
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; | ||
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 +276,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 +289,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 +308,23 @@ 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; | ||
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 +337,6 @@ describe('SyntheticEvent', () => { | |
} else { | ||
expectDev(console.error.calls.count()).toBe(0); | ||
} | ||
expect(expectedCount).toBe(1); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same.