Playwright Test Hanging Issue Fix: Causes, Examples, and Troubleshooting Guide

Introduction: What Does a Playwright Test Hanging Issue Mean?

A playwright test hanging issue occurs when a test starts but does not finish, fail, or move to the next step within a reasonable time.

For example:

import { test } from ‘@playwright/test’;

test(‘login test’, async ({ page }) => {

  await page.goto(‘https://example.com’);

  await page.getByRole(‘button’, { name: ‘Login’ }).click();

  // Test appears stuck here

});

A hanging test is different from a normal assertion failure. Instead of quickly reporting that an expected condition was false, the test may remain waiting for an operation to complete.

Common causes include:

  • An incorrect locator
  • Navigation that never finishes
  • An API that never responds
  • An infinite wait
  • An open browser resource
  • WebSocket connections
  • Incorrect synchronization
  • Excessive waitForTimeout()
  • CI/CD resource limitations
  • Parallel tests consuming too many resources

This playwright test hanging issue fix tutorial explains how to identify the root cause instead of simply increasing timeouts.


Hanging Test vs Timeout Failure

Understanding the difference is important for debugging.

ProblemMeaning
Hanging testTest appears stuck and does not complete normally
Timeout failurePlaywright waited until the configured timeout and then failed
Flaky testSame test sometimes passes and sometimes fails
Assertion failureApplication state does not match the expected result
Application failureThe application itself is genuinely broken

Playwright has built-in timeouts that eventually protect many operations from waiting forever. However, certain user-written code, external processes, or resource problems can make a test appear stuck for a long time.


Common Causes of Playwright Test Getting Stuck

Before changing code, investigate these areas:

  1. Locator waiting indefinitely
  2. Navigation waiting too long
  3. API request not completing
  4. Incorrect networkidle usage
  5. waitForTimeout() used repeatedly
  6. Browser process problems
  7. Unclosed pages or contexts
  8. Authentication redirects
  9. WebSocket connections
  10. Parallel execution overload
  11. CI/CD network problems
  12. Incorrect timeout configuration

The fastest playwright test hanging issue fix is usually to identify the exact statement where execution stops.


Infinite Waits and Incorrect Synchronization

Problem → Root Cause → Fix → Best Practice

Problem

A test waits for an element that never appears:

await page.getByText(‘Payment Successful’).click();

Root Cause

The application displays:

Payment completed

instead.

Playwright keeps waiting for the requested element to become actionable until the applicable timeout is reached.

Fix

Use the correct locator:

await page.getByText(‘Payment completed’).click();

Or, preferably, use a stable test identifier:

await page.getByTestId(‘payment-success’).click();

Best Practice

Prefer reliable locators and meaningful assertions instead of guessing selectors.


Locator and Assertion Waits

Playwright automatically waits for many locator actions and assertions.

For example:

await page.getByRole(‘button’, {

  name: ‘Submit’

}).click();

You generally do not need:

await page.waitForTimeout(3000);

before clicking.

Instead:

await expect(

  page.getByRole(‘heading’, { name: ‘Order Confirmed’ })

).toBeVisible();

This is a deterministic synchronization strategy.


Fixing waitForTimeout() Problems

Problem → Root Cause → Fix → Best Practice

Problem

await page.waitForTimeout(10000);

The test takes 10 seconds even when the page becomes ready after one second.

Root Cause

waitForTimeout() always waits for the requested duration.

Fix

Replace it with an assertion:

await expect(

  page.getByTestId(‘dashboard’)

).toBeVisible();

Best Practice

Use waitForTimeout() only for controlled debugging or unusual cases where a fixed delay is genuinely required.

It should not be your primary synchronization mechanism.


Navigation and Network-Related Hanging

Navigation is a common source of a Playwright test stuck problem.

For example:

await page.goto(‘https://example.com’, {

  waitUntil: ‘networkidle’

});

Modern applications may continuously send:

  • Analytics requests
  • Polling requests
  • WebSocket traffic
  • Notifications
  • Background API requests

Therefore, the network may never become completely idle.

Better Approach

await page.goto(‘https://example.com’);

await expect(

  page.getByRole(‘heading’, { name: ‘Dashboard’ })

).toBeVisible();

Wait for the state your test actually needs.

For API-dependent tests, use a targeted response:

const responsePromise = page.waitForResponse(response =>

  response.url().includes(‘/api/dashboard’) &&

  response.status() === 200

);

await page.goto(‘https://example.com/dashboard’);

await responsePromise;

await expect(

  page.getByTestId(‘dashboard’)

).toBeVisible();

This is much more reliable than waiting for every network request to finish.


Handling Slow Navigation

If the application genuinely needs more time, configure a reasonable navigation timeout.

import { defineConfig } from ‘@playwright/test’;

export default defineConfig({

  use: {

    navigationTimeout: 45_000

  }

});

You can also configure it for a specific test:

test(‘slow page’, async ({ page }) => {

  page.setDefaultNavigationTimeout(45_000);

  await page.goto(‘https://example.com/slow-page’);

});

However, increasing the timeout should not be the first response to every hanging test.

Ask:

Is the application actually slow, or am I waiting for the wrong condition?


Browser, Page, Context, and Process Issues

Browser resources can also cause a Playwright test not completing problem.

If you manually create resources:

import { chromium } from ‘@playwright/test’;

(async () => {

  const browser = await chromium.launch();

  const context = await browser.newContext();

  const page = await context.newPage();

  await page.goto(‘https://example.com’);

  console.log(await page.title());

  await page.close();

  await context.close();

  await browser.close();

})();

Make sure resources are closed.

For standard Playwright Test fixtures, Playwright handles browser/page lifecycle for you:

test(‘homepage’, async ({ page }) => {

  await page.goto(‘https://example.com’);

});

Avoid manually launching additional browsers inside every test unless you have a specific reason.


Authentication and API-Related Hanging Tests

Authentication can create confusing loops.

For example:

Login → Redirect → Login → Redirect → Login

The test may appear to hang because authentication never reaches the expected application state.

Check:

  • Login API status
  • Redirect URL
  • Cookies
  • Storage state
  • Authentication tokens
  • Environment variables
  • API availability

Use explicit API synchronization where necessary:

const loginResponse = page.waitForResponse(response =>

  response.url().includes(‘/api/login’) &&

  response.ok()

);

await page.getByLabel(‘Username’).fill(‘testuser’);

await page.getByLabel(‘Password’).fill(‘password’);

await page.getByRole(‘button’, { name: ‘Login’ }).click();

await loginResponse;

await expect(

  page.getByRole(‘heading’, { name: ‘Dashboard’ })

).toBeVisible();


Parallel Execution and Resource Problems

A test may pass alone but hang when many tests execute simultaneously.

For example:

npx playwright test –workers=8

Eight workers may overload:

Try reducing workers:

npx playwright test –workers=2

Or temporarily run serially:

npx playwright test –workers=1

If the problem disappears, investigate resource contention instead of modifying every test.


Debugging Playwright Hanging Tests

1. Use Playwright Inspector

Run:

npx playwright test –debug

The Inspector lets you step through actions and identify where the test stops progressing.


2. Add Request and Response Logging

page.on(‘request’, request => {

  console.log(‘REQUEST:’, request.method(), request.url());

});

page.on(‘response’, response => {

  console.log(‘RESPONSE:’, response.status(), response.url());

});

page.on(‘requestfailed’, request => {

  console.log(

    ‘FAILED:’,

    request.url(),

    request.failure()?.errorText

  );

});

This is useful for identifying:

  • Failed APIs
  • Repeated requests
  • Slow services
  • Unexpected redirects
  • Network problems

3. Use Trace Viewer

Run:

npx playwright test –trace=on

Then inspect the trace:

npx playwright show-trace trace.zip

Trace Viewer can help you understand the sequence of actions before the test became stuck.


4. Capture Screenshots

A screenshot can show whether the application is:

  • Still loading
  • Showing a login page
  • Displaying an error
  • Stuck behind a modal
  • Waiting for an unexpected state

await page.screenshot({

  path: ‘debug-page.png’,

  fullPage: true

});


Fixing Playwright Hanging Tests in CI/CD

A common scenario is:

The test works locally but hangs in CI.

Check the following:

Run with fewer workers:

npx playwright test –workers=1

Enable tracing:

npx playwright test –trace=on

Also collect the HTML report:

npx playwright show-report

CI failures often expose race conditions or resource problems hidden by a fast local machine.


Real-World Playwright Test Hanging Issue Examples

Example 1: Infinite Wait

Problem:

await page.waitForSelector(‘.loading-complete’);

Root Cause: The application uses a different selector.

Fix:

await expect(

  page.getByTestId(‘dashboard’)

).toBeVisible();

Best Practice: Use stable application-specific locators.


Example 2: Network Hanging

Problem:

await page.goto(‘/dashboard’, {

  waitUntil: ‘networkidle’

});

Root Cause: Dashboard polling never stops.

Fix:

await page.goto(‘/dashboard’);

await expect(

  page.getByTestId(‘dashboard’)

).toBeVisible();

Best Practice: Wait for application readiness rather than network inactivity.


Example 3: CI Hanging During Parallel Execution

Problem: Tests complete individually but stall when running 12 workers.

Root Cause: CI machine has insufficient resources.

Fix:

npx playwright test –workers=2

Best Practice: Choose worker counts based on available CI resources.


Common Mistakes and Solutions

MistakeSolution
Using long waitForTimeout() callsUse assertions
Waiting for networkidle everywhereWait for specific conditions
Increasing every timeoutIdentify the root cause
Ignoring failed requestsLog requests and responses
Running too many workersReduce parallelism
Manually opening browsers unnecessarilyUse Playwright fixtures
Ignoring authentication redirectsValidate login/API state
Debugging only locallyReproduce in CI-like environment
Using unstable locatorsPrefer role, label, and test IDs

Playwright Test Stability Best Practices

For a reliable Playwright TypeScript framework:

Use deterministic synchronization

await expect(

  page.getByTestId(‘results’)

).toBeVisible();

Avoid unnecessary sleeps

await page.waitForTimeout(5000);

should not be your normal synchronization method.

Use targeted API waits

await page.waitForResponse(response =>

  response.url().includes(‘/api/results’) &&

  response.ok()

);

Keep timeouts reasonable

Do not hide defects with extremely large timeout values.

Use stable locators

Prefer:

page.getByRole(‘button’, { name: ‘Save’ })

over brittle CSS/XPath selectors.

Debug failures with evidence

Use:

  • Trace Viewer
  • Screenshots
  • Video
  • HTML reports
  • Request logs
  • Response logs

Playwright Interview Questions With Answers

Why is my Playwright test hanging?

Common causes include incorrect waits, unavailable locators, slow navigation, APIs that never respond, continuous network requests, browser issues, and CI resource constraints.

How do you fix a Playwright test that is stuck?

Identify the exact statement where execution stops. Then inspect the locator, network request, navigation, timeout, browser process, and CI environment involved.

Why should you avoid excessive waitForTimeout()?

It introduces fixed delays and does not verify that the application is actually ready.

Is networkidle always recommended?

No. Applications with polling, WebSockets, analytics, and background requests may never become idle.

How do you debug Playwright hanging in CI/CD?

Run with fewer workers, enable tracing, collect screenshots and reports, inspect request failures, and compare the CI environment with local execution.

What is the difference between a timeout and a hanging test?

A timeout is a controlled failure after Playwright waits for a configured duration. A hanging test appears stuck because an operation, resource, process, or synchronization mechanism is preventing normal completion.


FAQs

Why is my Playwright test hanging?

A Playwright test can hang because it is waiting for an element, navigation, API response, network state, browser resource, authentication redirect, or another condition that never completes.

How do I fix a Playwright test stuck problem?

Find the exact operation where the test stops, then replace unnecessary waits with deterministic locators, assertions, targeted API waits, or appropriate timeouts.

How do I fix a Playwright test not completing?

Check open resources, navigation, API requests, WebSockets, authentication, parallel workers, and CI resource constraints.

Can waitForTimeout() cause Playwright tests to hang?

A large waitForTimeout() makes tests unnecessarily slow. It can contribute to the appearance of hanging when several long fixed waits are chained together.

Why does Playwright hang in CI but pass locally?

CI machines may have different CPU, memory, network latency, browser dependencies, environment variables, API availability, or worker configurations.


Leave a Comment

Your email address will not be published. Required fields are marked *