A useful Playwright website script follows a simple loop: open a page, perform a user-visible action, and assert the outcome. Playwright’s actionability checks and web-first assertions wait for elements and expected states, so ordinary tests do not need arbitrary sleep calls. This guide shows how to install Playwright, choose durable locators, record a first draft with Codegen, write complete JavaScript tests, and diagnose common failures.
What a Playwright website script should do
Playwright is a browser automation and testing framework. A script can navigate to a URL, fill forms, click controls, upload files, inspect responses, and verify what a user can observe. A test is valuable when it checks a behavior rather than merely replaying clicks.
- Arrange: open the page and establish any required state.
- Act: use a control as a user would.
- Assert: verify a visible, textual, URL, value, or other observable result.
For example, this JavaScript test opens a site, follows a link, and checks the destination heading:
import { test, expect } from '@playwright/test';
test('site navigation works', async ({ page }) => {
await page.goto('https://example.com/');
await page.getByRole('link', { name: 'Get started' }).click();
await expect(page.getByRole('heading', { name: 'Getting started' })).toBeVisible();
});
Replace the URL and accessible names with values from your own site. The first line of the test opens the page. The locator identifies the link, and click() waits until it is actionable. The final assertion waits until the expected heading is visible.
#1 Best Overall
Install Playwright and choose your project setup
Playwright installation downloads the browser binaries needed by the project. Runtime and operating-system requirements change, so use the current commands and compatibility information in the official installation guide rather than copying an old version matrix.
For a JavaScript or TypeScript project, the Playwright Test setup normally creates a configuration file, an example test, and a test directory. Keep the generated configuration under version control, then run the sample test before changing it. A working sample proves that Node.js, the package installation, browser binaries, and test runner are all available.
Playwright also supports Python and other language workflows. The Codegen command documents JavaScript, Playwright Test, and Python output targets. Select the language that matches your application and CI toolchain; there is no single language or browser combination that is best for every website.
Write a first test in JavaScript
Navigate and assert the page
Use page.goto() for navigation and assert a meaningful result, such as a heading or page title:
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →import { test, expect } from '@playwright/test';
test('home page has the expected title', async ({ page }) => {
await page.goto('https://your-site.example/');
await expect(page).toHaveTitle(/Your Site/);
await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible();
});
A title check alone can pass while the application is broken, so pair it with an element or content that represents the behavior you care about.
Fill and submit a form
test('visitor can submit a contact form', async ({ page }) => {
await page.goto('https://your-site.example/contact');
await page.getByLabel('Name').fill('Ada Lovelace');
await page.getByLabel('Email').fill('ada@example.com');
await page.getByLabel('Message').fill('Please contact me.');
await page.getByRole('button', { name: 'Send message' }).click();
await expect(page.getByRole('status')).toHaveText('Message sent');
});
Labels are preferable to positional selectors because they describe the control a user sees. If the application exposes a live region, checking its status text verifies the result without depending on a particular CSS class.
Check navigation and URL changes
test('pricing link opens the pricing page', async ({ page }) => {
await page.goto('https://your-site.example/');
await page.getByRole('link', { name: 'Pricing' }).click();
await expect(page).toHaveURL(//pricing/);
await expect(page.getByRole('heading', { name: 'Pricing' })).toBeVisible();
});
URL assertions are useful for routing, but combine them with a page-level assertion when the destination must render specific content.
Rank #2
Choose locators that survive UI changes
Playwright’s documentation states: “Locators are the central piece of Playwright’s auto-waiting and retry-ability.” A locator represents an element and is resolved again when an action or assertion runs.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Preferred locator order
- Role and accessible name:
getByRole('button', { name: 'Save' }). - Label:
getByLabel('Email')for form controls. - Visible text:
getByText('Order complete')when the text is the contract. - Test ID:
getByTestId('checkout-submit')when your team deliberately defines a stable testing contract. - CSS or XPath: use only when the preceding choices cannot express the target.
Prefer selectors tied to user-facing meaning instead of DOM position. A selector such as div:nth-child(3) > button can break after an unrelated layout change. If a control has no useful accessible name, improving the page’s semantics often makes both the product and its test easier to maintain.
Disambiguate repeated controls
const rows = page.getByRole('row');
await rows.filter({ hasText: 'Ada Lovelace' })
.getByRole('button', { name: 'Edit' })
.click();
Use filtering to scope a locator to the record or panel that contains the intended control. Avoid selecting the first matching element unless order is itself the behavior under test.
Use auto-waiting instead of arbitrary sleeps
Before acting, Playwright waits for conditions such as visibility, stability, enabled state, and the ability to receive pointer events. Web-first assertions retry until the expected condition is met or the test timeout expires. This handles many normal rendering delays without waitForTimeout().
Wait for a meaningful condition when a page has asynchronous work:
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsawait page.getByRole('button', { name: 'Load reports' }).click();
await expect(page.getByRole('heading', { name: 'Reports' })).toBeVisible();
await expect(page.getByRole('status')).toHaveText('Loaded');
A fixed delay can make a fast run slower and a slow run still flaky. If a delay is genuinely part of the product behavior, document why it exists; otherwise wait for a selector, URL, response, or assertion that represents completion.
Generate a starting script with Codegen
Playwright Codegen opens a browser for interaction and an Inspector that records actions and lets you copy generated tests. It prioritizes role, text, and test ID locators and can generate assertions for visibility, text, and values.
Rank #3
- Start Codegen using the command documented for your installed Playwright version, specifying the target language and browser when needed.
- Enter the site URL in the opened browser.
- Perform the workflow once: click, fill, select, or upload.
- Add assertions in the Inspector for the outcome that must remain true.
- Copy the generated test into your project.
- Review every locator, remove incidental actions, and replace weak assertions with behavior-specific checks.
Codegen is a quick first draft, not a substitute for review. Recording can capture exploratory clicks, transient text, or a selector that is technically valid but coupled to implementation details. Confirm that the resulting test would fail when the intended behavior is broken.
Browser coverage and execution choices
The CLI documents Chromium, Firefox, and WebKit browser options. Run the engines your users and support policy require; do not assume that passing in one engine proves equivalent behavior in all three.
Free tools Windows power users keep installed
One-click scans. No signup required.
Use a focused browser project while developing, then configure the required matrix in continuous integration. Keep tests independent: each test should create or reset its own data, avoid relying on execution order, and use isolated browser contexts supplied by the test fixture.
Common failures and fixes
“Locator resolved to multiple elements”
Cause: the locator is not unique.
Fix: improve the role or accessible name, use a label, add a deliberate test ID, or filter by the containing row or panel. Do not hide ambiguity with first() unless the first item is explicitly the requirement.
“Element is not visible” or “not receiving pointer events”
Cause: a modal, animation, overlay, disabled state, or consent dialog covers the element.
Fix: assert that the required dialog is closed, wait for the application’s visible completion state, or interact with the overlay as a real user would. Avoid forcing a click because it can make a test pass while users still cannot click.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Timeout while waiting for an assertion
Cause: the expected result never appeared, the test used the wrong locator, the backend request failed, or the environment is slower than expected.
Fix: inspect the failure trace and page state, verify the URL and accessible name, and check network or server logs. Increase a timeout only after fixing an incorrect wait condition or establishing that the operation legitimately needs more time.
Works locally but fails in CI
Cause: missing browser binaries, different environment variables, authentication state, viewport, timezone, or test data.
Fix: install the browsers in CI using the current Playwright setup instructions, make prerequisites explicit, and preserve traces or screenshots on failure. Do not depend on a developer’s existing browser profile.
Codegen produced a brittle selector
Cause: the recorded element lacked a stable role, label, text, or test ID.
Fix: edit the generated file manually. Add accessible names or a documented test ID to the application, then regenerate or replace the selector.
Reliability and maintenance checklist
- Assert the result of each important user action.
- Prefer role, label, text, and deliberate test-ID locators.
- Use web-first assertions instead of fixed sleeps.
- Keep test data and authentication setup deterministic.
- Run required browser engines rather than an arbitrary matrix.
- Review Codegen output before committing it.
- Use traces, screenshots, and server logs to diagnose failures.
- Follow the live Playwright installation documentation for version-sensitive requirements.
Or skip the browser setup
If your goal is a clean image or PDF of a website rather than an interaction test, ScreenshotNeo provides a website screenshot API and MCP server. One request can return PNG, JPEG, WebP, or PDF. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup 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 result.
Use the API documentation at https://screenshotneo.com/docs/ for all options, including full-page lazy-image capture, CSS-element capture, dark mode, device presets, custom viewport and retina scale, PDF paper and page settings, custom CSS or JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage data, and the OpenAPI specification.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchcurl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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}`);
ScreenshotNeo also includes an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots each month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.
FAQ
Can Playwright record my actions and turn them into a test?
Yes. Codegen records browser interactions and can add assertions, but inspect and refine the generated file before relying on it.
Which locator should I use when a page has no useful labels?
Prefer a role or visible text where possible. If neither is stable, define a deliberate test ID contract rather than coupling the test to DOM structure.
Do I need a fixed wait after every click?
No. Playwright waits for actionability and retries web-first assertions. Wait for a meaningful application condition instead.
Recommended Free Tools
Frequently Asked Questions
Can Playwright record my actions and turn them into a test?
Yes. Codegen records browser interactions and can add assertions, but inspect and refine the generated file before relying on it.
Which locator should I use when a page has no useful labels?
Prefer a role or visible text where possible. If neither is stable, define a deliberate test ID contract rather than coupling the test to DOM structure.
Do I need a fixed wait after every click?
No. Playwright waits for actionability and retries web-first assertions. Wait for a meaningful application condition instead.
Quick Recap
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.

