What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use Playwright scripts in two common ways: a direct browser script for one-off automation, or a Playwright Test test with fixtures and assertions. The smallest useful flow is always the same—launch a browser, open a page, perform an interaction with a resilient locator, and verify an observable result. The examples below show both styles, then cover waiting, forms, network interception, debugging, reliability, and common failures.
Choose the right Playwright script style
| Approach | Best for | Lifecycle and verification |
|---|---|---|
| Playwright Library script | One-off automation, data collection, smoke checks, or a custom Node.js program | You launch and close the browser yourself; add your own checks |
| Playwright Test | Repeatable end-to-end tests in a test suite | The runner supplies fixtures such as page, and expect provides retrying web-first assertions |
Both styles use the same browser, context, page, locator, and network APIs. Install Playwright in the project where the script will run, install the browser binaries required by your selected browser, and keep examples aligned with the version installed in your project because APIs and tooling evolve.
Complete Playwright Library script
This CommonJS example launches Chromium, navigates to a page, clicks a link by its accessible role and name, then closes the browser even if an error occurs.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.getByRole('link', { name: 'More information' }).click();
console.log('New URL:', page.url());
} finally {
await browser.close();
}
})();
goto resolves after the selected navigation condition. The default navigation behavior is usually sufficient; choose a more specific condition only when your workflow needs it. Do not treat a successful HTTP response as proof that the application rendered correctly—verify the page state your user needs.
#1 Best Overall
Run the script
- Create a Node.js project and install
playwright. - Install the browser binaries for the browsers you intend to launch.
- Save the file, for example as
smoke.js, and runnode smoke.js.
A Playwright Test example with an assertion
Tests should connect an action to an observable outcome. The following credentials are illustrative documentation values, not safe production credentials.
import { test, expect } from '@playwright/test';
test('sign-in form accepts credentials', async ({ page }) => {
await page.goto('https://example.com/login');
await page.getByLabel('User Name').fill('John');
await page.getByLabel('Password').fill('secret-password');
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page.getByText('Welcome, John!')).toBeVisible();
});
The page fixture is created and disposed by the test runner. The web-first assertion retries while checking the condition; the documented default assertion timeout is five seconds. Configure a different timeout when the application genuinely needs more time, rather than inserting arbitrary sleeps.
Locator examples that survive UI changes
Locators are evaluated when an operation runs, so they cope better with a framework rerendering the DOM between steps. Prefer selectors that describe the interface as a user experiences it.
Roles and accessible names
await page.getByRole('button', { name: 'Save changes' }).click();
await page.getByRole('checkbox', { name: 'Send me a receipt' }).check();
await page.getByRole('link', { name: 'Account settings' }).click();
A role plus meaningful accessible name is usually clearer than a generated class name. If several controls share a name, narrow the locator with a region or other stable relationship.
Labels, text, placeholders, and test IDs
await page.getByLabel('Email address').fill('person@example.test');
await page.getByPlaceholder('Search products').fill('keyboard');
await page.getByText('Order complete').toBeVisible();
await expect(page.getByTestId('status')).toHaveText('Submitted');
Use a test ID when the product team has deliberately made it part of the test contract. Text and placeholders are useful when they are stable and unique, but they can change during copy or localization work.
Rank #2
CSS and XPath when necessary
await page.locator('[data-state="open"] .menu-item').click();
await page.locator('xpath=//button[@data-action="archive"]').click();
CSS and XPath remain available, but long chains coupled to DOM structure are brittle. A redesign can leave the control visually unchanged while breaking a structural selector.
Actions and synchronization
Playwright actions such as click, fill, and check wait for the element to become actionable. Follow each important action with an assertion about the resulting state.
await page.getByRole('button', { name: 'Submit' }).click();
await expect(page.getByTestId('status')).toHaveText('Submitted');
Wait for a condition, not an arbitrary delay
A fixed sleep can pass on a fast machine and fail on a slow one. Prefer a retrying assertion or an explicit wait for a state your application owns.
await page.getByRole('button', { name: 'Refresh' }).click();
await expect(page.getByRole('status')).toHaveText('Updated');
await page.waitForSelector('[data-testid="report-ready"]');
Use waitForSelector sparingly when an assertion can express the expected result more directly. For navigation, wait for the URL or a page-level outcome instead of assuming a click completed immediately.
await Promise.all([
page.waitForURL('**/dashboard'),
page.getByRole('link', { name: 'Dashboard' }).click(),
]);
Forms, dialogs, and new pages
Forms and validation
await page.getByLabel('Quantity').fill('2');
await page.getByRole('radio', { name: 'Express delivery' }).check();
await page.getByRole('button', { name: 'Place order' }).click();
await expect(page.getByRole('alert')).toContainText('Order received');
Browser dialogs
page.once('dialog', async dialog => {
console.log(dialog.type(), dialog.message());
await dialog.accept();
});
await page.getByRole('button', { name: 'Delete' }).click();
Popups and new tabs
const popupPromise = page.waitForEvent('popup');
await page.getByRole('link', { name: 'Open receipt' }).click();
const popup = await popupPromise;
await popup.waitForLoadState('domcontentloaded');
await expect(popup.getByRole('heading', { name: 'Receipt' })).toBeVisible();
Mock, inspect, or block network requests
Playwright can monitor and modify HTTP and HTTPS traffic, including XHR and fetch. Register a route on a page or browser context before navigation so the application receives the intended response.
Replace an API response with fixture data
import { test, expect } from '@playwright/test';
test('renders mocked products', async ({ page }) => {
await page.route('**/api/products', route => route.fulfill({
json: [{ id: 1, name: 'Product 1' }],
}));
await page.goto('https://example.com/products');
await expect(page.getByText('Product 1')).toBeVisible();
});
This replaces the matching response; it is deterministic fixture testing, not an integration test against the live service.
Modify or abort a request
await page.route('**/api/profile', async route => {
const response = await route.fetch();
const body = await response.json();
body.plan = 'trial';
await route.fulfill({ response, json: body });
});
await page.route('**/*.{png,jpg,jpeg,gif}', route => route.abort());
Use modification when you need most of the real response with one controlled change. Abort selected resources to test degraded behavior or to reduce irrelevant traffic in a focused test.
Choose live or intercepted traffic deliberately
| Goal | Traffic choice | Reason |
|---|---|---|
| Verify the complete integration | Live service or a controlled test environment | Catches contract, authentication, and deployment problems |
| Exercise UI states predictably | Intercepted fixture | Removes latency and changing backend data |
| Test failures and empty states | Fulfill errors, empty JSON, or abort requests | Makes rare conditions repeatable |
Debug failing scripts
UI Mode and Inspector
Use Playwright UI Mode or the Inspector to step through a test, inspect locator calls, view logs and network activity, and examine DOM snapshots. These tools reveal whether the selector is wrong, the page is at the wrong URL, or the expected request never occurred.
HTML Reporter
The HTML Reporter lets you open an individual failure and review its steps and diagnostics. Preserve traces, screenshots, and videos in continuous integration only when they provide useful evidence; they increase artifact size and storage time.
Make a failing state reproducible
- Record the exact URL, browser, viewport, locale, and test data.
- Replace unstable live responses with a route fixture when diagnosing UI behavior.
- Use a locator assertion to identify the first missing state, rather than adding sleeps throughout the script.
- Run the smallest test that reproduces the problem before changing application code.
Reliability, speed, and maintenance
Contexts and isolation
In a library script, create a fresh browser context for an independent user session. In Playwright Test, use the supplied fixtures unless a deliberate shared-state design is required. Isolated contexts prevent cookies and local storage from leaking between scenarios.
Rank #4
Navigation and timeout choices
Set timeouts around real service limits and keep them consistent across environments. A generous timeout can hide a broken endpoint; an aggressive one creates false failures. Prefer a specific readiness assertion over waiting for every network request to become idle, because analytics and long polling can keep a page busy indefinitely.
Free tools Windows power users keep installed
One-click scans. No signup required.
Locator maintenance
Ask the application team to expose accessible names and stable test IDs for controls that cannot be identified by role or label. Review locators when copy, localization, or accessibility changes are made. Avoid selecting by position, such as “the third button,” unless position is the actual contract.
Parallelism and test data
Parallel tests are faster only when data and accounts are independent. Give each worker isolated records or reset state between tests; otherwise a speed improvement becomes an ordering-dependent failure.
Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| “Locator resolved to multiple elements” | The role, label, or text is not unique | Scope to a region, add an accessible name, or use a deliberate test ID; do not blindly use first() |
| Timeout waiting for a locator | Wrong URL, hidden control, changed copy, or an iframe | Inspect the page in Inspector, assert the URL, verify visibility, and use frameLocator for an iframe |
| Click times out because another element covers it | Consent dialog, animation, or overlay | Handle the dialog as a real user would, wait for its disappearance, and avoid forcing the click unless covering behavior itself is under test |
| Assertion is flaky | Fixed sleeps, shared state, or an eventually consistent backend | Use a web-first assertion, isolate data, and intercept the response for deterministic UI tests |
| Route did not intercept | Route registered after navigation or pattern does not match | Register before goto, log the request URL, and correct the glob pattern |
| Browser executable is missing | Playwright package is installed but its browser binaries are not | Run the browser installation command for your project and repeat the script |
| Works locally but fails in CI | Different viewport, permissions, environment variables, or timing | Pin the runtime setup, capture the failure report, and make dependencies and test data explicit |
Or skip the browser setup
If your goal is simply to obtain a clean screenshot rather than interact with a browser in a test, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; each response identifies the page verdict and billing status in X-Page-Verdict and X-Billed headers.
One GET request returns PNG, JPEG, WebP, or PDF. The API supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper and margin settings, custom CSS and JavaScript, clicks before capture, selector hiding, selector/delay/network-idle waits, request blocking, headers, cookies, user agents, Authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification. Existing parameter names used by other screenshot APIs also work for easier migration.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →See the ScreenshotNeo documentation for option names and response details.
curl -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}`);
An MCP server supplies take_screenshot, get_page_info, and capture_pdf tools to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can I use Playwright without the Playwright Test runner?
Yes. Install the Playwright library, launch a browser in your own code, create pages or contexts, and close the browser yourself.
When should I mock an API instead of calling it?
Mock it for deterministic UI states, errors, and empty results; use a live or controlled test environment when you need integration coverage.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesWhy does a locator work once and then fail after rerendering?
Prefer a locator created from a role, label, text, or test ID. Locators are resolved at operation time and are more resilient than storing an obsolete element handle.
What is the fastest way to investigate a timeout?
Run the test with UI Mode or Inspector, check the current URL and DOM snapshot, and identify whether the locator, navigation, overlay, iframe, or network response is the first missing condition.
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.

