Try adding a / to the end of the URL in your waitForURL call. From the docs for waitForURL:
Note that if the parameter is a string without wildcard characters, the method will wait for navigation to URL that is exactly equal to the string.
Here's a minimal, reproducible example without React, which is probably incidental to the problem (although if you're using React Router, the typical redirect is not using window). I'm using Chromium, so it doesn't exactly match your situation exactly, but may still resolve it.
index.html:
<!DOCTYPE html>
<html>
<body>
<button onclick="window.location.assign('/login')">go</button>
</body>
</html>
login/index.html:
<!DOCTYPE html>
<html>
<body>
<h1>login</h1>
</body>
</html>
pw.test.js:
import {test} from "@playwright/test"; // ^1.38.0
test("redirects to login", async ({page}) => {
await page.goto("http://localhost:3000", {waitUntil: "domcontentloaded"});
await page.locator("button").click();
await page.waitForURL("http://localhost:3000/login");
});
Start a web server: python -m http.server 3000, then navigate in your browser to http://localhost:3000 and click the button to make sure the redirect works as expected.
Run the test and observe the failure:
$ npx playwright test --headed
Running 1 test using 1 worker
✘ 1 pw.test.js:4:5 › redirects to login (30.0s)
1) pw.test.js:4:5 › redirects to login ───────────────────────────────────────
Test timeout of 30000ms exceeded.
Error: page.waitForURL: Navigation failed because page was closed!
=========================== logs ===========================
waiting for navigation to "http://localhost:3000/login" until "load"
============================================================
5 | await page.goto("http://localhost:3000");
6 | await page.locator("button").click();
> 7 | await page.waitForURL("http://localhost:3000/login");
| ^
8 | });
9 |
at pw.test.js:7:14
Slow test file: pw.test.js (30.0s)
Consider splitting slow test files to speed up parallel execution
1 failed
pw.test.js:4:5 › redirects to login ────────────────────────────────────────
Next, change the line
await page.waitForURL("http://localhost:3000/login");
to
await page.waitForURL("http://localhost:3000/login/"); // trailing slash added
Run the test again and observe success:
$ npx playwright test
Running 1 test using 1 worker
✓ 1 pw.test.js:4:5 › redirects to login (289ms)
1 passed (838ms)
Having shown the probable issue and fix, perhaps a better cross-browser approach is to use a regex or glob pattern:
await page.waitForURL(/\/login\/?$/);
await page.waitForURL("**/login/*");