-
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 5 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,249 @@ | |
|
||
'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 instance; | ||
var expectedCount = 0; | ||
|
||
var eventHandler = syntheticEvent => { | ||
expect(syntheticEvent.target).toBe(instance); | ||
|
||
expectedCount++; | ||
}; | ||
instance = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
expect(syntheticEvent.target).toBe(target); | ||
expect(syntheticEvent.type).toBe(undefined); | ||
var event; | ||
event = document.createEvent('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. Style nit: let's include assignment into definition? |
||
event.initEvent('click', true, true); | ||
// Emulate IE8 | ||
Object.defineProperty(event, 'target', { | ||
get() {}, | ||
}); | ||
Object.defineProperty(event, 'srcElement', { | ||
get() { | ||
return instance; | ||
}, | ||
}); | ||
instance.dispatchEvent(event); | ||
|
||
expect(expectedCount).toBe(1); | ||
}); | ||
|
||
it('should be able to `preventDefault`', () => { | ||
var nativeEvent = {}; | ||
var syntheticEvent = createEvent(nativeEvent); | ||
var instance; | ||
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); | ||
// TODO: Figure out why this is undefined when switching to public API | ||
// expect(nativeEvent.returnValue).toBe(false); | ||
|
||
expect(syntheticEvent.defaultPrevented).toBe(true); | ||
expectedCount++; | ||
}; | ||
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. |
||
instance = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
expect(nativeEvent.returnValue).toBe(false); | ||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
instance.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 instance; | ||
var expectedCount = 0; | ||
|
||
var eventHandler = syntheticEvent => { | ||
expect(syntheticEvent.isDefaultPrevented()).toBe(true); | ||
|
||
expectedCount++; | ||
}; | ||
instance = 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; | ||
}, | ||
}); | ||
instance.dispatchEvent(event); | ||
|
||
// TODO: figure out why this fails | ||
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'm currently investigating this. |
||
// event = document.createEvent('Event'); | ||
// event.initEvent('click', true, true); | ||
// Object.defineProperty(event, 'returnValue', { | ||
// get(){ | ||
// return false; | ||
// } | ||
// }); | ||
// instance.dispatchEvent(event); | ||
|
||
// TODO: change to 2 when problem above is resolved | ||
expect(expectedCount).toBe(1); | ||
}); | ||
|
||
it('should be able to `stopPropagation`', () => { | ||
var nativeEvent = {}; | ||
var syntheticEvent = createEvent(nativeEvent); | ||
var instance; | ||
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); | ||
// TODO: Figure out why this is undefined when switching to public API | ||
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'm currently investigating this. |
||
// expect(nativeEvent.cancelBubble).toBe(true); | ||
|
||
expect(nativeEvent.cancelBubble).toBe(true); | ||
expectedCount++; | ||
}; | ||
instance = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
instance.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({}); | ||
it('should be able to `stopPropagation`', () => { | ||
var instance; | ||
var expectedCount = 0; | ||
|
||
var eventHandler = syntheticEvent => { | ||
expect(syntheticEvent.isPersistent()).toBe(false); | ||
syntheticEvent.persist(); | ||
expect(syntheticEvent.isPersistent()).toBe(true); | ||
// TODO: Figure out why this is undefined when switching to public API | ||
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'm currently investigating this. |
||
// expect(nativeEvent.cancelBubble).toBe(true); | ||
|
||
expectedCount++; | ||
}; | ||
instance = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
instance.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(syntheticEvent.isPersistent()).toBe(false); | ||
syntheticEvent.persist(); | ||
expect(syntheticEvent.isPersistent()).toBe(true); | ||
expect(expectedCount).toBe(1); | ||
}); | ||
|
||
it('should be nullified if the synthetic event has called destructor and log warnings', () => { | ||
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 instance; | ||
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++; | ||
}; | ||
instance = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
Object.defineProperty(event, 'srcElement', { | ||
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. Again, this is specific to IE8 and there is just a single test needed for this. There's no need to add |
||
get() { | ||
return instance; | ||
}, | ||
}); | ||
instance.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 instance; | ||
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++; | ||
}; | ||
instance = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
Object.defineProperty(event, 'srcElement', { | ||
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. |
||
get() { | ||
return instance; | ||
}, | ||
}); | ||
instance.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 instance; | ||
var expectedCount = 0; | ||
var syntheticEvent; | ||
|
||
var eventHandler = e => { | ||
syntheticEvent = e; | ||
expectedCount++; | ||
}; | ||
instance = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
instance.dispatchEvent(event); | ||
|
||
syntheticEvent.preventDefault(); | ||
expectDev(console.error.calls.count()).toBe(1); | ||
expectDev(console.error.calls.argsFor(0)[0]).toBe( | ||
|
@@ -126,12 +261,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 instance; | ||
var expectedCount = 0; | ||
var syntheticEvent; | ||
|
||
var eventHandler = e => { | ||
syntheticEvent = e; | ||
expectedCount++; | ||
}; | ||
instance = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
|
||
instance.dispatchEvent(event); | ||
|
||
syntheticEvent.stopPropagation(); | ||
expectDev(console.error.calls.count()).toBe(1); | ||
expectDev(console.error.calls.argsFor(0)[0]).toBe( | ||
|
@@ -141,6 +291,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 | ||
|
@@ -172,9 +323,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 instance; | ||
var expectedCount = 0; | ||
var syntheticEvent; | ||
|
||
var eventHandler = e => { | ||
e.foo = 'bar'; | ||
syntheticEvent = e; | ||
expectedCount++; | ||
}; | ||
instance = ReactDOM.render(<div onClick={eventHandler} />, container); | ||
|
||
var event; | ||
event = document.createEvent('Event'); | ||
event.initEvent('click', true, true); | ||
|
||
instance.dispatchEvent(event); | ||
|
||
expect(syntheticEvent.foo).toBe('bar'); | ||
if (typeof Proxy === 'function') { | ||
expectDev(console.error.calls.count()).toBe(1); | ||
|
@@ -187,5 +352,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.
Let's rename this to node. It's not a React instance.