Playwright · 3 min read

Playwright 1.65 Changes How Page Object Fields Initialize

Playwright 1.65 follows useDefineForClassFields, so page object fields initialized from this.page can throw. It also adds Bun support and failures-only reports.

Playwright 1.65, released November 5, 2026, compiles TypeScript class fields the way tsc does: it now follows useDefineForClassFields from your tsconfig.json. That breaks page objects that build locators in field initializers. A field initializer that reads a constructor parameter property, such as this.page, throws a TypeError as soon as a test builds the page object. The test runner can now also run under Bun, and new reports keep only failures (release notes).

Page object fields that read this.page now throw

The release notes put it plainly: "A field initializer that reads a constructor parameter property now fails, because the initializer runs first." The flag "is enabled for ES2022 and later targets, and when target is not specified", so a project with no target in its tsconfig.json is affected too.

This is the shape that breaks:

class LoginPage {
  // TypeError: Cannot read properties of undefined (reading 'getByRole')
  readonly submit = this.page.getByRole('button', { name: 'Submit' });

  constructor(private readonly page: Page) {}
}

The fix is to declare the field and assign it in the constructor:

import { type Locator, type Page } from '@playwright/test';

export class LoginPage {
  readonly submit: Locator;

  constructor(private readonly page: Page) {
    this.submit = page.getByRole('button', { name: 'Submit' });
  }
}

The other way out, per the notes, is "useDefineForClassFields": false in tsconfig.json. Moving the assignment works under either setting, and tsc already reports the old pattern as error TS2729 ("Property 'page' is used before its initialization") on ES2022 and later targets. To list candidate fields before upgrading, search the test folder:

grep -rnE '^\s+((public|private|protected|readonly|override)\s+)*#?\w+\s*(:[^=]+)?=\s*this\.' tests

An initializer split across lines slips past the search; npx tsc --noEmit --target ES2022 reports those as TS2729 too.

Bun runs the test runner with --bun

The test runner now runs under Bun, which transpiles TypeScript itself. The flag matters: "without it bunx playwright test runs on Node.js".

bunx --bun playwright test

The Playwright team runs its own test runner tests "under Bun 1.4.3 on Linux", and the notes list what differs. There is no watch mode, --tsconfig and custom ESM loaders don't apply, stack traces lose async frames, and console output doesn't reach the trace or UI mode. Step titles change too: "click instead of locator.click". Anything in CI that matches on step titles or error messages needs a check before a team switches runtimes.

Failures-only reports for CI logs

The new failures reporter "prints failures and successful retries as they occur, followed by a summary, without progress output". The HTML, JSON and JUnit reporters get an onlyFailures option that "keeps only tests with unexpected outcomes, flaky tests and interrupted tests":

import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [
    ['failures'],
    ['html', { onlyFailures: true }],
  ],
});

Flaky tests stay in the trimmed report, so a suite that tracks them, as in fixing flaky Playwright tests, keeps that signal while the report drops the passing rows.

Five more Playwright 1.65 changes to check before upgrading

  • Node.js 20 is no longer tested. Use Node.js 22, 24 or 26; the Docker images now ship Node.js 26.
  • Actions such as click, fill and check wait for an element to be not inert, and time out if it stays inert.
  • A sharded run fails with "No tests found" when no shard has tests. Pass --pass-with-no-tests to allow it. An empty shard still passes when other shards have tests, so a matrix of shard jobs like the one in running tests in GitHub Actions fails only when the whole run matches nothing.
  • Cookie matching follows RFC 6265: with a URL, browserContext.cookies() and apiRequestContext.cookies() no longer return host-only cookies for subdomains or Path=/api cookies for /apiv2.
  • Proxy credentials are no longer sent to websites. Use httpCredentials for site login.

Upgrade with npm i -D @playwright/test@1.65.0 and npx playwright install --with-deps, then bump a container job to mcr.microsoft.com/playwright:v1.65.0-noble. Run the suite once locally to catch page object errors first. The full list, including the new -exclusive- test lock, is in the Playwright release notes.

Install the automation bundle.

9 plugins for test automation: web E2E, API, mobile, BDD, visual regression, CI integration, flaky-test triage and test-code review.

/plugin install qa-role-automation-engineer@testland-qa