bug: events with `dispatchEvent()` do not reach a parent's event handler that was added with `addEventListener()` in a Spec Page
Prerequisites
- [X] I have read the Contributing Guidelines.
- [X] I agree to follow the Code of Conduct.
- [X] I have searched for existing issues that already report this problem, without success.
Stencil Version
4.16.0
Current Behavior
Note: this bug is for the test setup only (Spec Page).
When a Stencil component emits an event using dispatchEvent(), then a parent component can listen for that event using addEventListener(). This works as expected in the browser. But, while running Spec tests, the event handler is not being called.
(The @Listen and @Event decorators are not being used here.)
Expected Behavior
While running Spec tests (with npm run test), then I expect event handlers (added with addEventListener()) to be called when a child component emits an event (emitted with dispatchEvent()).
System Info
System: node 20.9.0
Platform: darwin (23.4.0)
CPU Model: Apple M2 Max (12 cpus)
Compiler: /stencil-event-bug/node_modules/@stencil/core/compiler/stencil.js
Build: 1713191202
Stencil: 4.16.0 🚛
TypeScript: 5.4.5
Rollup: 2.56.3
Parse5: 7.1.2
jQuery: 4.0.0-pre
Terser: 5.30.3
Steps to Reproduce
- Create a "my-parent" component
- Add an event listener using
addEventListener()in theconstructor. Put aconsole.login the event handler. - Render a component called "my-child" in its JSX template.
- Create the "my-child" component that emits an event using
dispatchEvent()in thecomponentDidLoadlifecycle method. - Create a Spec test file that renders "my-parent".
- Run the Spec test file. You will not see the
console.logbeing called.
Code Reproduction URL
https://github.com/tomherni/stencil-event-bug
Additional Information
I have everything set up, including the Spec file, in my reproduction repo.
Thanks for raising the issue @tomherni
This seems to be a problem with our MockDoc implementation which is like JSDOM a JavaScript based re-implementation of the WHATWG DOM APIs. I will ingest this into our backlog but doubt that we provide any fast turnarounds due to competing priorities. I would recommend one of the other test solutions we've been working on that allow you to test your components in real browser / browser engines. Maybe take a look at:
For WebdriverIO I got your test working with the following:
import { h } from '@stencil/core'
import { fn, type Mock } from '@wdio/browser-runner'
import { render } from '@wdio/browser-runner/stencil'
import { expect } from '@wdio/globals'
import { MyParent } from './my-parent.js'
import { MyChild } from '../my-child/my-child.js'
describe('Stencil component testing', () => {
it('should increment value on click automatically', async () => {
console.log = fn()
await render({
components: [MyParent, MyChild],
template: () => <my-parent />
})
await browser.waitUntil(() => (console.log as Mock).mock.calls.length === 3)
expect(console.log).toHaveBeenNthCalledWith(1, 'adding event listener')
expect(console.log).toHaveBeenNthCalledWith(2, 'dispatching event')
expect(console.log).toHaveBeenNthCalledWith(3, 'event received')
})
})
@christian-bromann thanks for your quick reply and workaround.