lecture 4 of 180 completed

Moving around the app

goto, clicking links, and why asserting the URL turns a confusing failure into an obvious one.

Every test starts by going somewhere, and there is one habit here that catches real bugs.

page.goto loads a page:

await page.goto('/login');

With baseURL set in config, that path is added to it. Playwright waits for the page to load before continuing, so you do not wait yourself.

Most navigation in a test is a click, not a goto:

await page.getByRole('link', { name: 'Cart' }).click();

Now the habit. After navigation, check where you landed.

await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page).toHaveURL(/.*dashboard/);

This looks like a formality. It is one of the most useful assertions you can write, because it catches the case where login silently does nothing.

Without it, here is what happens. You click sign in, the app rejects the password and stays put, and your next line looks for a welcome message. The failure says "element not found", which tells you nothing about the cause. With the URL check, the test fails one line earlier saying it expected a dashboard URL and got the login one. Now the cause is obvious.

toHaveURL takes a regular expression, which is why the example has /.*dashboard/. That means "any URL containing dashboard". You can also pass an exact string.

Two more you will want:

await page.goBack();
await page.reload();

page.reload() earns its place in a test. It is how you prove something was really saved rather than just drawn on screen. Create a contact, reload, check the row is still there. Without the reload you have only proved the app updated its own display, which it would also do if the save request failed silently.

One thing worth understanding early, because it explains a class of confusing behaviour. In modern apps a link click usually does not reload the page. JavaScript swaps the content and updates the address bar. Playwright handles both, but it matters for your mental model: a URL change is not always a fresh page, and state from earlier may still be there.

Remember this: after any navigation, assert the URL. It converts a vague failure into a specific one.

Reference: Navigations.