Playwright - cleaning up URLs and configuration

Playwright - cleaning up URLs and configuration

Introduction

Repeating full page.goto('http://localhost:4100/login') and asserting that the URL merely “contains /” invites false greens. The Cypress cleanup article walked through hooks and baseUrl; here is the same discipline with Playwright Test.

Previous post: Playwright refactoring - app actions vs POM.

Hooks - test.beforeEach

Playwright reuses Mocha-style hooks. A common pattern: open /login before each test:

import { test } from "@playwright/test"

test.describe("login", () => {
  test.beforeEach(async ({ page }) => {
    await page.goto("/login")
  })

  test("successful login", async ({ page, request }) => {
    // ...
  })
})

In UI mode (npx playwright test --ui) the beforeEach steps are clearly grouped, similar to Cypress’s BEFORE EACH block.

beforeEach in the runner (asset from the Cypress series)

baseURL

In playwright.config.ts:

import { defineConfig } from "@playwright/test"

export default defineConfig({
  use: {
    baseURL: process.env.BASE_URL ?? "http://localhost:4100",
  },
})

Now page.goto("/login") resolves against the frontend origin - the same idea as baseUrl in cypress.json.

URL assertions - substring traps

Checking only / still passes if the app navigates to /you_should_not_be_here. Prefer equality (or a tight regex):

import { expect } from "@playwright/test"

const base = process.env.BASE_URL ?? "http://localhost:4100"

await expect(page).toHaveURL(`${base}/`)
await expect(page).toHaveURL(`${base}/login`)

Wrong “include /” assertion (from the Cypress article)

API base URL

Keep the ASP.NET host (http://localhost:5000) in process.env.API_URL and reuse it inside HTTP helpers. Optionally mirror values into defineConfig({ env: { ... } }) if you prefer reading from test.info(), but shared modules reading process.env are usually enough.

Remember: issue DELETE before POST when seeding users - the same logical bug described in login tests and the URL refactor post if create skips cleanup.

On CI, define BASE_URL and API_URL as pipeline variables (Cypress on Azure shows the idea). Playwright needs no Cypress plugin: Node already sees process.env before tests start.

Summary

Cypress Playwright Test
cypress.json playwright.config.ts
cy.visit('/x') page.goto('/x') + baseURL
Cypress.config() process.env / defineConfig

Reference branch from the Cypress series:

https://github.com/12masta/react-redux-realworld-example-app/tree/4-cypress

https://github.com/12masta/react-redux-realworld-example-app/pull/4/files

Next: data-testid selectors in Playwright.