---
title: "Problematic Playwright pitfalls"
description: "Fix the Playwright 'evaluation was aborted, probably because page refresh happened' error and avoid other common Playwright pitfalls."
canonical: "https://momentic.ai/blog/playwright-pitfalls"
last-updated: "2026-09-10T16:12:24Z"
---

# Problematic Playwright pitfalls

URL: https://momentic.ai/blog/playwright-pitfalls

[blog](/blog) [/ engineering](/blog/category/engineering)  / playwright-pitfalls

Engineering

Avoid common Playwright pitfalls that damage test stability, maintainability, and trust.

Jeff An

CTO, Momentic

Playwright is a powerful browser automation framework that recently [overtook Cypress](https://zhiminzhan.medium.com/playwright-download-count-exceeded-cypress-b109842d07bc) as the most popular E2E testing solution in the JavaScript ecosystem.

While full-featured and easy to get started with, we have ran into our fair share of unexpected, puzzling and dangerous bugs while working with Playwright at Momentic.

In this post, we're detailing the four most frustrating pitfalls we've encountered that have cost us dozens of engineering hours to remediate. Hopefully you can avoid them in your CI/CD pipelines as well!

## Pitfalls

### High page.screenshot() latency

Playwright's `page.screenshot()` method can hang for extremely long periods of time if your site loads custom fonts. Even though your site may not require these fonts to function correctly, by default Playwright will wait for **any** font loading network requests to complete before taking a screenshot.

If you notice that your screenshots are taking longer than 100ms to complete, turn on Playwright's [debug logging](https://playwright.dev/docs/debug) and see if the output is similar to the following:

How do you bypass this error? With a little sleuthing [inside the Playwright codebase](https://github.com/microsoft/playwright/blob/c3d8b22198244a692eb059db47c7d80bc9eefed5/packages/playwright-core/src/server/screenshotter.ts#L267), we discovered that you can force Playwright to bypass waiting for fonts to load with the `PW_TEST_SCREENSHOT_NO_FONTS_READY` environment variable. For example, JavaScript / Typescript users can simply add the following line before invoking `.screenshot()`:

Setting this environment variable improved screenshot speed by more than 10X for some Momentic customers!

### Hanging page loads

Did you know that the default options for `page.goto`, `page.waitForLoadState`, and `page.waitForURL` can actually cause testing scripts to hang indefinitely?

By default, these functions wait until the page fires the [load event](https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event). This event typically fires when all dependent resources have finished loading, including fonts, images, iframes, and scripts.

However, [many sites](https://stackoverflow.com/a/75725024) never fire this event due to long-running ads, dynamic iframe content, or background analytics events that continuously "reset the clock" on the load state. In these cases, the aforementioned Playwright functions will **never** return. And while these functions do support timeouts, the **default timeout is 0**, which equates to an unlimited timeout.

Thankfully, Playwright does allow you to override which event these functions wait for. For example, the following call only waits until the [DOMContentLoaded event](https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event), which fires immediately after the HTML document is parsed:

Note that at the DOMContentLoaded stage, the page may not have finished loading all assets. While [Playwright locators](https://momentic.ai/blog/the-ultimate-guide-to-playwright-trace-viewer-master-time-travel-debugging) automatically wait for the targeted element to stabilize, any custom logic will have to incorporate explicit waiting logic. For example, if your goal is to extract the name of a button on the page, you should explicitly wait for the button to exist before performing the extraction:

In the above example, the `scrollIntoViewIfNeeded` method ensures that the button has fully loaded before the custom `evaluate` code begins.

### Hanging locator.evaluate calls

`locator.evaluate()`

Many engineers will assume that the timeout parameter controls the execution time for the function being evaluated. Confusingly, this is **not** the case.

In actuality, the timeout is the maximum amount of time Playwright will wait **for the element to be available** on the page. Even if your function does something incredibly expensive, Playwright will never terminate it!

For example, the following code that attempts to wait until an input element has a value will never terminate and likely cause your headless browser to crash:

`evaluate()`

### Canceled navigations

Consider the following pseudo-code that attempts to sign in and then navigate to the dashboard sub-page:

`page.navigate()`

This is problematic since a complete redirection is usually required to obta incorrect authentication cookies. Therefore, in all likelihood, the dashboard page will not consider the user logged in. Some browsers even explicitly crash with an `ERR_ABORTED` or `ERR_CANCELLED` code when a navigation is cancelled.

Why does this happen? It turns out that in-progress browser navigations are immediately interrupted by `page.goto` or `page.reload` calls. While Playwright attempts to wait for navigations **immediately triggered** by interactive commands to complete (e.g. clicking on an anchor tag), any JavaScript-triggered redirections can run into this race condition.

An easy but potentially flaky way to address this issue is to wait for the navigation to complete by explicitly waiting until some new text appears on the page. For example:

Alternatively, at Momentic, we built an in-house page load management system that automatically detects when new page navigations occur, and pauses all other Playwright operations until those navigations are complete. This avoids users having to explicitly craft waiting conditions in most cases.

## Conclusion

Playwright is an amazing piece of open source software. However, due to its wide feature set and complexity, writing effective, bug-free, and maintainable Playwright code can be a challenge!

The four pitfalls outlined in this article are just some of the most frustrating quirks we encountered, investigated, and debugged over thousands of hours of operating Playwright at scale. We hope that this information saves you some tears and sweat!

P.S: If you are looking for a way to achieve quality without worrying about any of this, we built [Momentic](/) so that **anyone** can author complex E2E tests without a single line of code.

## Keep reading.

[Engineering   Axing our Custom Harness for AI SDK: Tool-based Agents for E2E Testing     From brittle browser scripts to self-healing AI agents: how we rebuilt AI Action to discover, replay, and repair end-to-end test flows without rewriting test code.     Zach Bellay     10 min read](/blog/tool-based-agents-for-e2e-testing)[Engineering   How We Ditched Postgres for ClickHouse to Process 12 Billion Caches Per Day     From Postgres pain to ClickHouse speed: how we re-architected caching to serve 2M+ cache queries and 20B entries per day, while maintaining ~250ms average resolution latency.     Henry Haefliger     6 min read](/blog/postgres-to-clickhouse-migration)[Engineering   Most Browser Agents "See" the DOM. Ours Had to Understand User Intent.     Browser agents look at the DOM. Momentic understands what the user actually meant. Here's how we scaled intent-based caching to maintain a 95%+ cache hit rate and be significantly more reliable.     Henry Haefliger     8 min read](/blog/teaching-browser-agents-user-intent)

## Close the feedback loop.

Point Momentic at your app. Free to start, no credit card.

[Try for free](https://app.momentic.ai/signup) [Contact sales](/sales)
