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
Add Event constructor polyfill #10401
Conversation
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed, please reply here (e.g.
|
I signed it! |
CLAs look good, thanks! |
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.
Looks good overall! 👍
There's a couple of lint errors on the Travis build. Can you fix those too please?
src/polyfills.js
Outdated
import {install as installDocContains} from './polyfills/document-contains'; | ||
import {install as installMathSign} from './polyfills/math-sign'; | ||
import {install as installObjectAssign} from './polyfills/object-assign'; | ||
import {install as installPromise} from './polyfills/promise'; | ||
import {install as installArrayIncludes} from './polyfills/array-includes'; | ||
import {getMode} from './mode'; | ||
import {install as installEvent} from './polyfills/event'; |
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.
Minor: Please alphabetize.
src/polyfills/event.js
Outdated
// win.Event is a function on Edge, Chrome, FF, Safari but | ||
// is an object on IE 11. | ||
if (typeof win.Event === 'function') { | ||
return false; |
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.
return;
since this function doesn't have a return value in other cases.
src/polyfills/event.js
Outdated
params.bubbles, | ||
params.cancelable, | ||
params.detail | ||
); |
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.
Event.initEvent
doesn't take a detail
param (CustomEvent does). https://developer.mozilla.org/en-US/docs/Web/API/Event/initEvent
src/polyfills/event.js
Outdated
return false; | ||
} | ||
|
||
function Event(event, params) { |
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.
Minor: Let's use name
instead of event
here to be clearer.
- Alphabetizes imports in polyfills.js - Corrects spacing and line lengths per linting rules - Corrects return in Event polyfill - Renames event type parameter - Corrects Event initialization and removes details parameter
src/polyfills/event.js
Outdated
return; | ||
} | ||
|
||
function Event(name, params) { |
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.
The current Travis error is a Closure compiler type error that seems to dislike the fact that this isn't a new-only constructor function (i.e. ES6 class). I'd try fixing it by changing this to be an ES6 class. If that doesn't work, type-cast. 😄
You can re-run the type checker locally by running gulp check-types
.
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.
Final stretch! 💪
Last thing I'd ask is to add a unit test to the test/functional
folder. Check out the other polyfill tests for an example, e.g. test-polyfill-array-includes.js.
src/polyfills/event.js
Outdated
|
||
/** | ||
*@constructor | ||
*/ |
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.
Nice, didn't know that @constructor
would solve it. 👍
Minor issue:
/**
* @constructor
*/
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.
Actually, this isn't what made it pass the type-check. It was not assigning directly to win.Event and instead using Object.defineProperty.
I included this because I read in the docs that @constructor
should be used if a function will be a constructor. I don't really understand the compiler well enough to know if this makes a difference though.
I will correct the spacing, but I could also completely remove this if it's not helpful.
|
||
beforeEach(() => { | ||
env.win.Event = Object.create(self.Event.prototype); | ||
env.win.Event.prototype = self.Event.prototype; |
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.
Are these two lines necessary?
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.
Yes, without this the beforeEach
hook fails due to a TypeError originating from event.js
. It tries to assign window.Event.prototype as the prototype of the newly created function, but throws an error because window.Event is undefined (recall that the prototype assignment happens before we assign the new function to window.Event). I believe these two lines effectively mimic IE 9+ as well, i.e. window.Event is an object, and not function.
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.
Gotcha, can you add a comment describing this please?
}); | ||
|
||
it('should require a type argument', () => { | ||
expect(() => new Event()).to.throw(TypeError); |
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.
We should make sure we're instantiating env.win
's Event rather than the test server's Event.
new env.win.Event
here and elsewhere.
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.
Doh, that makes sense. Done!
@choumx How do I identify which tests are failing with Travis CI? There are those 5 Video Player tests that consistently fail locally, so I'm assuming they are included, but the others are variable locally. Sometimes they pass and sometimes they fail. |
Good question. 😅 Looks like a recent build change we've made -- looking into it. |
@jongrim I reran the Travis build and you can see the test failures now. The video tests are failing because they use a fake Window object where the polyfill isn't installed. You can fix it by adding |
🎉 |
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.
Looking great! Last few changes before merge. 🎉
@@ -866,8 +866,10 @@ export class AmpLiveList extends AMP.BaseElement { | |||
} | |||
|
|||
sendAmpDomUpdateEvent_() { | |||
const event = this.win.document.createEvent('Event'); | |||
event.initEvent(AmpEvents.DOM_UPDATE, true, true); | |||
const event = new this.win.Event( |
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.
const event = new Event(
There are situations where we embed an AMP doc inside another AMP doc, wrapped in an iframe. In those cases, the polyfill won't be installed in the iframe's window so we should make sure we construct events using the top window.
src/custom-element.js
Outdated
@@ -1111,9 +1111,8 @@ function createBaseCustomElementClass(win) { | |||
const data = opt_data || {}; | |||
// Constructors of events need to come from the correct window. Sigh. | |||
const win = this.ownerDocument.defaultView; | |||
const event = win.document.createEvent('Event'); | |||
const event = new win.Event(name, {bubbles: true, cancelable: true}); |
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.
Ditto.
testing/fake-dom.js
Outdated
@@ -64,6 +64,8 @@ export class FakeWindow { | |||
this.DOMTokenList = window.DOMTokenList; | |||
/** @const */ | |||
this.Math = window.Math; | |||
/**@const */ |
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.
Nitpick: Space padding. 😅
/** @const */
|
||
beforeEach(() => { | ||
env.win.Event = Object.create(self.Event.prototype); | ||
env.win.Event.prototype = self.Event.prototype; |
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.
Gotcha, can you add a comment describing this please?
const ev = new env.win.Event('event'); | ||
const elm = document.createElement('p'); | ||
expect(() => elm.dispatchEvent(ev)).to.not.throw(); | ||
}); |
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.
This test case seems to be covered by the next one so I think it can be removed.
it('should be configurable', () => { | ||
const ev = new env.win.Event('event', {bubbles: true, cancelable: true}); | ||
expect(ev.bubbles).to.be.true; | ||
expect(ev.cancelable).to.be.true; |
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.
Would you mind adding another case to this test? This protects against the case where bubbles/cancelable are always true.
const defaultEvent = new env.win.Event('event');
expect(defaultEvent.bubbles).to.be.false;
expect(defaultEvent.cancelable).to.be.false;
Awesome! I'll be on the lookout for more issues. Thanks for the help and making the process super easy and welcoming 👏 |
This reverts commit 28f709f.
document.createEvent
withnew Event
.There is one location where I did not replace the usage of
document.createEvent
. It's intest/functional/test-event-helper.js
, line 236. The test is creating a custom function to assign todocument.createEvent
so I've left it alone.