Stencil version:
@stencil/core@<0.6.1>
I'm submitting a:
[ x] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or https://stencil-worldwide.slack.com
Current behavior:
I have implemented a special button component based on https://github.com/ionic-team/stencil-component-starter. The web component is intrested in events of its child button html component (mouseleave and keydown.tab) to be exact. Testing it manually in a browser succeeds.
When I try to do automated tests I have to dispatch the specified events. No matter how I try to create the specified Event I get the following error on dispatching:
```
TypeError: Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.
I logged the event to the console before dispatching and it is indeed an `Event`. I have tried several event types (Event, MouseEvent, CustomEvent) and several ways to construct the event but the result is always the same.
**Expected behavior:**
Tests should allow to fire events manually.
**Steps to reproduce:**
1. Create a clean projecet based on component-starter.
2. Create a custom component.
3. In the spec dispatch an event via `element.dispatch(Event)`
**Other information:**
Stack tarce:
TypeError: Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.
at convert (node_modules/jsdom/lib/jsdom/living/generated/Event.js:307:11)
at HTMLUnknownElement.dispatchEvent (node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:141:13)
at Object.<anonymous> (src/components/slds-button/tests/slds-button-stateful.spec.ts:95:41)
at step (src/components/slds-button/tests/slds-button-stateful.spec.ts:32:23)
at Object.next (src/components/slds-button/tests/slds-button-stateful.spec.ts:13:53)
at fulfilled (src/components/slds-button/tests/slds-button-stateful.spec.ts:4:58)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
ยดยดยด
node version: v8.9.4
npm version: 5.6.0
OS: Linux subsystem on Win10
just for the record, as I'm also experiencing this issue, I tried the following approach (in spec file):
const JsdomMouseEvent = require('jsdom/lib/jsdom/living/generated/MouseEvent').interface;
...
button.dispatchEvent(new JsdomMouseEvent('click', {
bubbles: true,
cancelable: true
}));
That error is no longer showing, but @Listen still doesn't listen. So, it seems to me that stencil, jest and jsdom are just not using the same source reference here.
I'm looking for a work around until this issue is solved.
I am experiencing this as well using @stencil/[email protected]. Full example for posterity:
my-component.tsx
import { Component, Listen } from '@stencil/core';
@Component({
tag: 'my-component'
})
export class MyComponent {
opened: boolean = false;
@Listen('click')
handleClick() {
this.opened = !this.opened;
}
render() {
return (
<div>my component</div>
);
}
}
my-component.spec.tsx
import { render } from '@stencil/core/testing';
import { MyComponent } from './my-component';
describe('my-component', () => {
let element;
beforeEach(async () => {
const components = [MyComponent];
const html = '<my-component></my-component>';
element = await render({ components, html });
});
describe('when clicked', () => {
it('toggles `opened`', () => {
element.dispatchEvent(new Event('click'));
expect(cmp.opened).toEqual(true);
});
});
});
Result:
FAIL src/my-component/my-component.spec.tsx
โ my-component โบ when clicked โบ toggles `opened`
TypeError: Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.
@adamdbradley , @3279676 doesn't seem to have solved this issue.
I've just updated my app to version 0.7.24 (and Jest to 22.4.3 too), and I still get the same error:
TypeError: Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.
This is how my test is defined:
import { TestWindow } from '@stencil/core/testing';
import { MyDialog } from './my-dialog';
describe('MyDialog', () => {
let window: TestWindow;
it('should build', () => {
expect(new MyDialog()).toBeTruthy();
});
describe('rendering', () => {
let element;
beforeEach(async () => {
window = new TestWindow();
element = await window.load({
components: [
MyDialog
],
html: `
<my-dialog></my-dialog>
`
});
});
it('should blabla when clicked on cancel button', async () => {
await window.flush();
const cancelButton = element.querySelector('button') as HTMLButtonElement;
cancelButton.dispatchEvent(new MouseEvent('click', {
bubbles: true,
cancelable: true
}));
// ...
});
});
});
Did I miss anything?
for the record, what my example above missed was to use window.Event instead of MouseEvent in the .dispatchEvent call. So it should be as below instead:
cancelButton.dispatchEvent(new window.Event('click', {
bubbles: true,
cancelable: true
}));
and I learned also that after this fix it's also possible this nicer alternative:
cancelButton.click();
Finally, I also want to record that, for other event classes, this also works fine:
const body = window.document.body;
body.dispatchEvent(new (window.window as any).KeyboardEvent('keyup', {
keyCode: 27,
bubbles: true,
cancelable: true
}));
These solutions did not work for me for KeyboardEvents. Looking through the Ionic tests I found that you can do these with much less code!
Assuming you are writing an E2E test and starting with const page = await newE2EPage();:
await page.keyboard.down("ArrowDown");
There is also a keyboard.up and a keyboard.press (press does both up and down).
I use @marinho's solution for clicks - e.g.
const button = await page.find("mds-dropdown-menu #menuButton button");
await button.click();
There is also a page.mouse, and this is what one of the Ionic tests does with it for example:
// Start in the center of the item
await page.mouse.move(centerX, centerY);
await page.mouse.down();
// Move halfway first
await page.mouse.move(halfX, centerY);
// Move all of the way to the end
await page.mouse.move(endX, centerY);
await page.mouse.up();
From: https://github.com/ionic-team/ionic/blob/master/core/src/components/item-sliding/test/test.utils.ts
Most helpful comment
for the record, what my example above missed was to use
window.Eventinstead ofMouseEventin the.dispatchEventcall. So it should be as below instead:and I learned also that after this fix it's also possible this nicer alternative:
Finally, I also want to record that, for other event classes, this also works fine: