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