Skip to content
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

Merged
merged 17 commits into from Jul 24, 2017
Merged

Conversation

jongrim
Copy link
Contributor

@jongrim jongrim commented Jul 13, 2017

  • Fixes Polyfill Event constructor #9597.
  • Implements a polyfill for the Event constructor for older browsers (IE 9+).
  • Replaces usages of document.createEvent with new Event.

There is one location where I did not replace the usage of document.createEvent. It's in test/functional/test-event-helper.js, line 236. The test is creating a custom function to assign to document.createEvent so I've left it alone.

@googlebot
Copy link

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!) and we'll verify. Thanks.


  • If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address. Check your existing CLA data and verify that your email is set on your git commits.
  • If your company signed a CLA, they designated a Point of Contact who decides which employees are authorized to participate. You may need to contact the Point of Contact for your company and ask to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the project maintainer to go/cla#troubleshoot.
  • In order to pass this check, please resolve this problem and have the pull request author add another comment and the bot will run again.

@jongrim
Copy link
Contributor Author

jongrim commented Jul 13, 2017

I signed it!

@googlebot
Copy link

CLAs look good, thanks!

@jongrim jongrim mentioned this pull request Jul 13, 2017
12 tasks
@dreamofabear dreamofabear self-requested a review July 13, 2017 18:19
Copy link

@dreamofabear dreamofabear left a 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';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: Please alphabetize.

// win.Event is a function on Edge, Chrome, FF, Safari but
// is an object on IE 11.
if (typeof win.Event === 'function') {
return false;

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.

params.bubbles,
params.cancelable,
params.detail
);

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

return false;
}

function Event(event, params) {

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
return;
}

function Event(name, params) {

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.

Copy link

@dreamofabear dreamofabear left a 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.


/**
*@constructor
*/

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
 */

Copy link
Contributor Author

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;

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?

Copy link
Contributor Author

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.

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);

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.

Copy link
Contributor Author

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!

@jongrim
Copy link
Contributor Author

jongrim commented Jul 18, 2017

@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.

@dreamofabear
Copy link

Good question. 😅 Looks like a recent build change we've made -- looking into it.

@rsimha
Copy link
Contributor

rsimha commented Jul 18, 2017

@jongrim, that was my fault. A fix is imminent with #10516. Stay tuned.

Edit: Fix is merged. You should now see a summary of failed tests at the end of the run. You might need to sync your branch to upstream master to see the changes.

@dreamofabear
Copy link

@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 this.Event = window.Event to the FakeWindow constructor in fake-dom.js.

@jongrim
Copy link
Contributor Author

jongrim commented Jul 19, 2017

🎉
Thanks for the guidance @choumx!

Copy link

@dreamofabear dreamofabear left a 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(

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.

@@ -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});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

@@ -64,6 +64,8 @@ export class FakeWindow {
this.DOMTokenList = window.DOMTokenList;
/** @const */
this.Math = window.Math;
/**@const */

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;

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();
});

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;

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;

@dreamofabear dreamofabear merged commit 28f709f into ampproject:master Jul 24, 2017
@dreamofabear
Copy link

Thanks for contributing to AMP @jongrim! 🎉

I hope you'll continue and become a regular contributor here. 😃 We'll be working on writing great second (and third) issues soon, so stay tuned!

In the meantime, please reach out to me @choumx or Joey @mrjoro on Slack.

@jongrim
Copy link
Contributor Author

jongrim commented Jul 25, 2017

Awesome! I'll be on the lookout for more issues. Thanks for the help and making the process super easy and welcoming 👏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants