Home > Enterprise >  How to await button's listeners to resolve in javascript?
How to await button's listeners to resolve in javascript?

Time:12-22

I am doing frontend tests in Jest using jsdom environment which lets me simulate DOM tree and manually invoke things like button.click().

What I'd like to achieve is to await button.click() which as I imagine should await for all button's listeners to resolve their promises but unfortunately it doesn't work like that.

Let's take this code as an example:

class Test {
    constructor() {
        const button = document.getElementById('button');
        button.addEventListener('click', async () => this.fetch());
    }

    async fetch(): Promise<void> {
        await this.sleep();
    }

    sleep() {
        return new Promise(resolve => setTimeout(resolve, 2000))
    }
}

Now imagine I have some async Jest test and I am manually invoking button.click() expecting it to wait 2000ms:

async fun(): Promise<void> {
    const button = document.getElementById('button');
    
    await button.click(); //I expect this await to sleep for 2000ms but it resolves instantly
}

CodePudding user response:

As far as I know, the environment isn't waiting for your event listeners to complete. It's fire and forget.

Instead, let's take a step back. What is the test about? Do you want to test a certain change in the frontend? For example: If there is some kind of loading indicator, you could test for the presence of the loading indicator in the DOM, instead of testing the inner workings of the class / code.

An example of this with jest, reactjs and @testing-library/react could look like this.

// render the DOM
const { getByRole, getByText } = render(
    <App />
)

const button = getByRole("button", { name: "Submit" })

// click the button
button.click()

// wait till the text appears within the DOM
await waitFor(() => {
    getByText("Successfully submitted!")
})

Where waitFor is the key function here. It checks in intervals if the supplied callback succeeds. Only if the waitFor completes, the test will continue.

Please not that the example uses reactjs, but in it's core this post is about the idea of waiting for a signal in the DOM, not about a certain library.

But I might be on the wrong track here, feel free to supply more informations if so.

CodePudding user response:

I think the issue here is you will have to add await here:

  constructor() {
        const button = document.getElementById('button');
        button.addEventListener('click', async () => await this.fetch());
    }
  • Related