Utilize puppeteer by passing a function inside page.waitForFunction() for efficient automation processes

Below is the code I am using:

function checkDataRefresh(pastAvgGain, currentAvgGain) {
  if (pastAvgGain !== currentAvgGain) {
      return true;
  } else {
      return false;
  }
}

async function fetchInformation(pair, page) {

  let pastAvgGain = C.AVG_GAIN.textContent;

  await page.click(pair);

  let currentAvgGain = C.AVG_GAIN.textContent;

  await page.waitForFunction(checkDataRefresh(pastAvgGain, currentAvgGain));

  ...

}

However, when I run this code, I encounter the following error:

Error: Evaluation failed: TypeError: true is not a function

Is there a different approach to accomplish similar functionality?

Answer №1

There seems to be a number of issues and misunderstandings present in the code provided.

One major issue is the immediate invocation of the callback function that is intended to be passed as a callback. This leads to the boolean comparison result being passed into page.waitForFunction instead of the actual callback itself. Attempting to call a boolean value like a function results in an error being thrown.

Additionally, it is necessary to pass the data as parameters when invoking the callback using variable arguments with page.waitForFunction. The call should take the form of

page.waitForFunction(predicate, configObj, ...args)
, where ...args represent the variable arguments for predicate.

Moreover, attempting to monitor changes on two variables by fetching text content before and after a click operation will not work as expected. The value of

let currentAvgGain = C.AVG_GAIN.textContent
remains constant, leading the predicate to either terminate immediately or continuously loop based on initial values. If the click action is asynchronous, it is likely that C.AVG_GAIN.textContent is outdated, necessitating the retrieval of the latest text content from the node within the waitForFunction predicate.

Furthermore, the nature of C.AVG_GAIN.textContent is unclear as it does not resemble DOM nodes or Puppeteer elementHandles. It may need to be redefined in order to function correctly.

The objective appears to involve checking for changes in the text displayed by a DOM element, elementHandle, or selector. A more generic method can be employed for this purpose:

const puppeteer = require("puppeteer"); // ^19.6.3

const waitForTextChange = async (
  page,
  elOrSel,
  opts={polling: "mutation", timeout: 30000}
) => {
  const el = typeof elOrSel === "string" 
    ? await page.$(elOrSel) : elOrSel;
  const originalText = await el.evaluate(el => el.textContent);
  return page.waitForFunction(
    (el, originalText) => el.textContent !== originalText,
    opts,
    el,
    originalText, 
  );
};

let browser;
(async () => {
  const html = `
    <h2>foo</h2>
    <script>
      setTimeout(() => document.querySelector("h2").innerText = "bar", 4000);
    </script>
  `;
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.setContent(html);
  await waitForTextChange(page, "h2");
  console.log(await page.$eval("h2", el => el.innerText)); // => bar
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

If you intend to use waitForTextChange in conjunction with an action triggering the text change, consider the following usage to prevent race conditions:

const textChangedPromise = waitForTextChange(page, "h2");
await page.click("button"); // trigger the text change
await textChangedPromise;

When applied to the example above:

const html = `
<h2>foo</h2>
<button>click to change text</button>
<script>
document
  .querySelector("button")
  .addEventListener("click", () => {
    document.querySelector("h2").innerText = "bar";
  });
</script>
`;
await page.setContent(html);
const textChanged = waitForTextChange(page, "h2");
await page.click("button"); // action that triggers text change
await textChanged;
console.log(await page.$eval("h2", el => el.innerText)); // => bar

Answer №2

When using page.waitForFunction(), it is important to remember that it accepts a callback function, not just a boolean value as you may be passing in right now. To address this issue, consider the following solution:

  await page.waitForFunction((pastAvgGain, currentAvgGain) => {
  if (pastAvgGain !== currentAvgGain) {
      return true;
  } else {
      return false;
  }
}, {}, pastAvgGain, currentAvgGain )

https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitforfunctionpagefunction-options-args provides more detailed documentation on this topic.

It's worth noting that the third parameter consists of the arguments you wish to pass to the callback function.

Following your comment, you can also try the following approach:

  await page.waitForFunction(() => {
      return hasDataBeenRefreshed(pastAvgGain, currentAvgGain); 
  })

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

The elegant-admin template's mobile navigation toggle is missing

I recently downloaded an admin theme and added the CSS to my Django static files. However, after doing so, the mobile toggle feature disappeared. I double-checked all the CSS and JS links in the index template, and they are correctly linked to the paths, b ...

Is it possible to assign numerical values to attributes in HTML code?

I'm unsure about something - is it possible to set an attribute value as a number? For example: <div data-check="1"></div> Is this the correct way to do it or not? I've heard conflicting opinions, with some people saying you shouldn ...

Mongoose is struggling to locate the expected result

I currently have three different schemas set up. User.js: const mongoose = require("mongoose"); const bcrypt = require("bcryptjs"); const userSchema = new mongoose.Schema({ name: { type: String, required: true, }, email: { type: String, ...

Development and staging setups tailored specifically for a JavaScript SDK

Currently, I am working with a Javascript SDK that is available on NPM. Alongside this, I have a Vue application utilizing the SDK and it's crucial for me to test them together across various pre-production environments (such as staging). Here are the ...

What is the best way to obtain the value of a radio button using ajax?

Here is the search button in my PHP file. I am unsure of how to connect the radio button to the JavaScript file. <button id="submit">Search</button> This is the starting point in the JavaScript file var xhr = new XMLHttpRequest(); f ...

Merge requirejs modules using build script

I am attempting to merge and compress require modules into a single file. For instance, if I have a file named article.js with the following content: define(["jquery","flexslider","share_div"],function(){}); I wish for all these dependencies to be merge ...

Is there a common method for generating complex identifiers to be used as the HTML element's id, class, or name attributes

Is there a recommended method for "encoding" complex identifiers such as {Source:"ARCH.1", Code: "456-789.456 A+", SubNumber:##2} to be used in HTML elements' id, class, and name attributes? I could come up with something myself, but perhaps there is ...

What is the most efficient way to switch perspectives?

I'm currently utilizing storybook to simulate various pages of my application. My concept involves encapsulating storybook within one context for mock data, and then during live application execution, switching to a different context where data is fet ...

Encountering issues with CSS selectors when using Selenium WebDriver

I am encountering an error with the following code: elem = new Array() elem = driver.findElements(By.CssSelector('input')); What could be causing the issue in the code above? If I have an HTML form like this: <form role="form" method="post ...

Manipulating puppets with a Raspberry Pi Zero W

I'm facing an issue while running a Node.js script with Puppeteer on Raspberry Pi Zero W. The error message I'm encountering is: (node:5699) UnhandledPromiseRejectionWarning: Error: Failed to launch the browser process! /SteamCheaper/node_module ...

Problem with responsive design on iPhone

I'm currently working on developing a responsive chatbot using CSS Bootstrap. However, I've encountered an issue where the header and footer are not fixed when I open the app on an iPhone. The keyboard header is also moving up the screen, which s ...

Error encountered while trying to display content in the rendering area

const Pages = () => { return ( <> <Box display="flex"> {window.location.pathname === "/profile" ? undefined : <Sidebar />} <Box flex={3}> <Navbar /> <Routes> {/* Cont ...

What type of JavaScript scope is accessible by an anchor tag's href attribute?

My current query involves using an <a> tag to invoke a JavaScript function: <a href="javascript:doSomething();">link</a> In which scope does this JS function need to be defined in order to be reachable? Is declaring it globally necessar ...

Tips for altering the appearance of a button when moving to a related page

I have a master page with four buttons that have a mouse hover CSS property. Each button's corresponding response page is defined on the same master page. Now, I want to change the button style when the user is on the corresponding page. How can this ...

Encountering an error stating 'ReadableStream is not defined' while attempting to log in using Discord on the NextAuth application

While attempting to set up a Discord sign-in page to test NextAuth on my website, I encountered the error ReferenceError: ReadableStream is not defined. After examining the stack trace, it seems to be related to how my packages are configured, but I' ...

Access and retrieve numerous variables from the data object sent back through an ajax request

When using jQuery to make an ajax call to an MVC controller, the goal is to return multiple variables from the controller. What is the best way to package this data in the controller and then extract it using jQuery? ...

Customize Magento pop-up close function on click event

I developed a unique module with a Magento pop-up feature. I am looking to customize the close event for the pop-up. <div onclick="Windows.close(&quot;browser_window_updatecc&quot;, event)" id="browser_window_updatecc_close" class="magento_clos ...

Why is it that styling <div> and <img> with a URL doesn't seem to work, even when applying the same styles?

In the example I have, I apply the same styling to an image and a div. Interestingly, the styling on the div makes the image look significantly better, while on the image itself it appears distorted. What could be causing this discrepancy? Both elements a ...

Add a SlideUp effect to the .removeClass function by using a transition

Looking to incorporate a SlideUp transition while removing the class with .removeClass. This script handles showing/hiding the navigation menu based on page scroll up or down. I am looking to add a transition effect when the navigation menu hides. Check ou ...

Using the setTimeout function with asynchronous tasks

I have a situation where I need to introduce a 5000ms delay before firing an asynchronous function. To accomplish this, I attempted to utilize the setTimeout() method. This async function is called within a loop that runs multiple times, and each time it i ...