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.

evandavis commented 7 years ago

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

cantonic commented 7 years ago

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]}
cantonic commented 7 years ago

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

runarberg commented 7 years ago

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' }));
ghost commented 7 years ago

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

bortexz commented 7 years ago

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.

justingrayston commented 7 years ago

@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

runarberg commented 7 years ago

@justingrayston Sure, go ahead.

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

ghiscoding commented 7 years ago

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.

ghost commented 7 years ago

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.

vitallium commented 7 years ago

Could you try again with 2.5 binary please? Thanks!

lechu1985 commented 7 years ago

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

fgc29 commented 7 years ago

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.

stale[bot] commented 4 years ago

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!

ghost commented 4 years ago

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

HolgerJeromin commented 4 years ago

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.