Main Website
Web Scraping
Web Scraping
Updated on
May 21, 2024

How to Wait For Button to be Enabled in Puppeteer?

In web applications, buttons may initially be disabled to prevent actions before certain conditions are met, such as form completion or data loading. This design helps ensure that users interact with the application as intended, enhancing usability and preventing errors. However, automating interactions with such elements using tools like Puppeteer can be challenging, as scripts must accurately detect when a button becomes clickable. This article guides you through the process of Puppeteer wait for button to be enabled on a webpage. We will demonstrate it with complete code samples as well. 

What functions will be using?

There are two functions you can use for this purpose. Those are the waitForSelector function and the waitForFunction. 

The waitForSelector function is specifically designed to wait for an HTML element to appear when page load on the browser. When you use this function, you provide it with a selector, such as an ID or a class that identifies the element you're interested in. This function will pause your script until the element matching the selector is found on the rendered page.

The waitForFunction function in Puppeteer pauses the script execution until a specified condition or page events are met, including conditions across consecutive animation frames. This is particularly useful for monitoring dynamic events that occur after the webpage has loaded. When Puppeteer encounters a waitForFunction, it repeatedly executes this function until it returns a truthy value. Only after this condition is satisfied does Puppeteer continue with the execution of the remaining script.

Read Puppeteer proxy setup to learn how to use Puppeteer through a Proxy server.

Full code example

Let's first take a look at the complete code example, which we will break down step by step in the following section. This implementation assumes that you have a use case where you need to wait for a button to become enabled before proceeding. For this example, we'll use an imaginary domain name, puppeteer_example.com, and assume that the ID of the button we're waiting to enable is 'my-button'. We'll operate Puppeteer in headless mode to demonstrate how it can be used for background execution in automated testing environments.


const puppeteer = require('puppeteer');

async function waitForEnabledButton(page, selector) {
 
  // Await page until a certain element appears represented by a CSS selectors
  await page.waitForSelector(selector, { visible: true });
  await page.waitForFunction((selector) => {
    const button = document.querySelector(selector);
    return !button.disabled;
  }, {}, selector);
}

(async () => {

  const browser = await puppeteer.launch({ headless: true });

  //use await browser to create a new Page object
  const page = await browser.newPage();
  await page.goto('https://puppeteer_example.com');

  const buttonSelector = '#my-button';

  try {
    await waitForEnabledButton(page, buttonSelector);
    console.log('Button is enabled!');
    await page.click(buttonSelector);
  } catch (error) {

    console.error('Error waiting for button or clicking:', error);

  }

  await browser.close();

})();

In the next section, we will discuss how to build this script step by step, explaining the purpose of each part of the code and how it contributes to effectively handling dynamically enabled buttons in web automation.

Read Get Element in Puppeteer to learn how to select an element in Puppeteer.

Step 1: Setup Puppeteer and open a web page

First, we start by setting up Puppeteer and launching a browser instance. In this example, we use the headless mode (headless: true), which means that the browser runs in the background without physically opening a window on the screen. This mode is particularly useful for automated testing environments.


const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://puppeteer_example.com');

In this example, I am using a domain called puppeteer_example.com. You need to change it according to your use case. 

Step 2: Define the function to wait for the button to be enabled

In the next step, we will define a function named waitForEnabledButton that will handle the waiting mechanism for the button to become enabled.


async function waitForEnabledButton(page, selector) {
    await page.waitForSelector(selector, { visible: true });
    await page.waitForFunction((selector) => {
      const button = document.querySelector(selector);
      return !button.disabled;
    }, {}, selector);
  }

As you can see, we are using waitForSelector and waitForFunction on the page object. The page object is created by the browser, which means these functions work within the browser context.

waitForSelector waits for a selector parameter which we will later pass to it. waitForFunction will return true only if the button represented by the selector passed to it is enabled. It continuously evaluates whether the disabled attribute of the button is false.

Step 3: Use the function and interact with the button

After defining the function, we use it within an asynchronous self-invoking function to manage the flow of operations. This includes auto waiting mechanisms to handle dynamic interactions. We also handle potential errors with a try-catch block to manage issues related to network connections or other input/output operations.


(async () => {
    const buttonSelector = '#my-button';
    try {
      await waitForEnabledButton(page, buttonSelector);
      console.log('Button is enabled!');
      await page.click(buttonSelector);
    } catch (error) {
      console.error('Error waiting for button or clicking:', error);
    }
  })();
await browser.close();

We define a selector string for the button we intend to interact with. It's essential that this selector is accurate to identify the correct element. In this case, I use the #my-button id as the text input. You have to get to know that by inspecting the web page. 

Then I logged Errors during the wait or click process, which helps in debugging if something goes wrong.

Finally, it's good practice to properly close the browser session once all actions are completed. This helps in freeing up resources.

Read Puppeteer timeout to learn how to fix timeout issues in Puppeteer.

Troubleshooting common errors

As with all forms of code, when waiting for your button to be enabled, you may come across some errors. To overcome these errors, it is essential to understand the possible reasons why the button might not be working and troubleshoot the issue. With that, let’s discuss some common issues when waiting for your button to be enabled in Puppeteer and how to troubleshoot them, including issues related to network response.

  • Script Timing Out: If the script times out while waiting for the button to be enabled, it's important to confirm that the selector used is correct for your specific request. You need to check if the button is actually present. Using browser developer tools to inspect the button and verify attributes like ID or specific CSS classes is a good approach to gaining more control over the element interaction.
  • Delayed Button Enablement: If the button doesn't become enabled immediately after appearing, it may be due to JavaScript that hasn't finished executing or other operations on the page. In this case, waitForSelector and waitForFunction can be used with suitable conditions to specifically check the status of the button and prepare the script for further actions.
  • Visibility and Network Latency: Your button might be enabled but not yet visible due to network latency. To troubleshoot this, you can use waitForNavigation before waiting for the button, to handle cases where the button appears after a page navigation. Moreover, consider using page.goto with a timeout option to manage slow loading.
  • Debugging Tips: Incorporating console.log statements to output the status of the script at various stages is an excellent way to identify where it might be getting stuck. The use of the debugger statement in the script for a more interactive debugging session can also provide insights into the script's behavior at runtime, especially when running in a non-headless mode where the browser UI is visible. This allows for direct observation and more control during the debugging process.

Additional resources

While this article gives you a comprehensive view of how to wait for a button to be clickable in Puppeteer, there are some additional resources and documentation that you can use to expand your understanding of the subject.

  • The official Puppeteer documentation on `waitForSelector` offers a clear view into the function's capabilities, including waiting for specific element states.
  • A more detailed overview of the waitForSelector and its applications.
  • The unofficial Python port of Puppeteer - Pyppeteer.
  • You can also get involved with the community by engaging in discussion forums and platforms like Stack Overflow to learn more about waiting for a button. 
  • For more complex scenarios where you might need to wait for one of multiple elements to appear, this Github issue provides a discussion that could solve your issue.

waitForSelector in Puppeteer: Basic and Advanced Configuration

Wait For Page to Load in Puppeteer: 4 Methods Compared

waitForNavigation in Puppeteer: Basic and Advanced Configuration