Repository navigation
[Feature] evaluate timeout #13253
Description
Activity
kachkaev commented
on Aug 1, 2022 ContributorMore actionsI faced a similar issue recently. One of my
page.evaluatecalls was crashing a Chrome tab and my Node.js app paused indefinitely. Essentially,await page.evaluate(/* */)was pending forever.Here is my workaround:
const evaluateTimeout = 30_000; const page = /* ... */; try { const result = await Promise.race([ new Promise((resolve) => setTimeout(resolve, evaluateTimeout)), page.evaluate(async () => { return /* ... generateResult .. */; }), ]); if (!result) { throw new Error("page.evaluate must have crashed"); } console.log(result); } finally { await page.close(); }
The readibility of this code is quite poor but it's not the only problem here. If the timeout promise needs to be lengthy, the whole Node.js process will get slow. It exits only after
evaluateTimeoutms.It’d be great to be able to do this:
page.evaluate(pageFunction, arg, { timeout: 30_000 })
Alternatively, my problem could be solved if
page.evaluateutilisedpage.on('crash', ...)internally.Reacted by Martin Löper, Ivan Kleshnin, Serhiy Tymoshenko, Nikita Savchenko, Szymon Dzialowski and Yair Even Orevaluatedoes support a timeout option, butevaluateAll, unfortunately, does not: #23352evaluatedoes support a timeout option, butevaluateAll, unfortunately, does not: #23352page.evaluate() doesn't support timeout too
page.evaluate() doesn't support timeout too
👉 https://playwright.dev/docs/api/class-locator#locator-evaluate
options Object (optional)
timeout number (optional)# 👈
Maximum time in milliseconds. Defaults to 0 - no timeout. The default value can be changed via actionTimeout option in the config, or by using the browserContext.setDefaultTimeout() or page.setDefaultTimeout() methods.Ivan Kleshnin (@ivan-kleshnin), yes locator.evaluate has timeout but page.evaluate, hasn't
Locator's interface evaluate function:* const tweets = page.locator('.tweet .retweets'); * expect(await tweets.evaluate(node => node.innerText)).toBe('10 retweets'); * ``` * * @param pageFunction Function to be evaluated in the page context. * @param arg Optional argument to pass to `pageFunction`. * @param options */ evaluate<R, Arg, E extends SVGElement | HTMLElement = SVGElement | HTMLElement>(pageFunction: PageFunctionOn<E, Arg, R>, arg: Arg, options?: { timeout?: number; }): Promise<R>;Same function for page interface:
* const bodyHandle = await page.evaluate('document.body'); * const html = await page.evaluate<string, HTMLElement>(([body, suffix]) => body.innerHTML + suffix, [bodyHandle, 'hello']); * await bodyHandle.dispose(); * ``` * * @param pageFunction Function to be evaluated in the page context. * @param arg Optional argument to pass to `pageFunction`. */ evaluate<R, Arg>(pageFunction: PageFunction<Arg, R>, arg: Arg): Promise<R>;Also, if I try to use locator.evaluate() to evaluate a certain function that can fail with a timeout, the timeout still fails to stop evaluation in case of function failure and the test fails by global test timeout(120000 in my example)
example
const reports = await getActualReports(); const testUserTestReports = reports.filter(r => r.Username === process.env.USER && r.Title.includes(testPrefix.trim())); for (const report of testUserTestReports) { try { const body = page.locator('body'); await body.evaluate( async (el, report) => { return await window.analyticsAutomations.deleteReport(report.ReportId); }, report, { timeout: 2000 } ); } catch (e) { console.log('Report cleanup failed. Maybe report was already deleted by the parallel process'); } }Test output
Report cleanup failed. Maybe report was already deleted by the parallel process 1) [chromium] › Analytics/Reports_List/reports_list_view.spec.ts:21:9 › Reports List View @analytics › Verify Reports List Fields for Newly Created Basic Report Test timeout of 120000ms exceeded.Reacted by Ivan Kleshnin, Anthony Phan, gianpesto and tsukimizake
Hello,
This is half feature request / half bug report, depends on how you read it :D
I noticed
evaluate()do not have a timeout and this can be problematic when executing on a busy thread that will never let go.Will Display
Possible Resolutions
timeouttoevaluateso that it at least throw a timeout error