What is the best way to wait for a button's listeners to resolve in JavaScript?

Currently, I am conducting frontend tests utilizing Jest with the jsdom environment to simulate a DOM tree and manually trigger actions such as button.click().

My goal is to be able to await button.click(), which in my expectations should wait for all of the button's event listeners to resolve their promises, but unfortunately that's not the case.

Consider this code snippet:

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))
    }
}

Imagine having an async Jest test where I manually trigger button.click() anticipating it to pause for 2000ms:

async fun(): Promise<void> {
    const button = document.getElementById('button');
    
    await button.click(); //I assume this await would wait for 2000ms, however, it resolves instantly
}

Answer №1

From my understanding, the environment does not wait for your event listeners to finish. It operates on a fire-and-forget basis.

Instead of focusing on the technical details, let's take a different approach. What is the objective of the test? Are you trying to verify a specific change in the frontend? For instance, if there is a loading indicator, you could confirm its presence in the DOM rather than delving into the intricacies of the class or code.

An illustration using jest, reactjs, and @testing-library/react might resemble the following:

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

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

// simulate button click
button.click()

// wait for the expected text to appear in the DOM
await waitFor(() => {
    getByText("Successfully submitted!")
})

The critical aspect here is the waitFor function. It periodically checks if the provided callback succeeds. The test progresses only after the completion of the waitFor.

It's worth noting that while this example is based on reactjs, the essence of the discussion revolves around the concept of waiting for a signal in the DOM, rather than focusing on a particular framework.

If I have misunderstood your query, please feel free to provide additional information.

Answer №2

The solution to this problem lies in the inclusion of an 'await' keyword within the event listener:

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

PhantomJS version 2.1.1 encountered an error on a Windows 7 system, displaying "ReferenceError: Map variable not found."

I've been utilizing the "MVC ASP.NET Core with Angular" template. I'm attempting to incorporate phantomJS and execute the tests, but encountering the following errors: ERROR in [at-loader] ..\\node_modules\zone.js\dist&bs ...

NestJS Troubleshooting: Nest is unable to resolve dependencies required by the ChildService

My project has a class structure set up like this: Inside the libs/childmodule/src/child.module.ts, I have a ChildModule. It is mapped to @app in the taconfig.json file. In addition, there is a ParentModule where I am attempting to import the ChildModule ...

AngularJS ng-focus does not function properly with iframes

Why isn't ng-focus working with iframe in AngularJS? What am I missing? Take a look at my code: <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script> <iframe src="example.com" tabindex="-1" ng-fo ...

What is the most efficient method for storing and accessing a large matrix in JavaScript?

With 10000 items, creating a matrix of 10000 rows * 10000 columns using a one-dimensional array would be massive. Additionally, setting specific values to cells (i,j) where 0 < i, j < 10000 would require a large number of iterations. I am facing cha ...

The system encountered an error while attempting to access the property "getChild" of an unspecified object

I am currently developing a react application and encountering an issue when trying to call a function from the render method. The function I'm trying to call utilizes the getChild method, but I keep receiving an error stating "cannot read property &a ...

Utilizing ChartJS to convert a chart into a Base64 image within a Vue environment

I am currently utilizing the PrimeVue chart component, which is built on top of ChartJS. The configuration is very similar. The documentation indicates that I need to instantiate a new Chart() and then call toBase64Image(); https://i.sstatic.net/NMHjV.p ...

Retrieval is effective in specific situations but ineffective in others

I have encountered an issue with fetching data only when using the async behavior. I am currently in the process of re-building a property booking website that was originally developed using Laravel and a self-built API. The new version is being created wi ...

Unexpected token error occurs when using map-spread operator in vue-test-utils combined with jest

I recently set up testing for my Vue project by following the instructions provided in this helpful guide here Upon completion of the guide, I proceeded to create a test for one of my components. However, when I ran jest, I encountered the following error ...

Error message when using Typescript with Redux Saga: "Cannot use 'then' property on type 'void'. TS2339"

Whenever I attempt to fetch data from this API endpoint using promises, I encounter these type of issues. export function* signUpWithEmail(authInfo: any) { const { email, password } = authInfo.payload try { const response = yield authSignUpService ...

Issue with MiniCssExtractPlugin during compilation of the entry point build

We have integrated webpack into our deployment process to bundle resources efficiently. However, we are now facing a challenge as we aim to include the bundling of sass files through webpack in order to streamline our build process. The MiniCssExtractPlugi ...

What is the best way to incorporate an automatic scroll to the following section on a single page website

My goal is to implement a feature that enables automatic scrolling between sections as the user scrolls up or down. The smooth transition should occur when the user reaches halfway through each section, seamlessly moving to the next screen on the same page ...

Unusual navigation patterns in Angular

https://i.sstatic.net/kdh4A.png My Mean app is set up with the Angular app residing in the '/dashboard' path. The home page of the app works fine. Reloading the app returns the page it was on. Even routes with '/dashboard/anything/anything& ...

"JavaScript: Issue Encountered While Converting Hexadecimal to Decimal

I've been working on a custom function to convert hexadecimal to decimal in my Scratch project: function Hex2Decimal(hex){ var deci = 0; var num = 1; var hexstr = String(hex); hexstr = hexstr.toLowerCase(); var expon = 0; for( ...

Difficulty encountered when consolidating intricate data attributes into a single array

I have a task to tackle in the code snippet below. My goal is to collect all the data in the age attributes and store them in a single array, formatting it as shown here: output = [48, 14, 139, 49, 15, 135, 51, 15, 140, 49, 15, 135, 51, 15, 140, 52, 16, ...

Could you provide some guidance on how to properly test this AngularJS code using Jasmine?

Here is a simple function I have: wpApp = angular.module('wpApp', ['ngRoute']); wpApp.controller("ctrlr", function($scope) { $scope.message = 'This is the page'; }); I am attempting to test it using Jasmine with this sp ...

Issue with Angular Script not functioning upon reopening the page

I recently completed my first website, which can be found at Despite my efforts, I've encountered an issue that has me stumped. When you navigate to the certificate page, you should be able to input your name onto the certificate. However, if you sw ...

Having trouble passing data between view controllers

In my AngularJS application, I have a table column in main.html that is clickable. When clicked, it should redirect to a new customer page with the value of the column cell as the customer's name. There is a corresponding service defined for the app m ...

What is the best way to extract the ID of an element that triggers an OnChange event?

Just a heads up: The solution to my problem ended up being CSS code that was triggered by clicking on a widget. Once I realized it was CSS, along with the widget name and hover action, I was able to handle it successfully. Previous question before the PS ...

Retrieving outcomes from a sequence of callback functions in Node.Js

I've been struggling to get my exports function in Node.Js / Express app to return the desired value after going through a series of callback functions. I've spent hours trying to fix it with no success. Can someone provide some guidance? Here is ...

Node.js is no longer able to fulfill promises

Imagine having an API that needs to be queried for important data. const fetchData = async () => { rootUrl = 'http://....' data = await (await fetch(rootUrl)).json() moreData = await Promise.all(data.map(async (elem) => subData = ...