Reputation: 597
Here's my code :
function hasDataBeenRefreshed(pastAvgGain, currentAvgGain) {
if (pastAvgGain!== currentAvgGain) {
return true
} else {
return false
}
}
async function getInfos(paire, page) {
let pastAvgGain = C.AVG_GAIN.textContent
await page.click(paire)
let currentAvgGain = C.AVG_GAIN.textContent
await page.waitForFunction(hasDataBeenRefreshed(pastAvgGain, currentAvgGain))
...
}
But if I do this I get this error:
Error: Evaluation failed: TypeError: true is not a function
Is there a way to achieve something like this ?
Upvotes: 0
Views: 6645
Reputation: 56885
There are multiple issues and misunderstandings with the code here.
The first problem is that you're immediately calling the function you want to pass as a callback. This results in the return value of the callback (a boolean comparison) being passed into page.waitForFunction
rather than the callback itself. You can't call a boolean like a function, so an error is thrown.
Secondly, you'll need to pass the data in as parameters to the callback using the variable arguments to page.waitForFunction
. The second argument is a configuration object, so the call will look like page.waitForFunction(predicate, configObj, ...args)
where ...args
are the variable arguments to predicate
.
Thirdly, you're getting text content before and after a click, but polling for further changes on these two variables won't work because the value of let currentAvgGain = C.AVG_GAIN.textContent
will never change. Your predicate will either terminate instantly or spin based on whatever the initial values were. If click
is asynchronous, then C.AVG_GAIN.textContent
is probably stale and you'll want to re-select the latest text content from the node in the waitForFunction
predicate.
Furthermore, it's not clear what C.AVG_GAIN.textContent
is. Neither DOM nodes or Puppeteer elementHandles look like this, so I'll assume this also needs to be rewritten.
It appears you're trying to check whether a DOM element, elementHandle or selector has changed its text. This should be a pretty generic function you can use:
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());
Note that if you're using waitForTextChange
alongside an action that triggers the change, you'll want to use it as follows to avoid a race condition:
const textChangedPromise = waitForTextChange(page, "h2");
await page.click("button"); // trigger the text change
await textChangedPromise;
Applied to the above example:
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
Upvotes: 2
Reputation: 4296
page.waitForFunction() accepts a callback and right now you're passing in a boolean. To solve this you can do the following :
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 see documentation for more info
the third parameter is the arguments you want to pass to the callback
after your comment :
await page.waitForFunction(() => {
return hasDataBeenRefreshed(pastAvgGain, currentAvgGain);
} )
Upvotes: 1