ariya / phantomjs

Scriptable Headless Browser
http://phantomjs.org
BSD 3-Clause "New" or "Revised" License
29.47k stars 5.76k forks source link

'[object EventConstructor]' is not a constructor #11289

Closed davidcelis closed 4 years ago

davidcelis commented 11 years ago

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.

JamesMGreene commented 11 years ago

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.

davidcelis commented 11 years ago

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.

JamesMGreene commented 11 years ago

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:

carlthuringer commented 11 years ago

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)
JamesMGreene commented 11 years ago

@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);
carlthuringer commented 11 years ago

Awesome, thanks for the quick explanation and response!

ianstormtaylor commented 11 years ago

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

kramerc commented 10 years ago

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.

rossbruniges commented 10 years ago

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.

peter-mouland commented 10 years ago

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);
        }
    }
hous commented 10 years ago

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

sukima commented 10 years ago

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.

mendozao commented 10 years ago

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)

sukima commented 10 years ago

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

mendozao commented 10 years ago

@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

sukima commented 10 years ago

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.

leeight commented 10 years ago

+1

vitallium commented 10 years ago

Fixed in 2.0

peter-mouland commented 10 years ago

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

Robdel12 commented 9 years ago

Is it possible to get this fixed sooner than 2.0?

benlesh commented 9 years ago

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

Robdel12 commented 9 years ago

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

benlesh commented 9 years ago

same.

Drahakar commented 9 years ago

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

Robdel12 commented 9 years ago

Woop!

aviynw commented 9 years ago

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

ahri commented 9 years ago

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

fabiosussetto commented 9 years ago

same here...

sukima commented 9 years ago

@Vitallium please re-open this issue.

ourmaninamsterdam commented 9 years ago

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

JamesMGreene commented 9 years ago

Reopened for now.

Ajedi32 commented 9 years ago

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?

zackw commented 9 years ago

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

zackw commented 9 years ago

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

evandavis commented 9 years ago

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

ghost commented 9 years ago

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

mmahalwy commented 9 years ago

Any updates on this?

lazylester commented 9 years ago

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

xldenis commented 9 years ago

Any recent news on this issue?

vitallium commented 9 years ago

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

BeforeLoadEvent
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
Robdel12 commented 9 years ago

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

ortexx commented 8 years ago

new WheelEvent.contructor is not contructor

v 2.0

sirLisko commented 8 years ago

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.

wzhscript commented 8 years ago

@sirLisko thx, simulant solved my problem too.

ortexx commented 8 years ago

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

ghost commented 8 years ago

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

bttf commented 8 years ago

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 phantom@2.1.7 fixed it :|

perrin4869 commented 8 years ago

Same problem with phantomjs@2.1.1 (using npm's phantomjs-prebuilt):

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

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);
dwightdegroff commented 7 years ago

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

On PhantomJS 2.1.1