Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Most “page is not defined” failures are scope errors, not Angular errors. In Playwright Test, import test and expect from @playwright/test, then request the page fixture in every test, hook, helper, or page object that uses it. Once that runs, debug Angular validation separately: identify whether the form is reactive or template-driven, use accessible locators, await every browser action, and assert the message the user can actually see.

Fix the missing page variable first

page is a Playwright fixture supplied to a test callback; it is not a global browser object. The runner creates an isolated Page for a test that asks for it. See the Playwright fixture guide and fixture API.

import { test, expect } from '@playwright/test';

test('shows a validation message for an empty email', async ({ page }) => {
  await page.goto('/signup');
  await page.getByLabel('Email').fill('');
  await page.getByRole('button', { name: 'Submit' }).click();
  await expect(page.getByText('Email is required')).toBeVisible();
});

The { page } parameter is the binding that makes the identifier available. If you write test('...', async () => { await page.goto(...); }), JavaScript raises ReferenceError: page is not defined because that function has no variable named page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Pass page into helpers

A helper, hook, or page-object class has its own scope. Pass the fixture explicitly rather than assuming it can see a test’s local variable.

#1 Best Overall
Sale
Philips 24 Inch Computer Monitor FHD 100Hz VA VESA Flicker-Free, 241V8LB
  • CRISP CLARITY: This 23.8″ Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
  • INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
  • THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors
  • WORK SEAMLESSLY: This sleek monitor is virtually bezel-free on three sides, so the screen looks even bigger for the viewer. This minimalistic design also allows for seamless multi-monitor setups that enhance your workflow and boost productivity
  • A BETTER READING EXPERIENCE: For busy office workers, EasyRead mode provides a more paper-like experience for when viewing lengthy documents
import { test, type Page } from '@playwright/test';

async function fillSignupForm(page: Page) {
  await page.getByLabel('Email').fill('[email protected]');
}

test('submits a signup', async ({ page }) => {
  await page.goto('/signup');
  await fillSignupForm(page);
});

For a page object, accept Page in the constructor and store it on the instance. In a beforeEach hook, request the fixture in the hook callback too:

test.beforeEach(async ({ page }) => {
  await page.goto('/signup');
});

Do not create a second browser manually just to obtain a variable called page; that bypasses the runner’s isolation, fixtures, tracing, and configuration.

Use locators that survive Angular DOM updates

Playwright recommends locators based on how a user perceives the page. Prefer labels for form controls and roles for buttons, links, and other interactive elements. The locator guide explains the trade-offs.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.getByLabel('Name').fill('');
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByText('Name is required')).toBeVisible();
  • getByLabel(): use when a visible <label> is associated with the input.
  • getByRole(): use the control’s semantic role and accessible name, such as button with “Save”.
  • getByText(): assert a user-visible validation message, using the application’s exact wording.
  • Test IDs: choose an explicit data-testid contract when no suitable user-facing locator exists.
  • CSS or XPath: reserve them for cases where semantic locators cannot identify the element; avoid chains tied to incidental layout.

Locator actions resolve the element when the action runs and automatically wait for it to be actionable. This helps when Angular renders or replaces controls after a state change.

Rank #2
Philips 22 Inch Computer Monitor FHD 100Hz VA VESA Flicker-Free, 221V8LB
  • CRISP CLARITY: This 22 inch class (21.5″ viewable) Philips V line monitor delivers crisp Full HD 1920x1080 visuals. Enjoy movies, shows and videos with remarkable detail
  • 100HZ FAST REFRESH RATE: 100Hz brings your favorite movies and video games to life. Stream, binge, and play effortlessly
  • SMOOTH ACTION WITH ADAPTIVE-SYNC: Adaptive-Sync technology ensures fluid action sequences and rapid response time. Every frame will be rendered smoothly with crystal clarity and without stutter
  • INCREDIBLE CONTRAST: The VA panel produces brighter whites and deeper blacks. You get true-to-life images and more gradients with 16.7 million colors
  • THE PERFECT VIEW: The 178/178 degree extra wide viewing angle prevents the shifting of colors when viewed from an offset angle, so you always get consistent colors

Determine which Angular form you are testing

Angular supports reactive and template-driven forms. Both track values, state, and validity, but the source of that state differs. Angular’s forms overview describes template-driven forms as convenient for simpler forms and reactive forms as a scalable model for complex forms.

Reactive forms

Reactive forms declare controls and validators in the component class. The template binds to that model, so failures often involve the wrong control name, validator, or condition around the error message.

this.form = this.fb.group({
  email: ['', [Validators.required, Validators.email]]
});

In a test, enter an invalid value, perform the event that your UI uses to reveal errors, and assert the rendered result—not an internal control property.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Template-driven forms

Template-driven forms use directives such as NgModel from FormsModule. The template declares controls and validation attributes; Angular creates and updates the model state.

Rank #3
Sale
Dell 24 Monitor - SE2426H - 23.8-inch FHD (1920x1080) 144Hz 1ms Display, in-Plane Switching (IPS) Technology, AMD FreeSync™, TÜV 3-Star 2X HDMI, Tilt
  • Clear visuals. Fluid motion: A 144Hz refresh rate and 1ms MPRT deliver smooth, tear‑free motion across work, gaming, and streaming for clearer, more fluid viewing.
  • Eye comfort: TÜV Rheinland 3‑star* certification reduces harmful blue light while preserving stunning color quality without compromise. *TÜV Rheinland 3-star eye comfort certification.
  • Wide viewing angle: Get consistent views across a wide 178° /178° viewing angle.
  • In-Plane Switching (IPS): See excellent color accuracy and consistency across wide viewing angles with In-plane Switching (IPS) technology.
  • Ultra-thin bezels: Maximize your viewing experience with thin bezels.
<input name="email" [(ngModel)]="model.email" required email>

When diagnosing a failure, inspect the exported NgModel state and the form’s registration. A control may be invalid while its message remains hidden until it is touched, dirty, or the form has been submitted.

Trigger the same state a real user would

Angular validation messages commonly depend on touched, dirty, or a submitted form. Filling a field alone may not display an error if the application waits for blur or submit. Reproduce that transition in the test:

test('shows required error after submit', async ({ page }) => {
  await page.goto('/signup');
  await page.getByLabel('Email').fill('');
  await page.getByRole('button', { name: 'Submit' }).click();
  await expect(page.getByText('Email is required')).toBeVisible();
});

If the application validates on blur, use await page.getByLabel('Email').blur() before asserting. If it validates only after a value is entered, supply an invalid value such as not-an-email and assert the corresponding message. Match the exact accessible name and copy used by your application.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Await actions; do not start with arbitrary sleeps

Make the test callback async and await navigation, locator actions, and assertions. Playwright’s migration guidance says its auto-waiting generally removes the need for Protractor’s waitForAngular in ordinary cases; see the Protractor migration guide.

Rank #4
Samsung 27" Essential S3 (S36GD) Series FHD 1800R Curved Computer Monitor
  • CURVED FOR ENHANCED ENGAGEMENT: An immersive viewing experience with a curved monitor that wraps more closely around your field of vision; It creates a wider view, enhancing depth perception and minimizing peripheral distraction
  • SMOOTH PERFORMANCE FOR SEAMLESS CONTENT: Stay in the action when playing games, watching videos, or working on creative projects; The 100Hz refresh rate reduces lag and motion blur so you don't miss a thing in fast-paced moments¹
  • MORE GAMING POWER: Gain the edge with optimizable game settings; Color and image contrast can be adjusted to see scenes more vividly and spot enemies hiding in the dark; Game Mode adjusts any game to fill the screen so you can view every detail²
  • KEEP IT EASY ON THE EYES: Care for your eyes and stay comfortable, even during long sessions; Advanced eye comfort technology certified by TÜV reduces eye strain by minimizing blue light and reducing irritating screen flicker²
  • INCREASED VERSATILITY: Connect to more; Plug devices straight into your monitor for increased flexibility, making your computing environment even more convenient
test('validates a password', async ({ page }) => {
  await page.goto('/signup');
  await page.getByLabel('Password').fill('short');
  await page.getByRole('button', { name: 'Create account' }).click();
  await expect(page.getByText('Password must be at least 8 characters')).toBeVisible();
});

Locator construction, such as page.getByLabel('Email'), is synchronous; the operation on that locator is not. A fixed waitForTimeout can hide a race and make a suite slow. If an awaited assertion still fails, verify the selector, validation rule, message visibility condition, and rendered DOM before adding a delay for a genuinely external process.

Separate Playwright scope errors from Angular registration errors

ReferenceError: page is not defined is a JavaScript or TypeScript scope problem. It occurs before Angular validation can explain the failure. An Angular error such as NG01354 is different: Angular documents it when an NgModel in a child component cannot reach its parent form. The child controls then do not participate in the parent’s value, validity, or submission state.

  • Fix missing page by importing the runner and receiving the fixture.
  • Fix NG01354 by checking the child control’s form registration and whether it should be standalone or part of the parent form.
  • Do not treat an Angular console error as evidence that the Playwright fixture disappeared.

End-to-end or component test?

For a normal browser journey, use an end-to-end test against the running Angular application. It exercises routing, rendering, browser events, and the real form submission path. Playwright component testing is a separate approach with a mount fixture and story gallery; it is not required for ordinary end-to-end form tests. See Playwright component testing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Decision Use this when What the test observes
End-to-end You need the running app, routing, and browser-visible validation Real page interaction and rendered messages
Component test You want to mount an isolated component with Playwright’s component setup Component behavior without the full application journey

A practical failure checklist

  1. Confirm the file imports { test, expect } from @playwright/test.
  2. Confirm every callback that uses the fixture declares async ({ page }) or receives page through another argument.
  3. Check helper and page-object constructors for an explicit Page parameter.
  4. Run the test against the correct base URL and verify that page.goto() reaches the expected route.
  5. Inspect the accessible name with Playwright’s inspector or a trace, then replace brittle CSS with a label or role locator.
  6. Identify reactive versus template-driven forms and inspect the matching control or NgModel state.
  7. Trigger blur, dirty, touched, or submit state exactly as the UI requires.
  8. Await every action and assertion; investigate the rendered DOM before adding sleeps.
  9. If Angular reports NG01354 or another named error, follow that error’s Angular documentation instead of changing Playwright fixture code.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If you only need a rendered reference image of a form page, ScreenshotNeo returns a screenshot or PDF from one GET request. It accepts the cookie or consent banner as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo documentation for all 63 options, including full-page and element capture, device and retina settings, dark mode, PDF margins and page ranges, custom CSS or JavaScript, click and wait conditions, request blocking, headers, cookies, geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous webhooks, bulk capture, usage data, and OpenAPI compatibility.

Best Value
Sale
Sceptre New 22-Inch Gaming Monitor, FHD 1080p, Up to 144Hz, HDMI, DisplayPort, Built-in Speakers, Machine Black (E225W-FW144 Series, 2026)
  • 【INTEGRATED SPEAKERS】Whether you're at work or in the midst of an intense gaming session, our built-in speakers provide rich and seamless audio, all while keeping your desk clutter-free.
  • 【EASY ON THE EYES】 Protect your eyes and enhance your comfort with Blue-Light Shift technology. This feature reduces harmful blue light emissions from your screen, helping to alleviate eye strain during long hours of use and promoting healthier viewing habits.
  • 【WIDEN YOUR PERSPECTIVE】Our sleek minimal bezel design ensures undivided attention. The nearly bezel-free display seamlessly connects in a dual monitor arrangement, delivering an unobstructed view that lets you focus on more at once, completely distraction-free.
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 screenshots a month without a card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account.

Frequently Asked Questions

Can I use a global Playwright page fixture?

No. The supported pattern is to request the runner-provided fixture in each test or hook and pass it into helpers or page objects.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why is my Angular error message in the DOM but not visible?

The application may show it only after the control is touched, dirty, or the form is submitted. Reproduce that transition before asserting visibility.

Should I replace every CSS selector with a test ID?

No. Use labels and roles first; add a deliberate test ID when no stable user-facing locator exists.

Does every Angular form test need waitForAngular?

No. Playwright’s normal auto-waiting generally replaces Protractor’s waitForAngular. Investigate the selector and application state before adding a delay.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.