Phantomjs: '[object EventConstructor]' is not a constructor

Created on 4 May 2013  Â·  66Comments  Â·  Source: ariya/phantomjs

This seems like a PhantomJS bug, but feel free to educate me if otherwise.

If I put new Event(message) in a Jasmine test and run it under PhantomJS's headless browser, I get an error saying '[object EventConstructor]' is not a constructor. This is weird, considering EventConstructor is probably really a constructor. If I run the Jasmine test normally (i.e. fire up a Jasmine server and let the test run in my actual browser), it works.

To fix the test on Phantom, I have to change new Event(); to document.createEvent();, which is deprecated.

Confirmed stale

Most helpful comment

For others who might stumble on this from Google, this is how I managed to facilitate my own tests that used keyboard events manually. The reason I had to do this was that I couldn't use $('#foo').keyup() as jQuery's trigger would not fire the browser's events that were added via addEventListener but only events that were attached through the jQuery's API. (Pasted gist available for commenting):

// <input id="my-input-element" type="text" value="foo"/>
var evt, node = document.getElementById('my-input-element');

// Have to use dispatchEvent/fireEvent because jQuery.trigger will not
// fire an event attached via addEventListener. Each environment has an
// unusual way to trigger a keyup event.
if (node.dispatchEvent) {
  // Sane browsers
  try {
    // Chrome, Safari, Firefox
    evt = new KeyboardEvent('keyup');
  } catch (e) {
    // PhantomJS (wat!)
    evt = document.createEvent('KeyboardEvent');
    evt.initEvent('keyup', true, false);
  }
  evt.keyCode = 32;
  node.dispatchEvent(evt);
} else {
  // IE 8
  evt = document.createEventObject('KeyboardEvent');
  evt.keyCode = 32;
  node.fireEvent('onkeyup', evt);
}

The situation I had to got me there was that I was in a test runner which had jQuery available for doing fixtures and testing assertions but the code I was testing (read: module) needed to be jQuery free. That code would attach to DOM events via addEventListener but when the test script attempted to trigger the event via jQuery it was ignored. Forcing me to trigger the event manually in all the browser environments.

All 66 comments

I don't see new Event mentioned anywhere in the DOM4 spec, only derived types like new UIEvent, new MouseEvent, etc.

Even with the spec considered, I've personally never seen this used in the real world nor have I really found any practical documentation examples (i.e. on MDN, WebPlatform, etc.), so this must be a pretty new shift (which also means it likely isn't supported in PhantomJS yet as we have an older version of WebKit at the moment). If you know of any good documentation, please share it for my own edification.

The MDN says to "use event constructors instead" here: https://developer.mozilla.org/en-US/docs/DOM/document.createEvent

If this isn't official, then I can retract this, but it is perturbing. MDN is where everybody points me to for JS-related docs, so I'm taking this as true.

But that doesn't seem to be my issue, I guess. I didn't realize that there are sub-constructors for specific event types that must be used. If that's the case, I'll give that a shot, and we can close this issue.

I _did_ find a reference to new Event after a second look at the DOM Level 4 spec: http://www.w3.org/TR/domcore/#concept-event

However, MDN's deprecation warning seems a bit premature since the spec is still only a draft. :confused:

I'm also having this issue when trying to test that an event listener calls the right callback when an event occurs:

✘ sets the field value to the text
        ➤ TypeError: '[object EventConstructor]' is not a constructor (evaluating 'new Event('message')') in http://localhost:56873/assets/spec.js (line 42731)

but document.createEvent('message') doesn't work for me either.

 ➤ NOT_SUPPORTED_ERR: NOT_SUPPORTED_ERR: DOM Exception 9 in http://localhost:56873/assets/spec.js (line 42708)

@carlthuringer: You're getting an error because you're not using document.createEvent correctly. Check out the suggested polyfill on MDN to easily see how document.createEvent and new CustomEvent differ.

TL;DR:
You need to do some like this:

var evt = document.createEvent('CustomEvent');  // MUST be 'CustomEvent'
evt.initCustomEvent('yourCustomEventName', false, false, null);

Awesome, thanks for the quick explanation and response!

+1

Also getting this error, except it's in a 3rd party library I have no access to. new Event('click') doesn't throw an error in the browser, so it would be nice if it didn't throw an error in Phantom either.

I have found that this issue is caused by QtWebKit in Qt4. This problem doesn't occur in Qt5 when testing with a simple web browser application though.

Wondering if this bug is going to get active development?

I found that the only way I could trigger a resize event on window was by using new Event('resize') and then dispatchEvent.

I was just wandering if this was still an issue?

I just bumped into the following error:

'[object EventConstructor]' is not a constructor (evaluating 'new Event(e)')

when running the following code within my mocha spec:

event.emit(window,'resize');

which translates into this pretty standard cross browser event handler

function emit(el, eventName) {
        var event;
        if (document.createEvent) {
            event = new Event(eventName);
            el.dispatchEvent(event);
        } else {
            event = document.createEventObject();
            el.fireEvent('on' + eventName, event);
        }
    }

Having issues with this myself. No problem executing tests in all browsers except phantomjs, which does throws a TypeError.

For others who might stumble on this from Google, this is how I managed to facilitate my own tests that used keyboard events manually. The reason I had to do this was that I couldn't use $('#foo').keyup() as jQuery's trigger would not fire the browser's events that were added via addEventListener but only events that were attached through the jQuery's API. (Pasted gist available for commenting):

// <input id="my-input-element" type="text" value="foo"/>
var evt, node = document.getElementById('my-input-element');

// Have to use dispatchEvent/fireEvent because jQuery.trigger will not
// fire an event attached via addEventListener. Each environment has an
// unusual way to trigger a keyup event.
if (node.dispatchEvent) {
  // Sane browsers
  try {
    // Chrome, Safari, Firefox
    evt = new KeyboardEvent('keyup');
  } catch (e) {
    // PhantomJS (wat!)
    evt = document.createEvent('KeyboardEvent');
    evt.initEvent('keyup', true, false);
  }
  evt.keyCode = 32;
  node.dispatchEvent(evt);
} else {
  // IE 8
  evt = document.createEventObject('KeyboardEvent');
  evt.keyCode = 32;
  node.fireEvent('onkeyup', evt);
}

The situation I had to got me there was that I was in a test runner which had jQuery available for doing fixtures and testing assertions but the code I was testing (read: module) needed to be jQuery free. That code would attach to DOM events via addEventListener but when the test script attempted to trigger the event via jQuery it was ignored. Forcing me to trigger the event manually in all the browser environments.

I just ran into this issue - not sure how to work around it. According to MDN, document.createEvent is deprecated - so using event constructors is the correct way to implement your custom events.

See:
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
https://developer.mozilla.org/en-US/docs/Web/API/document.createEvent (Deprecated)

@mendozao at the time I wrote the above comment PhantomJS did not support KeyboardEvent and still relied on the deprecated createEvent. I do not know if newer versions of PhantomJS have changed since.

@sukima the error I was getting was the following:

PhantomJS 1.9.7 (Mac OS X) player encountered a declaration exception FAILED
ReferenceError: Can't find variable: CustomEvent

In my code, I create an event using the following syntax:

var myevent  = new CustomEvent('onSomething');

Just seems wrong to have to write conditional logic in my code to support phantomJS's implementation

Kinda sucks. The above is the best I could do.

Although if I had a choice I'd just rely on jQuery's event system or something of the like. Unfortunately the requirements I had circumvented any third party event system and forced me to come up with a cross browser / cross PhantomJS test suite as seen above.

+1

Fixed in 2.0

@Vitallium when is 2.0.0 to be released, i see it's currently on 1.9.7?

Is it possible to get this fixed sooner than 2.0?

"Fixed in 2.0" ... 6 months later, no 2.0. :(

^ I ended up applying a hacky polyfill just to keep Travis CI building.

same.

An announcement was made on the mailing list, the version 2.0 is supposed to happen on Jan 23th.

Woop!

UM...wasn't this supposed to be fixed in the 2.0 release? I'm still getting
MouseEventConstructor is not a constructor (evaluating 'new MouseEvent')

I compiled 2.0 for linux, and I find that I still experience this exception when using the "new" keyword to construct a MouseEvent.

same here...

@Vitallium please re-open this issue.

I'm using this shim until support comes to Phantom.

Reopened for now.

So to clarify, the '[object EventConstructor]' is not a constructor error in particular is fixed in 2.0 right? It's just MouseEventConstructor is not a constructor (evaluating 'new MouseEvent') that's still a problem, correct?

Confirming that the "new" way to create synthetic events is still not supported in 2.0. I guess the newer Webkit in 2.0 is not new _enough_. (We are painfully aware of how slow we are at picking up new iterations of Webkit.)

@Ajedi32 Yes, new Event(...) seems to be accepted without error in 2.0, but not new MouseEvent(...). I didn't try any of the others.

MouseEventConstructor is not a constructor (evaluating 'new MouseEvent') just bit me.

@ariya Hi. Is there a solution for this already or am I missing something?

Any updates on this?

this may not work for everyone, but as a workaround jQuery seems to provide a cross-browser (including phantomjs) Event object constructor: $.Event(event)

Any recent news on this issue?

Here is the list of all supported events in 2.x version:

CloseEvent
CompositionEvent
CustomEvent
ErrorEvent
FocusEvent
HashChangeEvent
KeyboardEvent
KeyboardEvents
MessageEvent
MouseEvent
MouseEvents
MutationEvent
MutationEvents
OverflowEvent
PageTransitionEvent
PopStateEvent
ProgressEvent
TextEvent
TransitionEvent
WebKitAnimationEvent
WebKitTransitionEvent
WheelEvent
XMLHttpRequestProgressEvent
StorageEvent
SVGEvents
SVGZoomEvent
SVGZoomEvents
TouchEvent
CSSFontFaceLoadEvent
SecurityPolicyViolationEvent

Is there an easy way to install 2.x yet?

new WheelEvent.contructor is not contructor

v 2.0

I resolved using simulant.

var fakeEvent = require('simulant');
fakeEvent.fire(ghost, fakeEvent('mousemove'));

It nicely wraps around the event API and it works also with phantom 1.9.x.

@sirLisko thx, simulant solved my problem too.

WheelEvent is not working, with "simulant" too (v 2.1, ubuntu)

+1, I still have to use document.createEvent('MouseEvent'); instead of new MouseEvent(). I am trying to test GUI with Karma (not Selenium), and triggering DOM events artificially is an important feature to do that.

I'm also getting this error, using v2.1.7, after calling new window.Event('mousedown', { bubbles: true, cancelable: true, view: window });

EDIT: Re-installing [email protected] fixed it :|

Same problem with [email protected] (using npm's phantomjs-prebuilt):

KeyboardEventConstructor is not a constructor (evaluating 'new KeyboardEvent('keydown', {
                      key: 'a',
                      keyCode: 65,
                      which: 65
                    })')

My workaround to get tests working in both browsers and PhantomJS:

var clickEvent;
var keyupEvent;

// check if Event() is a constructor function
// usage as per the spec, if true
if (typeof(Event) === 'function') {

    clickEvent = new MouseEvent('click');
    clickEvent.initMouseEvent('click');

    keyupEvent = new Event('keyup');

// the deprecated way for PhantomJS
} else {

    clickEvent = document.createEvent('CustomEvent');
    clickEvent.initCustomEvent('click', false, false, null);

    keyupEvent = document.createEvent('CustomEvent');
    keyupEvent.initCustomEvent('keyup', false, false, null);

}

Usage:

submitButton.dispatchEvent(click);
textInput.dispatchEvent(keyup);

Any progress here? Still running into"
TypeError: MouseEventConstructor is not a constructor (evaluating 'new MouseEvent("click")')

On PhantomJS 2.1.1

@dwightdegroff I switched to jsDOM 6 months ago and have never been happier.

we have failing tests because of TypeError: MouseEventConstructor is not a constructor (evaluating 'new MouseEvent("click")') and tried using PhantomJS 2.5.0-beta on TravisCI. Now all tests that were failing with the mentioned error are now failing with this:

Capybara::Poltergeist::DeadClient:
        PhantomJS client died while processing {"id":"9600aa3c-0be5-40f3-9010-018c39322890","name":"visit","args":["http://127.0.0.1:35752/messages/conversations",30]}

Not sure if this will help anyone else, but we were able to solve the issue by tracking it down to opal-browser gem. This commit fixes it for us: https://github.com/opal/opal-browser/commit/6791db2dc63ea9bbe3b01444c4360813534d601d

This short shim worked for me:

function keyboardEvent(eventType, init) {
  try {
    return new KeyboardEvent(eventType, init);
  } catch (error) {
    const modKeys = [
      init.ctrlKey ? 'Control' : '',
      init.shiftKey ? 'Shift' : '',
      init.altKey ? 'Alt' : '',
      init.altGrKey ? 'AltGr' : '',
      init.metaKey ? 'Meta' : '',
    ].join(' ');
    const keyEvent = document.createEvent('KeyboardEvent');
    keyEvent.initKeyboardEvent(
      eventType,
      false,
      false,
      window,
      init.char || '',
      init.keyCode || 0,
      modKeys,
      init.repeat || false,
    );
    keyEvent.key = init.key;

    return keyEvent;
  }
}

And using it like so:

document.body.dispatchEvent(keyboardEvent('keydown', { key: 'Escape' }));

@astrotim Creating some kind of polyfill would be better and you don't have to load it in your production code, just for testing.

We have faced this problem as well. In our case, we were using angular 2 testing and doing some MouseEvent with clientX and clientY properties. All the tests were working until we changed to PhantomJS instead of Chrome for CI, then we faced this.

We could fix it for PhantomJS, instead of creating a MouseEvent, creating an Event passing clientX and clientY properties, but then the typescript compiler complained that clientX and clientY are not properties expected on the properties passed to the event.

We ended up just doing:

const evtOpts = {
      clientX: component.menuContainer.nativeElement.offsetLeft + 1,
      clientY: component.menuContainer.nativeElement.offsetTop + 1
};
window.dispatchEvent(new Event('mousedown', evtOpts));

This way, evtOpts gets an implicit any, so when passed to Event constructor, TS does not complain, and PhantomJS works.

@runarberg I hope you don't mind, but I created your function into a phantomJS polyfil. As above, I wanted to test in Angular2+ in Typescript and it type checking complained about the assignment of readonly properties. Being able to load it in via yarn or npm means it is outside of the linted code. It also makes it easily available to all.

https://github.com/justingrayston/basic-keyboard-event-polyfill

@justingrayston Sure, go ahead.

FYI: I extracted the vital bits from https://github.com/termi/DOM-Keyboard-Event-Level-3-polyfill.

In order to fix the

MouseEventConstructor is not a constructor (evaluating 'new MouseEvent')

I used the Polyfill from the MSDN MouseEvent docs and that finally worked.

Probably creating a repo including both polyfills, and publishing it on npm as phantomjs-event-polyfill would be a wise idea until this is fixed. As far as I remember the error stack has similar issues, I managed to fix it somehow in my (partially complete) error polyfill.

Could you try again with 2.5 binary please? Thanks!

For the same reasons as @justingrayston I created a npm package for helping PhantomJS with Mouse Events. It is based on the solution provided by: @ghiscoding

https://github.com/lechu1985/basic-mouse-event-polyfill-phantomjs

I been experiencing a sort of similar problem. TypeError: undefined is not a constructor (evaluating 'targetElement.closest('tr')'). The arg 'targetElement' is the supposed to be the DOM target element retrieved from event.target. But event.target is only returning the href in a string. Has anyone had this happen and if so, were you able to resolve it? This is for a rails 5 system test using poltergeist to run the headless test.

Due to our very limited maintenance capacity (see #14541 for more details), we need to prioritize our development focus on other tasks. Therefore, this issue will be automatically closed. In the future, if we see the need to attend to this issue again, then it will be reopened. Thank you for your contribution!

Great, so a 6 years old confirmed bug was not fixed. Is this repo even maintained?

Cleanup is a very strong sign of restart of maintenance.
There are no recources to check every 1400 issues if they are still valid. If they are still valid and important they can be reopened.

Was this page helpful?
0 / 5 - 0 ratings