I'm using the Lit Framework right now but I think this type of thing would happen with regular web components as well.
My connectedCallback
is async
, but, with a Lit fixture
, I don't think it waits until connectedCallback
is finished, so my state changes happen after the test has finished.
As a workaround, I put a this.dispatchEvent(new Event('cc-completed')
at the end of my connectedCallback
.
@customElement('my-lit-element')
export default class MyLitElement extends LitElement {
override async connectedCallback() {
super.connectedCallback();
await this.loadStuff(); // Also changes state
this.dispatchEvent(new Event('cc-completed'));
}
}
And then:
it('My Lit Element Test #1', async () => {
const myLitElement: MyLitElement = await fixture(html`
<my-lit-element .prop=${"prop"}></my-lit-element>
`);
myLitElement.addEventListener('cc-completed', () => {
// asserts
});
}).timeout(5000);
However, this only works with debugging and breakpoints, because otherwise the test is gonna finish and the callback is gonna be left hanging behind.
What is the proper way of doing this?
For synchronous update requests like setting a reactive property, doing await myLitElement.updateComplete
would have been sufficient.
But if the thing that causes an update within connectedCallback
is asynchronous, the only way would be to poll for some result you're looking for.
Open-WC has some testing utilities for this in @open-wc/testing
package.
waitUntil
lets you provide a generic predicate function and some options like interval and timeout.
oneEvent
lets you await for the firing of an event, like the one you fire in your second example.
One possible solution for you in your test, you can also pass a timeout as an options
parameter for waitUntil
:
it('My Lit Element Test #1', async () => {
const myLitElement: MyLitElement = await fixture(html`
<my-lit-element .prop=${"prop"}></my-lit-element>
`);
await waitUntil(
() => myLitElement.shadowRoot!.querySelector('#id'),
'Element is not ready', { timeout: 5000 }
);
// asserts
})