QA Graphic
June 19, 2025

CSS Selector Reference Sheet in PlayWright

PlayWright with Typescript reference guide

When working with Playwright and TypeScript, having a concise reference guide for selectors and locators can significantly improve productivity. This cheat sheet highlights commonly used locator strategies and actions in Playwright - ideal for anyone writing end-to-end tests or automating modern web applications.

Below is a handy visual cheat sheet that you can download and keep nearby during your testing work.

Playwright Locator Cheat Sheet

Highlights from the Cheat Sheet

Here's a breakdown of some key locator patterns and actions:


// CSS Selectors
page.locator('#id');
page.locator('.class');
page.locator('tagname');
page.locator('[data-test="button"]');
// By Text
page.locator('text=Submit');
page.locator('text=/Submit/i');
page.getByText('Submit');
// By Role (Recommended for accessibility)
page.getByRole('button', { name: 'Submit' });
page.getByRole('textbox', { name: 'Username' });
page.getByRole('checkbox', { name: 'Remember me' });
page.getByRole('link', { name: 'Learn More' });
// By Test ID
page.getByTestId('submit-button');
// Filtering Locators
page.locator('div.card').getByRole('button', { name: 'Add to Cart' });
page.locator('.item').first();
page.locator('.item').last();
page.locator('.item').nth(2);
// Filter by text content
page.locator('.product-item').filter({ hasText: 'Limited Edition' });
// Filter by child element
page.locator('.product-card').filter({ has: page.locator('.discount-badge') });
// Actions on Locators
await page.locator('#element').click();
await page.locator('#element').fill('value');
await page.locator('#element').scrollIntoViewIfNeeded();
        

This cheat sheet is great for both beginners and experienced QA engineers who want quick access to essential Playwright syntax. It covers a variety of selector strategies from basic CSS to accessibility-driven roles and filtering techniques.

Feel free to print it out, save it, or bookmark this post for future reference.

Permalink
June 12, 2025

Get By Selector Cheat Sheet

A handy reference guide for Playwright's "Get By" selectors using TypeScript.

About This Cheat Sheet

When working with Playwright in TypeScript, selecting elements efficiently is key to writing robust automation scripts. Playwright provides a variety of "Get By" methods to locate elements based on different attributes, text, roles, and more. This cheat sheet summarizes the most commonly used methods, making it a quick reference for developers and testers alike.

Below is the code from the cheat sheet, formatted for easy reading. Feel free to copy and use it in your projects.

Code Breakdown

const element = await page.getByText('Click me');
const input = await page.getByLabel('Username');
const input = await page.getByPlaceholder('Enter your name');
const image = await page.getByAlt('Product Image');
const link = await page.getByTitle('Learn More');
const button = await page.getByRole('button');
const component = await page.getByTestId('product-card');
const nav = await page.getByAriaLabel('Main Navigation');

How to Use These Selectors

  • getByText: Selects an element containing the specified text.
  • getByLabel: Targets input elements by their associated label text.
  • getByPlaceholder: Finds input elements by their placeholder text.
  • getByAlt: Selects image elements by their alt text.
  • getByTitle: Targets elements with a specific title attribute.
  • getByRole: Selects elements by their ARIA role for better accessibility.
  • getByTestId: Finds elements by a custom data-testid attribute, often used in testing.
  • getByAriaLabel: Targets elements by their ARIA label for accessibility-focused testing.

Keep this cheat sheet handy as you build your Playwright scripts. Download the image above to have it as a quick reference whenever you need it.

Permalink
June 5, 2025

Your Go-To Playwright TypeScript Cheat Sheet

Some Common Commands around Navigation and Clicking

If you are working with Playwright and TypeScript for your automated tests, you know how crucial it is to have quick access to common commands. We have put together a handy cheat sheet that covers essential Playwright operations, making your development process smoother and faster.

This cheat sheet is designed as a quick reference guide, perfect for both beginners getting started with Playwright and experienced users who need a reminder of specific syntax. It is organized into logical sections, covering navigation, input, clicking, content retrieval, and dialog handling.

Playwright TypeScript Cheat Sheet

What's Included in the Cheat Sheet?

Here is a breakdown of the key areas covered in this valuable resource:

Navigation

Learn how to navigate through web pages with commands like page.goto(), page.goBack(), page.goForward(), and page.reload(). Also included are useful page.waitForURL() and page.waitForLoadState() examples to ensure your tests wait for the page to be ready.


// Navigation
await page.goto('https://www.example.com');
await page.goBack();
await page.goForward();
await page.reload();
await page.waitForURL('**/dashboard'); // Waits for URL to match a pattern
await page.waitForLoadState('networkidle'); // 'load', 'domcontentloaded', 'networkidle'

Input

Handling user input is a core part of testing. This section demonstrates how to fill text fields using page.fill(), type character by character with page.type(), press specific keys with page.press(), and manage dropdowns with page.selectOption(). It also shows how to upload files using page.setInputFiles().


// Input
await page.fill('#username', 'myUser'); // Fills input field
await page.type('#search-input', 'playwright'); // Types character by character
await page.press('body', 'Escape'); // Presses a key on the page
await page.selectOption('#country-select', 'USA'); // Selects option by value
await page.selectOption('#multi-select', ['option1', 'option2']); // Multi-select
await page.setInputFiles('input[type="file"]', 'path/to/file.png'); // Uploads file

Clicking & Interaction

From simple clicks to more advanced interactions, this part of the cheat sheet covers page.click(), double clicks with page.dblclick(), checking and unchecking checkboxes/radios using page.check() and page.uncheck(). You will also find examples for hovering over elements with page.hover(), focusing on input fields with page.focus(), granular keyboard control with page.keyboard.press(), and clicking at specific coordinates with page.mouse.click().


// Clicking & Interaction
await page.click('button#submit');
await page.dblclick('.item');
await page.check('#remember-me'); // Checks a checkbox/radio
await page.uncheck('#subscribe'); // Unchecks a checkbox
await page.hover('.menu-item');
await page.focus('input-field');
await page.keyboard.press('Enter'); // More granular keyboard control
await page.mouse.click(100, 200); // Clicks at specific coordinates

Content Retrieval

Extracting information from the page is essential for assertions. This section provides commands to get text content using page.innerText(), HTML content with page.innerHTML(), input values via page.inputValue(), and attribute values with page.getAttribute().


// Content Retrieval
const text = await page.innerText('.welcome-message');
const html = await page.innerHTML('#content');
const value = await page.inputValue('input-field');
const attribute = await page.getAttribute('img', 'alt');

Dialog

Learn how to handle browser dialogs such as alerts, confirms, and prompts. The cheat sheet illustrates how to listen for dialog events using page.on('dialog') and how to accept or dismiss them with dialog.accept() and dialog.dismiss().


// Dialog
page.on('dialog', async dialog => {
  console.log(dialog.message());
  await dialog.accept(); // Or dialog.dismiss()
});
await page.click('#show-alert-button');

We hope this Playwright TypeScript Cheat Sheet becomes an indispensable tool in your automation journey. Keep it handy and happy testing!

Permalink
May 29, 2025

Mastering Double Clicks in Playwright with TypeScript

Learn how to master the double mouse click

In web automation, simulating user interactions accurately is key. One common interaction is the double click, often used to open files, edit text, or trigger specific UI behaviors. Playwright, a robust automation library, provides straightforward methods to perform such actions. This post will guide you through simulating a double click using Playwright with TypeScript.

Performing a Double Click with Playwright

Playwright offers a dedicated method, dblclick(), on its Page and Locator objects, making double clicking a breeze. You can target an element using a CSS selector, XPath, or Playwright's built in text/role locators.

Example 1: Double Clicking by CSS Selector

Let us consider a scenario where you want to double click a button with the ID myDoubleClickButton.


import { test, expect } from '@playwright/test';
test('should perform a double click on a button', async ({ page }) => {
    // Navigate to a page where your button exists
    await page.goto('https://example.com/double-click-page');
    // Double click the element using its CSS selector
    await page.dblclick('#myDoubleClickButton');
    // Optionally, add an assertion to verify the double click's effect
    // For instance, check if a new element appeared or text changed
    await expect(page.locator('#doubleClickResult')).toHaveText('Button was double clicked!');
});

Example 2: Double Clicking a Text Element

Sometimes you might need to double click on a piece of text. Playwright's text locator is very convenient for this.


import { test, expect } from '@playwright/test';
test('should double click on specific text', async ({ page }) => {
    await page.goto('https://example.com/text-selection-page');
    // Double click on the text "Editable Content"
    await page.getByText('Editable Content').dblclick();
    // Verify that the element is now in an editable state or shows a specific behavior
    await expect(page.locator('.editable-field')).toHaveAttribute('contenteditable', 'true');
});

Example 3: Controlling the Click Options

The dblclick() method also accepts an options object, allowing you to fine tune the behavior. For example, you can specify a delay between clicks, force the action, or click at a specific position within the element.


import { test, expect } from '@playwright/test';
test('should double click with specific options', async ({ page }) => {
    await page.goto('https://example.com/advanced-click-page');
    await page.locator('.custom-element').dblclick({
        delay: 500, // Wait 500ms between the two clicks
        position: { x: 10, y: 10 } // Click at coordinates 10,10 relative to the element
    });
    await expect(page.locator('#statusMessage')).toHaveText('Custom double click performed');
});

Common options for dblclick() include:

  • delay: Time in milliseconds to wait between the two clicks.
  • button: The mouse button to use ('left', 'right', 'middle'). Default is 'left'.
  • modifiers: An array of modifier keys to press ('Alt', 'Control', 'Meta', 'Shift').
  • position: A `{ x, y }` object to click at a specific point relative to the top-left corner of the element.
  • force: Forces the action, even if the element is not considered actionable (e.g., it is hidden).

Permalink
May 22, 2025

Popular Assertions in Playwright with TypeScript

Top 5 Assertions That People Use

A guide to the most commonly used assertions in Playwright for robust test automation with TypeScript.

Playwright's expect function offers a variety of assertions to validate webpage elements, states, and behaviors. Below are the most popular ones, with TypeScript examples.

1. toBeVisible

Verifies that an element is visible on the webpage. This is useful for checking if UI components render correctly.

import { test, expect } from '@playwright/test';
test('should display header', async ({ page }) => {
  await page.goto('https://example.com');
  const header = page.locator('h1');
  await expect(header).toBeVisible();
});

This test navigates to a webpage and checks if an h1 element is visible.

2. toHaveText

Asserts that an element contains the specified text. It can match exact text or a regular expression.

test('should have correct button text', async ({ page }) => {
  await page.goto('https://example.com');
  const button = page.locator('button#submit');
  await expect(button).toHaveText('Submit');
});

Use this to verify text content in buttons, labels, or other elements.

3. toHaveAttribute

Checks if an element has a specific attribute with an expected value, such as class, id, or custom attributes.

test('should have disabled attribute', async ({ page }) => {
  await page.goto('https://example.com');
  const input = page.locator('input#username');
  await expect(input).toHaveAttribute('disabled', '');
});

This is ideal for testing element states like disabled or checked inputs.

4. toBeEnabled / toBeDisabled

Verifies whether an element is enabled or disabled, commonly used for form controls.

test('should have enabled submit button', async ({ page }) => {
  await page.goto('https://example.com');
  const button = page.locator('button#submit');
  await expect(button).toBeEnabled();
});

Use toBeDisabled for the opposite case.

5. toHaveValue

Asserts that an input element (e.g., input, textarea) has a specific value.

test('should have input value', async ({ page }) => {
  await page.goto('https://example.com');
  const input = page.locator('input#username');
  await input.fill('testuser');
  await expect(input).toHaveValue('testuser');
});

Permalink
May 15, 2025

Filtering Locators by Text Content in Playwright with TypeScript

How I used Playwright's locator filtering to extract data

Introduction

Automating web testing often involves interacting with elements that lack unique identifiers like IDs or classes. In such cases, Playwright's powerful locator filtering capabilities can save the day. In this post, we'll explore how to filter locators by text content in TypeScript, using a real-world example from the American Freight Refrigerators & Freezers page.

Our goal is to capture the number of items displayed on the page, where the text (e.g., "Showing 24 results") is not tied to a unique ID. We'll use Playwright's text-based filtering and parse the result to extract the number.

The Challenge

On the American Freight page, the text indicating the number of results is displayed dynamically, something like:

Showing 24 results

The element containing this text doesn't have a unique ID or class, making it tricky to locate directly. A naive approach might grab multiple elements with similar text, leading to incorrect results. Playwright's locator filtering allows us to narrow down the search by combining text matching with additional conditions.

Refrigerators
Screenshot of the page that I am testing.

Solution: Playwright Locator Filtering

Playwright provides the getByText method to locate elements by their text content. We can further refine this using the filter method to ensure we target the exact element. Here's how it works:

  1. Use page.getByText('Showing', { exact: false }) to find elements containing the word "Showing".
  2. Apply filter({ hasText: 'results' }) to narrow down to elements that also contain "results".
  3. Extract the text content and parse it to get the number using a regular expression.

Below is the complete TypeScript code for the test:

import { test, expect } from '@playwright/test';
test('American Freight Refrigerator Numbers', async ({ page }) => {
  await page.goto('https://www.americanfreight.com/plp/appliances/refrigerators-freezers/695');
  // Locate element with text starting with "Showing" and containing "results"
  const locator = page.getByText('Showing', { exact: false });
  const element = locator.filter({ hasText: 'results' });
  const text = await element.innerText();   
  const match = text.match(/Showing (d+) results/);
  const resultsNumber = match ? match[1] : null;
  
  console.log(`Number of results: ${resultsNumber}`);
  expect(resultsNumber).not.toBeNull();
});

Code Breakdown

Let's dissect the key parts of the code:

  • Navigating to the Page: await page.goto(...) loads the American Freight page.
  • Locating by Text: page.getByText('Showing', { exact: false }) finds all elements containing "Showing". The exact: false option allows partial matches.
  • Filtering: locator.filter({ hasText: 'results' }) refines the locator to only include elements that also contain "results".
  • Extracting Text: await element.innerText() retrieves the full text content (e.g., "Showing 24 results").
  • Parsing the Number: The regex /Showing (d+) results/ captures the number between "Showing" and "results". The result is stored in resultsNumber.

Why Use Locator Filtering?

Locator filtering is a game-changer for several reasons:

  • Precision: It allows you to target elements based on multiple conditions, reducing false positives.
  • Flexibility: You can combine text, attributes, or even child elements in the filter.
  • Robustness: It handles dynamic content where IDs or classes may change.

In our example, filtering ensured we got the exact element with "Showing" and "results", avoiding other elements with similar text.

Tips for Success

  • Inspect the Page: Use browser DevTools to confirm the text content and structure before writing your locator.
  • Test Your Locator: Use Playwright's locator.count() or locator.all() to verify how many elements match your criteria.
  • Handle Edge Cases: Add checks for null or unexpected text formats, as we did with the regex match.
  • Debugging: Log the innerText or use Playwright's tracing to inspect the locator's behavior.

Conclusion

Playwright's locator filtering by text content is a powerful tool for tackling elements without unique identifiers. By combining getByText and filter, we successfully extracted the number of refrigerators from the American Freight page. This approach is versatile and can be adapted to many scenarios in web automation.

Try it out in your next Playwright project, and explore other filtering options like has or hasNotText to handle even more complex cases!

Permalink
May 8, 2025

Validating Todays Date with Playwright and TypeScript

Learn how to use Playwright with TypeScript to check if today's date is displayed on a web page.

In this tutorial, we'll create a Playwright script in TypeScript to validate that today's date is present on a web page. This is useful for testing dynamic content, such as date displays in web applications.

Writing the Validation Script

We'll write a script to navigate to a web page, extract text from an element, and verify if it contains today's date. For this example, we'll assume the page displays the date in a format like "April 30, 2025" (you can adjust the format as needed).

Create a file named src/validate-date.ts with the following code:


import { chromium, Browser, Page } from 'playwright';
async function validateTodaysDate(): Promise {
    // Launch browser
    const browser: Browser = await chromium.launch();
    const page: Page = await browser.newPage();
    try {
        // Navigate to the page (replace with your target URL)
        await page.goto('https://example.com');
        // Get today's date in the format "April 30, 2025"
        const today: string = new Date().toLocaleDateString('en-US', {
            month: 'long',
            day: 'numeric',
            year: 'numeric'
        });
        // Locate the element containing the date (adjust selector as needed)
        const dateElement = await page.locator('h1'); // Example: 

April 30, 2025

const pageDate: string = await dateElement.textContent() || ''; // Validate the date if (pageDate.includes(today)) { console.log(`Success: Today's date "${today}" is displayed on the page.`); } else { console.error(`Failure: Expected "${today}", but found "${pageDate}".`); } } catch (error) { console.error(`Error: ${(error as Error).message}`); } finally { // Close browser await browser.close(); } } // Run the script validateTodaysDate();

This script:

  • Launches a Chromium browser using Playwright.
  • Formats today's date using toLocaleDateString to match the expected format.
  • Navigates to the target page and extracts text from a specified element (e.g., an h1 tag).
  • Checks if the element's text contains today's date.
  • Logs success or failure and handles errors.

Note: Replace https://example.com with your target URL and adjust the locator selector (e.g., 'h1') to match the element containing the date on your page.

Running the Script

Compile and run the TypeScript script using:


npx ts-node src/validate-date.ts
            

Example output if the date is found:


Success: Today's date "April 30, 2025" is displayed on the page.
            

If the date is not found or an error occurs, you'll see an appropriate error message.

Conclusion

Using Playwright with TypeScript, you can reliably validate dynamic content like today's date on a web page. TypeScript's type safety helps catch errors early, while Playwright's powerful APIs simplify browser automation. Customize the selector and date formats to fit your use case, and consider integrating with Playwright's test framework for robust testing.

For further exploration, try adding visual regression testing or combining with CI/CD pipelines to automate date validation in your workflows.

Permalink
May 1, 2025

Measuring Page Load Time with Playwright

Learn how to use Playwright to measure how long it takes for a web page to load.

One of its many capabilities PlayWright is measuring page performance metrics, such as load times. In this tutorial, we'll walk through how to use Playwright to record the time it takes for a page to fully load.

Writing the Script

Create a file named measure-load-time.js and add the following code to measure the page load time for a website (e.g., example.com):


const { chromium } = require('playwright');
(async () => {
    // Launch browser
    const browser = await chromium.launch();
    const page = await browser.newPage();
    // Record start time
    const startTime = performance.now();
    // Navigate to the page
    await page.goto('https://example.com');
    // Wait for the page to fully load
    await page.waitForLoadState('load');
    // Record end time
    const endTime = performance.now();
    // Calculate load time
    const loadTime = endTime - startTime;
    console.log(`Page load time: ${loadTime.toFixed(2)} ms`);
    // Close browser
    await browser.close();
})();
            

This script:

  • Launches a Chromium browser using Playwright.
  • Records the start time using performance.now().
  • Navigates to the specified URL.
  • Waits for the load event, indicating the page is fully loaded.
  • Calculates the load time by subtracting the start time from the end time.
  • Outputs the result in milliseconds.

Running the Script

Run the script using Node.js:


node measure-load-time.js
            

You should see output similar to:


Page load time: 1234.56 ms
            

The actual time will vary depending on the website, network conditions, and system performance.

Permalink
April 24, 2025

Speed Up Your Tests with storageState()

Little Known Tip to Get Your Test Running Faster

Tired of logging in before every test? Playwright’s storageState() lets you save your login state and reuse it across multiple tests - boosting performance and reliability.

Quick Tip: Reusing browser context cuts down execution time and enhances CI/CD pipeline efficiency.

Why storageState() Matters

Every time your test logs in, you're spending time and creating potential points of failure. Also it adds additional overhead on your tests - that may impact the overall test time. Instead, you can log in once, save the state (cookies + local storage), and load that state in future tests.

Step 1: Save the Auth State

Create a setup script that logs in and saves the storage state.

// setup-auth.ts
import { chromium } from '@playwright/test';
(async () => {
  const browser = await chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto('https://example.com/login');
  await page.fill('#username', 'your-username');
  await page.fill('#password', 'your-password');
  await page.click('button[type="submit"]');
  // Wait for redirect or element that confirms login
  await page.waitForSelector('#dashboard');
  // Save storage state to file
  await context.storageState({ path: 'auth.json' });
  await browser.close();
})();

Step 2: Reuse the Auth State

In your test file, load the previously saved auth.json file to reuse the session.

// example.spec.ts
import { test, expect } from '@playwright/test';
test.use({
  storageState: 'auth.json'
});
test('Dashboard loads for authenticated user', async ({ page }) => {
  await page.goto('https://example.com/dashboard');
  await expect(page.locator('#dashboard')).toBeVisible();
});

When Should You Use This?

  • Tests that require an authenticated user
  • Reducing login redundancy in CI/CD pipelines
  • Speeding up test suites with shared session state
Pro Tip: You can use different storage files for different roles or test scenarios.

Start using storageState() today and take the fast lane through your E2E tests!

Permalink
April 17, 2025

Modern Number Formatting

From Perl to Playwright

The Old Way: Perl's Commify Function

In the days of Perl, developers often wrote custom functions to format numbers with commas for readability. Here's an example of a Perl function called commify that added commas to numbers:


sub commify {
    local($_) = shift;
    1 while s/^(-?d+)(d{3})/$1,$2/;
    return $_;
}

                

This function:

  • Takes a number as input.
  • Uses a regular expression to insert commas every three digits from the right.
  • Handles negative numbers with the -? pattern.
  • Returns the formatted string (e.g., 1234567 becomes 1,234,567).

While effective, this approach is verbose and relies on regex, which can be error-prone and hard to maintain.

The Modern Way: Playwright with TypeScript

Today, when working with modern web automation tools like Playwright and TypeScript, you can achieve the same result using JavaScript's built-in toLocaleString() method. This method is simpler, more readable, and supports internationalization out of the box.

Here's how you can format numbers in a Playwright test with TypeScript:


import { test, expect } from '@playwright/test';
test('Format number with commas', async ({ page }) => {
    await page.goto('https://example.com');
    const number = 1234567;
    const formattedNumber = number.toLocaleString('en-US'); // Outputs: "1,234,567"
    // Example: Set the formatted number in an input field
    await page.locator('#number-input').fill(formattedNumber);
    // Verify the value
    const inputValue = await page.locator('#number-input').inputValue();
    expect(inputValue).toBe('1,234,567');
});

In this example:

  • toLocaleString('en-US') formats the number with commas according to the US locale (e.g., 1234567 becomes 1,234,567).
  • The formatted number is used in a Playwright test to fill an input field and verify its value.
  • No custom regex or loops are needed, making the code cleaner and less prone to errors.

Why toLocaleString() is Better

Using toLocaleString() over the Perl commify function offers several advantages:

  • Simplicity: No need for complex regex or manual string manipulation.
  • Internationalization: Supports different locales (e.g., de-DE for German formatting with periods: 1.234.567).
  • Built-in: Native to JavaScript, so no custom code is required.
  • Type Safety: When used in TypeScript, you get type checking for numbers and locale strings.

For example, to format a number for a German audience:


const number = 1234567;
const formattedNumber = number.toLocaleString('de-DE'); // Outputs: "1.234.567"

                

Using toLocaleString() in Playwright

In a real-world Playwright scenario, you might need to format numbers when testing forms, displaying data, or verifying UI elements. Here's a more complete example:


import { test, expect } from '@playwright/test';
test('Test number formatting in a form', async ({ page }) => {
    await page.goto('https://example.com/form');
    const rawNumber = 9876543.21;
    const formattedNumber = rawNumber.toLocaleString('en-US', {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2
    }); // Outputs: "9,876,543.21"
    // Fill a form input with the formatted number
    await page.locator('#price-input').fill(formattedNumber);
    // Submit the form
    await page.locator('#submit-btn').click();
    // Verify the displayed result
    const displayText = await page.locator('#price-display').textContent();
    expect(displayText).toContain('9,876,543.21');
});

This test formats a number with two decimal places, fills a form, submits it, and verifies the result in the UI.

Conclusion

The transition from Perl's commify to JavaScript's toLocaleString() in a Playwright and TypeScript environment showcases how modern web development simplifies tasks that once required custom solutions. With toLocaleString(), you get a robust, maintainable, and internationally aware solution for number formatting, perfectly suited for browser automation with Playwright.

So, next time you're formatting numbers in your Playwright tests, skip the regex and reach for toLocaleString() - your code will thank you!

Permalink

About

Welcome to Playwright Tips and Tricks, your go-to resource for mastering the art of web automation and testing with Playwright! Whether you're a seasoned developer looking to streamline your workflows or a curious beginner eager to dive into the world of browser automation, this blog is designed with you in mind. Here, I'll share a treasure trove of practical insights, clever hacks, and step-by-step guides to help you harness the full power of Playwright - a modern, open-source tool that's revolutionizing how we interact with web applications.

Check out all the blog posts.

Blog Schedule

Sunday 22 Misc
Monday 23 Media
Tuesday 24 QA
Wednesday 25 Pytest
Thursday 26 PlayWright
Friday 27 Macintosh
Saturday 28 Internet Tools