This rule raises an issue when Playwright tests wait with the 'networkidle' load state.

Why is this an issue?

Playwright can wait until the network is quiet for at least 500 ms through:

Playwright documents this state as discouraged for testing. Pages often keep long-lived connections open, such as analytics beacons, websockets, Server-Sent Events, or polling, so the idle condition may never be reached and the wait times out. When it does resolve, the quiet period still does not prove that the UI the test cares about is ready, which leads to flaky or overly slow suites.

Replace the 'networkidle' wait with a condition that matches what the test actually needs: a web-first assertion such as expect(locator).toBeVisible() or expect(locator).toHaveText(…​), or a specific readiness signal such as page.waitForURL(…​) or page.waitForResponse(…​).

Code examples

Noncompliant code example

test('opens the dashboard', async ({ page }) => {
  await page.goto('/dashboard');
  await page.waitForLoadState('networkidle'); // Noncompliant: "networkidle" wait
  await page.getByRole('button', { name: 'Export' }).click();
});

Compliant solution

test('opens the dashboard', async ({ page }) => {
  await page.goto('/dashboard');
  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
  await page.getByRole('button', { name: 'Export' }).click();
});

Noncompliant code example

test('opens the dashboard', async ({ page }) => {
  await page.goto('/dashboard', { waitUntil: 'networkidle' }); // Noncompliant: "networkidle" wait
  await page.getByRole('button', { name: 'New report' }).click();
});

Compliant solution

test('opens the dashboard', async ({ page }) => {
  await page.goto('/dashboard');
  await expect(page.getByRole('button', { name: 'New report' })).toBeEnabled();
  await page.getByRole('button', { name: 'New report' }).click();
});

Noncompliant code example

test('saves a user', async ({ page }) => {
  await page.getByRole('button', { name: 'Save' }).click();
  await page.waitForLoadState('networkidle'); // Noncompliant: "networkidle" wait
});

Compliant solution

test('saves a user', async ({ page }) => {
  const saveResponse = page.waitForResponse('**/api/users');
  await page.getByRole('button', { name: 'Save' }).click();
  await saveResponse;
  await expect(page.getByText('Saved')).toBeVisible();
});

Resources

Documentation

Related rules