Q9 of 42 · Playwright

What is page.goto() and what options does it accept?

PlaywrightJuniorplaywrightnavigationfundamentalsjunior

Short answer

Short answer: `page.goto(url)` navigates to the URL and resolves when a load event fires. Options include `timeout`, `waitUntil` ('load' default, 'domcontentloaded', 'networkidle', 'commit'), and `referer`. Returns the navigation Response — you can assert on its status.

Detail

page.goto is the standard way to navigate. The behaviour:

const response = await page.goto('/dashboard');
expect(response?.status()).toBe(200);

If baseURL is set in config, relative paths resolve against it. Otherwise pass a fully qualified URL.

Options:

  • timeout (default 30s) — how long to wait. Override per call when you know a page is slow.
  • waitUntil — when to consider the navigation done:
    • 'load' (default) — load event fires.
    • 'domcontentloaded' — DOM parsed but resources may still load.
    • 'networkidle' — no network activity for 500ms. Useful for SPAs but can hang on apps with constant polling.
    • 'commit' — navigation committed (response started). Fastest, riskiest.
  • referer — set the Referer header.

Common pitfalls:

  • Apps with persistent WebSocket / long-poll never reach networkidle. Use load or domcontentloaded instead.
  • A 4xx response doesn't throw — page.goto resolves successfully with the response. Assert on response.ok() if you care.
  • Navigation triggered by a click (not by goto) needs page.waitForURL(...) or Promise.all([page.waitForURL(...), button.click()]) to handle.

// EXAMPLE

// Default — wait for load event
await page.goto('/dashboard');

// SPA without persistent polling — wait for network idle
await page.goto('/spa-page', { waitUntil: 'networkidle' });

// Long-running page — bump timeout
await page.goto('/slow-report', { timeout: 60_000 });

// Assert on response status
const response = await page.goto('/protected');
expect(response?.status()).toBe(200);

// Navigation triggered by a click (not goto)
await Promise.all([
  page.waitForURL('**/dashboard'),
  page.getByRole('button', { name: 'Continue' }).click(),
]);

// WHAT INTERVIEWERS LOOK FOR

Knowing the `waitUntil` options and when each is appropriate, that 4xx doesn't throw, and the `Promise.all` pattern for click-triggered navigation.

// COMMON PITFALL

Using `waitUntil: 'networkidle'` on an app with persistent WebSocket / polling — the page never goes idle and the test times out.