
Kick off the course with a quick map of what Section 1 covers and where you'll end up. This short text lecture previews the section: setting up your environment (Node.js, Playwright, VS Code, and the official Microsoft extension), creating your first project and running the example tests, touring the Playwright toolkit, understanding the config file and base URL, and debugging visually with UI Mode and the VS Code extension. No prior Playwright experience is needed — if you can install Node.js and open VS Code, you're ready to start.
Set up a complete Playwright test development environment from scratch. You'll install the Node.js LTS release, add Playwright through npm, and set up Visual Studio Code as your IDE. You'll also install the official Microsoft "Playwright Test for VS Code" extension — and learn how to avoid the lookalike extensions you shouldn't install. By the end you'll verify Node.js with node -v and be ready to write your first test.
Scaffold a brand-new Playwright project inside VS Code. You'll open a project folder, launch the integrated terminal, and run npm init playwright@latest — choosing TypeScript, a tests folder, and a GitHub Actions workflow along the way. Then you'll run the bundled example tests with npx playwright test to confirm everything is wired up correctly and your setup actually works.
Learn how to run your Playwright tests, and how to view HTML reports. This video shows how to perform important Microsoft Playwright operations through the command line (CLI) in its most basic form.
Understand what you really get when you install Playwright — it's a full testing toolkit, not just a browser library. This lecture tours the five pieces that ship out of the box: the Playwright library and its page object, the Playwright Test runner (with test, expect, fixtures, parallel runs, and reporting), the bundled Chromium/Firefox/WebKit browsers, the Codegen test generator, and the Trace Viewer for debugging. You'll leave knowing exactly which tool does what.
Take control of how your tests run through playwright.config.ts. You'll set a baseURL so tests use short paths instead of full URLs, use the projects array to choose which browsers execute, and pick browsers from the command line with --project. You'll also run tests in a visible browser with --headed, filter tests using --grep, and turn on the Trace Viewer to step through execution — the core configuration skills every Playwright project needs.
Run and debug your tests in a rich graphical dashboard instead of reading terminal logs. Launch UI Mode with npx playwright test --ui and explore the timeline view with per-step snapshots, plus the Actions, Source, Errors, Logs, Console, and Network tabs. You'll also use watch mode so tests re-run automatically as you edit — turning UI Mode into an all-in-one hub for running, exploring, and debugging tests.
Work with Playwright like a testing IDE using the VS Code Test Explorer. You'll run tests with one click from the file, test, or project level, filter through large test suites, and debug directly in the editor with each executing line highlighted in real time. You'll enable a second browser project (Firefox) to see multi-browser runs, watch tests live with the "show browser" option, and open the Trace Viewer to inspect results after a run.
Get oriented before you start writing tests. This short text lecture previews Section 2 — the mechanical core of the course. You'll see the roadmap: understanding the anatomy of a Playwright test file, finding elements reliably with locators and getByRole, speeding things up with the Pick Locator tool, performing real interactions like clicking links and filling forms, narrowing searches by chaining locators, and reading data back off the page (visible text, input values, HTML attributes, and whole columns). By the end of the section you'll be able to locate anything on a page, act on it, and read whatever you need back.
Understand what a Playwright test is actually made of before you write your own. You'll learn where tests live (the tests folder), why every test file ends in .spec.ts (or .spec.js), and what the import { test, expect } from '@playwright/test' line brings in. You'll see that every test is built from two things — actions and expectations — and how that maps to the classic Arrange-Act-Assert (AAA) pattern. By the end you'll recognize the skeleton that every Playwright test shares.
Take the example test Playwright generated and understand every line of it. You'll break down the has title test piece by piece: the test name, why the function is async, the arrow function that holds the test body, and the all-important page object — your browser tab, giving you page.goto, page.click, and page.fill. You'll learn why asynchronous actions need await, how the expect assertion verifies the page title, and how the regex-based match works. Once you see this actions-then-assertions pattern, you can read (and write) any Playwright test.
Locate and interact with elements the reliable way. Using the Get Started Link test, you'll meet the getByRole locator — finding a link by its accessibility role and name, then clicking it, with Playwright's built-in auto-wait and auto-retry handling timing for you. You'll learn why role-based locators (link, button, heading, textbox, checkbox) produce more stable, readable tests than brittle CSS or XPath selectors, how the name parameter differs from the HTML name attribute, and how to confirm it all in the Trace Viewer.
Learn to read an element's accessibility information straight from your browser. You'll open Chrome DevTools, inspect an element, and find the Accessibility pane — where the role (heading, textbox, button) and its details are shown. You'll connect this directly to the first parameter of getByRole, so you always know what role to target, and you'll see how it's all grounded in the WAI-ARIA W3C accessibility standard. A short, practical lecture that makes locator-building far less guesswork.
Stop hand-writing selectors. In Part 1 you'll meet the Pick Locator tool inside the VS Code Playwright extension — the "pickaxe" for grabbing locators. You'll open it against the demo site, hover over elements to see Playwright's recommended locator in a tooltip, and use the "Copy on Pick" option to copy a ready-made locator straight into your script. By the end you'll be able to produce a solid locator for any element in seconds.
Put the Pick Locator tool to work in a complete, passing test. You'll create a new test that opens the demo site, clicks the Community link using a picked locator, and verifies the resulting page with an expect(...).toBeVisible() assertion. Along the way you'll pick the main heading, add the assertion, and catch a common beginner mistake — forgetting the page. prefix when pasting a locator. A hands-on, end-to-end follow-up to Part 1.
Learn to type into fields and drive a real login flow. You'll build login.spec.ts from an empty file — importing test and expect, adding the test skeleton, then using the fill() method to enter the email and password (picked with the Pick Locator tool) and clicking Sign In. You'll rely on role-based locators and Playwright's auto-waits (no manual sleeps), then use the Record tool's Assert Text feature — powered by Codegen — to verify the dashboard's welcome message. The full course code is in the GitHub repo linked from the videos.
Reach elements that are hard to pin down. You'll learn locator chaining — calling a locator method on an existing locator instead of on page — to drill from a parent element down to a specific child. Using a purpose-built "confusing" demo page with three identical Hello World buttons, you'll see how the Pick Locator tool suggests a chained getByLabel(...).getByRole(...) locator, how to inspect the parent div in the Accessibility pane, and when chaining is the right tool for sections, modals, and table rows that share similar locators.
Start pulling data back off the page. Sometimes asserting isn't enough — you need to read a value to reuse or log it. This lecture contrasts the two text-reading methods: innerText, which returns only what the user actually sees, and textContent, which grabs the raw text even when CSS hides it. Working on the dashboard's statistics cards and welcome message with getByLabel and getByText, you'll read values into variables and print them with console.log, seeing exactly how the two methods differ.
Read the value out of a form input — the right way. You'll learn why innerText fails on inputs (their text lives in the value property, not between tags) and use the inputValue() method instead. Working with the QA form in the demo app, you'll read the "lucky number" field via getByLabel, store it in a constant, and print it. A short, targeted lecture that fills a gap students hit as soon as they test real forms.
Read a whole list of values at once instead of one at a time. Targeting the "recent login attempts" table, you'll chain row and cell locators to select every email cell, then call allInnerTexts() to pull them all into a single list — printing the count and the full set of values. You'll see how easily the same result could be saved to a CSV file or database, making this the go-to pattern for scraping columns and lists from any page.
Read data that lives in HTML attributes — the "dark matter" of the DOM where apps often stash state and metadata. You'll use getAttribute() to read a custom user-type attribute from the dashboard's user menu (normie for standard users, admin for admins). You'll also get a first taste of data-driven testing: a TypeScript interface and an array of credential objects drive the same login test for different users, asserting the attribute matches each expected value. A deeper dive into data-driven testing comes later in the course.
Here's a short plain-text version — no HTML, just paste it in:
Download your Section 2 cheat sheet: a one-page reference for every Playwright locator, action, and reading-data method from this section — getByRole, getByLabel, getByText, chaining, click, fill, innerText vs textContent, inputValue, getAttribute, and allInnerTexts, plus common ARIA roles and quick links to the Pick Locator tool, Trace Viewer, and Codegen. Keep it handy while you write your own tests — no need to memorize anything. Grab the PDF from this lecture's Resources.
Want an even shorter one-liner too? Something like: "Your one-page Playwright quick reference for Section 2 — locators, actions, and reading data. Download the PDF from this lecture's Resources."
Get oriented before you start asserting. This short text lecture previews Section 3 — the section that turns your scripts into real tests. So far you can drive a browser and read data, but clicking and typing is only half the job; without assertions, a script just performs actions and hopes for the best. You'll see the roadmap: the anatomy of an assertion (the expect call and its matcher), negative assertions with the .not modifier, the two families of assertions (auto-retrying vs non-retrying) and why auto-retrying ones fight flakiness, and the choice between hard and soft assertions. By the end of the section you'll know not just how to assert, but which assertion to reach for in each situation.
Understand what an assertion actually is — and why a script without one isn't really a test. You'll learn that every Playwright assertion has two parts: the expect call, which takes a locator or the page object, and the matcher, which is the rule you're enforcing (toHaveURL, toContainText, toBeVisible, and more). Using a login flow, you'll assert that the URL contains "dashboard" and that a welcome message appears — proving the app met your expectations instead of just hoping it did.
Learn to assert that something is absent, not just present. Sometimes success means an element is gone — a log-out flash message that shouldn't appear on first load, or a loading spinner that should have vanished. You'll use Playwright's .not modifier, placed between the expect call and the matcher, to write clean, readable negative assertions — and you'll see a real test that confirms a message is not displayed to a brand-new visitor.
Stop fighting flaky tests. Modern pages are dynamic — elements don't always appear the instant a page loads — which is what made older tools so unreliable. You'll learn Playwright's two assertion families: auto-retrying matchers (toBeVisible, toHaveText) that poll the UI for up to five seconds and must always be awaited, and non-retrying matchers (toBe, toEqual) that check exactly once, ideal for data validation like a math result or an API status code. You'll leave knowing the golden rule: prefer auto-retrying matchers for anything on the UI.
<h3>Section 3 Assertions Cheat Sheet</h3>
<p>Everything you learned about assertions in this section, on one page. Download the attached PDF, <strong>Section 3 - Playwright Assertions Cheat Sheet</strong>, and keep it handy while you write your own tests.</p>
<p><strong>What's inside:</strong></p>
<ul>
<li>Anatomy of an assertion — <code>expect(locator | page)</code> + a matcher (the rule you enforce).</li>
<li>Web-first matchers (auto-retrying) — <code>toBeVisible</code>, <code>toHaveText</code>, <code>toContainText</code>, <code>toHaveValue</code>, <code>toBeChecked</code>, <code>toHaveCount</code>, <code>toHaveTitle</code>, <code>toHaveURL</code>.</li>
<li>Generic matchers (non-retrying, for data) — <code>toBe</code>, <code>toEqual</code>, <code>toBeTruthy</code>.</li>
<li>Modifiers — <code>.not</code> for negative assertions and <code>.soft</code> for soft assertions.</li>
<li>Auto-retrying vs non-retrying — which type to use, and why auto-retrying beats flaky tests.</li>
<li>Hard vs soft strategy — when a failure should stop the test, and when it shouldn't.</li>
</ul>
<p>You don't need to memorize any of this. When you forget which matcher to reach for, or whether an assertion needs <code>await</code>, just glance at the sheet. Look for the PDF in this lecture's <strong>Resources</strong>.</p>
Basic clicks and text input will only take you so far. Real applications are full of trickier controls — checkboxes with hidden states, custom dropdowns, and drag-and-drop widgets — that break naive automation. This section shows you how to handle those elements cleanly and reliably in Playwright.
What you’ll learn in this section
Handle checkboxes and radio buttons correctly, including the tricky indeterminate ("third state") checkbox.
Deal with elements that require scrolling before they can be used, like scroll-to-agree terms.
Work with the Shadow DOM, which Playwright can see into automatically.
Automate every kind of list and dropdown: standard select lists, multi-select boxes, searchable dropdowns, and custom list views.
Tackle drag and drop — one of the classic headaches of UI automation.
By the end, the web elements that trip up most automation engineers will be routine for you.
Handle checkboxes the right way — without the bug that click() invites. You'll learn why clicking a checkbox is risky (it toggles from the current state, so a changed default silently flips your test) and how Playwright's dedicated check() and uncheck() methods guarantee the final state instead. They run actionability checks — waiting for the element to be visible and enabled — and do nothing if the box is already in the target state. You'll finish by verifying results with the toBeChecked assertion, using .not to confirm the boxes that should stay unchecked.
Automate radio-button groups and prove the right option is selected. Radio buttons follow the same logic as checkboxes with one twist: buttons in a group share a name, so selecting one automatically clears the others — behavior Playwright handles cleanly. You'll select a radio with getByLabel, confirm the others are unchecked with toBeChecked and .not, and learn a handy one-off CSS-selector trick ([name=plan]:checked) for grabbing the selected member of a group.
Master the trickiest checkbox of all — the indeterminate state. When a "Select all" parent has only some of its children checked, it shows a dash: a third state that's neither checked nor unchecked. The catch is that indeterminate is a DOM property, not an HTML attribute, so an attribute-based locator will fail. You'll confirm the behavior in DevTools, then read the state reliably in your test with the auto-retrying toHaveJSProperty('indeterminate', true) assertion — the stable way to verify a property that only lives in the browser's memory.
Beat the "scroll to the bottom before you can agree" trap. Many sites keep the terms-and-conditions checkbox disabled until the user scrolls a text container all the way down — so calling check() too early just times out. You'll use scrollIntoViewIfNeeded on a bottom element (like the "end of terms" text) to fire the app's native scroll event and enable the checkbox, then check it. You'll also see why the "if needed" part keeps tests fast by skipping the scroll when the element is already visible.
Understand the Shadow DOM — and why it's a non-issue in Playwright. The Shadow DOM is a fenced-off mini-document that lets developers build components whose internal styles and markup can't leak out and clash with the rest of the page. Historically, that isolation blocked test tools unless you wrote awkward shadow-root code. Playwright's engine pierces the Shadow DOM by default, so you target enclosed elements exactly like any other. You'll inspect a real #shadow-root on the demo site to see the boundary for yourself.
Automate standard <select> dropdowns three different ways. You'll use Playwright's built-in selectOption to pick an option by its underlying value, by its visible label, or by its index — handy when an option has no value or text to match on. You'll step through the selection in the debugger, then add list assertions with toContainText, toHaveText, and toHaveValue, and tidy the view with scrollIntoViewIfNeeded so you can watch the control as the test runs.
Select several options at once — no Ctrl or Cmd key required. Where a manual tester holds a modifier key, Playwright just takes an array of strings in the same selectOption method you already know. You'll select multiple values in one call and verify them with toHaveValues (note the plural), and you'll learn the gotcha that bites people: the asserted values must be listed in the correct order, or the test fails. A direct, practical follow-on to standard dropdowns.
Tame custom, searchable, autocomplete-style dropdowns. Modern apps often fake a dropdown with a text input wired to a hidden datalist — so selectOption throws an error and you have to treat it like a text box, carefully. You'll use pressSequentially() to type the first few characters and trigger the autocomplete JavaScript (a bulk fill() can break it), finish the value with fill(), press Tab to commit the selection, and assert the input holds the value you expect.
Count and verify the items in a custom-built list. Using a "Recent Tasks" <ul>/<li> list made testable with data-test-id attributes, you'll see why getByRole is the right tool when you need to count or check a list's length. You'll retrieve every child with .all(), loop through the items to print them, and finish with an assertion on the item count — a reliable pattern for any unordered list on the page.
Conquer one of UI automation's classic headaches — in a single line. Under the hood, drag-and-drop fires a whole event sequence (drag start, enter, over, drop) that older frameworks had to simulate by hand. Playwright collapses all of it into dragTo(): locate the source with getByTestId, locate the target, and call source.dragTo(target). You'll then prove it worked — asserting the moved item is visible in the drop zone and that the page's dynamic count badges updated correctly.
Automate standard select dropdowns three different ways. You'll use Playwright's built-in selectOption to pick an option by its underlying value, by its visible label, or by its index — handy when an option has no value or text to match on. You'll step through the selection in the debugger, then add list assertions with toContainText, toHaveText, and toHaveValue, and tidy the view with scrollIntoViewIfNeeded so you can watch the control as the test runs.
Set the stage for the section where your tests grow up. Writing one or two tests is easy, but real projects run dozens or hundreds — and without structure they turn messy, repetitive, and hard to maintain. This short overview previews the toolkit you'll master: hooks like beforeEach to remove repeated steps, Playwright's built-in fixtures for setting up pages and sessions, data-driven testing so you don't rewrite the same test, and browser contexts for simulating multiple users or tabs at once. By the end of the section, you'll structure suites that stay readable and maintainable no matter how large they get — and debug and adjust AI-generated tests with confidence.
Organize a messy file into clean, named groups. You'll use test.describe to wrap related tests together — passing the group name as the first argument and a function holding the tests as the second. You'll run the whole group with the special double play button in VS Code, run a suite from the command line with the -g flag, and see how the suite name appears alongside each test in the HTML report. You'll also learn that a single spec file can hold multiple test.describe suites.
Stop copy-pasting the same opening steps into every test. When multiple tests repeat page.goto, logging in, and filling credentials, a beforeEach hook lets you write that code once and have Playwright run it automatically before every test in the block. You'll refactor shared login into a suite-level beforeEach (and see how an AI coding agent can do the move for you), understand the page argument the framework supplies to the hook, and follow the execution order: the hook runs first, then each test body.
Run shared setup without wrapping everything in a test.describe block. Declared at the top level of a file, a beforeEach hook treats the entire file as a suite and runs before every test in it — whether tests float at the root or sit nested inside describe blocks. You'll learn the execution order (file-level hook first, then any describe-level hooks) and the ideal use case: when a whole file targets one area of your app and every test needs the same unified starting state, a file-level hook keeps the code clean without forcing everything under one describe.
Give one shared hook different behavior per test. A blanket login beforeEach breaks the test that logs in on its own — so you'll add a testInfo parameter, which Playwright populates with details of the test about to run, and use it in an if condition to branch. In this lecture you'll skip the login step for a specific test by returning early from the hook based on that test's name, so the same beforeEach serves every test in the file without collisions.
Run the same test against many inputs without duplicating code. Instead of copy-pasting a test for each user, you'll iterate a data array with a JavaScript forEach loop and run one test body for every item. You'll call forEach on your credentials container, name the per-item parameter data, move the test body inside the loop, and swap the old single-item variable for data. The result is the double-play icon that signals multiple tests will run — one per row of your data.
Put costly setup in the right place so your suite stays fast. Logging in, fetching a token, or seeding data before every test adds up quickly. You'll learn how beforeAll runs just once per file, versus beforeEach which runs before each test — and the crucial gotcha that beforeAll has no access to the page fixture, because page is created fresh for every test. That makes beforeAll the home for work like generating an API token or authenticating without the UI, not for navigating a page.
Build an anti-fragile suite by cleaning up, not just setting up. Skipping teardown causes state leakage (test pollution) — the number-one cause of flaky tests that pass alone but fail in a full run. You'll use afterEach, which runs after every test whether it passed or failed, to reset state (like navigating to the logout URL), and learn that with hooks at both describe and file level, cleanup runs inside-out. You'll use testInfo to skip cleanup where it isn't needed, and reach for afterAll for heavy, once-per-file teardown like closing database connections — all in service of the golden rule: leave the environment exactly as you found it.
Finally understand where page comes from — you've used it all course without ever calling new. The answer is fixtures: Playwright's backstage crew that sets the stage for every test. You'll learn the built-in chain browser → context → page (the browser engine, a fresh incognito-style profile, and a tab), created fresh per test and torn down after. Then you'll take the browser fixture directly to create a new context and page with browser.newContext(), opening a second website in a second tab — the pattern for simulating multiple users or multiple tabs in one test.
Manage a suite that's grown from ten tests to thousands. You'll tag tests as metadata labels — grouping them into tiers like fast smoke checks for every commit and thorough regression runs before release — by passing a config object to the test, then filter which tests run. You'll use test.skip to skip tests during development, test.only to run a single test (including inside a describe block), and conditional annotations to skip a test based on browserName (the real case of unreliable drag-and-drop on WebKit). You'll also view tags in the Playwright UI and list tests by tag from the command line for CI scenarios.
A one-page (printable) companion covering everything you need to keep a growing test suite organized, isolated, and fast: the commands to run and filter tests (run a single spec, run a test.describe suite by name with -g, filter by tag with --grep, list tests by tag, open UI Mode, and disable parallelism with --workers=1); the four lifecycle hooks and exactly when each runs (beforeAll, beforeEach, afterEach, afterAll), including the nesting order and the beforeAll no-page-fixture gotcha; ready-to-use code patterns for test.describe grouping, a smart beforeEach that uses testInfo, and data-driven testing with a forEach loop; a tags and annotations reference (adding tags, test.skip, test.only, and conditional skips by browserName); and the built-in browser to context to page fixture chain with a multi-tab example. Includes tool links, quick fixes, and the golden rule of teardown. By Naeem Akram Malik, AI Builder and Lead SDET — demo.testautomationtv.com
A framing lecture with no code. It opens on a pain students recognize — the same three login locators copied across login, dashboard, and other spec files — then asks what happens when the label "Enter your email address" changes to "Email": multiple files break, and you hope you don't miss one. The one-sentence definition lands: a page object is a class that holds the locators and actions for a single page, giving every test a single source of truth (no frameworks, just a regular class). Leading with "Why" signals it's the motivating intro; "Kill Locator Duplication" names the exact payoff and carries the search keyword.
he hands-on begins. Students create a pages/ folder and a login-page.ts file, then build the LoginPage class: a constructor that takes and stores the page Playwright hands every test, locators declared once and initialized in the constructor, a goto() method, and the intent-named loginAs() method (named for what it does, not the button it clicks). They import the class into login.spec.ts, replace four lines with an instance, and the test reads like a sentence anyone can follow. Closes on the section's core rule — no expect() calls inside a page object. The title names the concrete artifact (LoginPage) students will build and search for.
One page object is just tidy code; two in one test is where the pattern pays off. Students add a DashboardPage class with the same shape (locators in the constructor, intent-named methods) whose methods return data rather than assert — reinforcing that assertions belong in the test. A single test then builds both page objects, logs in through LoginPage, and reads the dashboard greeting and recent emails through DashboardPage — zero raw getByRole calls in the spec. The title shows the composition (LoginPage → DashboardPage) that is the lecture's whole point.
Every dashboard test opened with two setup lines that have nothing to do with what's being tested. This lecture removes them with a custom fixture: a custom-fixtures.ts file extends Playwright's base test, declares an authPage fixture that navigates, fills credentials, and clicks sign-in before the use(page) handoff (setup before use, teardown after). Tests then just ask for authPage in their signature and arrive already logged in. The principle lands: fixtures handle setup, tests handle assertions. "Inject Page Objects with Custom Fixtures" names both the technique and the outcome.
Some UI isn't tied to one page — a navbar on every screen, a QA-form modal that opens from the nav. Modeling those as full page objects is wrong, so students build a component object: same pattern (constructor with page, locators up front, intent-named methods like open, setLuckyNumber, submit), just scoped to a slice of UI. The key insight — there's no special component class or syntax; a component object is just a page object that models less than a full page. Students then compose the QAFormModel into the DashboardPage and use it in a test, and see the navbar as the next natural candidate. The title names the recognizable targets (navbars, modals) and the reuse payoff.
Your complete Page Object Model reference for Section 6. This one-page printable sheet distils the whole pattern into what you'll actually reuse: the three core rules (locators in the constructor, intent-named methods, and never put assertions inside a page object), the anatomy of a page object class, and how to use and compose several page objects in a single test. It also covers injecting page objects through custom fixtures, building component objects for reusable UI like navbars and modals, and the six anti-patterns to avoid. Keep it beside you while you code so a UI change stays a one-file fix.
You already know how to drive a browser with Playwright. In this section you add one more powerful tool to that workflow: calling your application's API directly from inside your tests. There is nothing new to install — the request capability is already part of Playwright.
What you’ll learn in this section
Understand why calling APIs from your tests is so useful, especially for setting up test data quickly.
Make your first API call from a test and assert the response status.
Verify the structure and contents of a JSON response body.
Use AI (Claude) to read the API docs and generate an API test for you.
Set up test data through the API before the browser opens — and clean it up through the API when the test finishes.
By the end, you will be able to mix fast API calls with browser checks to write tests that are quicker and more reliable.
Understand the payoff before you write a line of API code. You'll see the problem: a UI-only test has to click through a form, navigate, submit, and wait just to put the app in the state it wants to check — and every one of those steps is a place the test can fail for reasons that have nothing to do with what you're testing.
The fix is one idea: call the API directly to create that state in a single request before the browser even opens, using Playwright's built-in request fixture — no new installs, no new libraries. You'll also meet the demo site's live /api/docs and the habit that saves you time all section: read the spec before you write the test.
Make a real API call from a test and prove the endpoint works. You'll create api.spec.ts, open the Guestbook GET endpoint in /api/docs to note its URL, response shape, and 200 status, and try it live before writing anything. Then you'll declare the request fixture in your test arguments — Playwright provides it automatically, exactly like the page fixture, with no imports or configuration — make the GET call, and assert response.ok() with toBeTruthy(). The result: a working API call inside a Playwright test in one line, one assertion, and no browser opened.
Go beyond "is it reachable?" and check what actually came back. A status check confirms the endpoint responds; a body assertion confirms the payload. You'll call response.json() to parse the body into a plain JavaScript object, then assert its properties like anything else in Playwright — that the response contains entries and total, and that entries is an array. You'll also learn a subtlety that trips people up: these are synchronous data assertions, so you don't await these expect calls.
AI draft an API test for you — then learn where it falls short. You'll hand Claude Code a prompt that tells it to find the base URL in playwright.config.ts, read the /api/guestbook GET docs, and write a schema-checking test in api.spec.ts — without writing the test yourself. It works on the first pass, but it misses an edge case (what if zero entries are returned?), so you'll guide it to handle the empty-array case and drop an assertion you don't want. The takeaway: AI is like a junior developer — it produces working code fast, but it still needs your review.
Use the API for setup and the browser for verification — in the same test. You'll create a separate guestbook.spec.ts (kept apart from the pure-API api.spec.ts) and declare both the request and page fixtures together. A POST call creates a guestbook entry and confirms the server accepted it with a 201; then the browser navigates to the guestbook page and asserts the message is actually visible to the user. Each fixture does only what it does best, so your tests run faster and flake less. You'll also save the created entry's ID from the response — you'll need it for cleanup next.
Make your test clean up after itself so it can run forever. Left alone, every run leaves another guestbook entry behind until text-matching tests start failing — so you'll complete the setup, verify, and cleanup arc. You'll capture the entry ID the POST returned and call request.delete() on the delete endpoint with that ID. Because that endpoint is protected, this is also where you meet HTTP Basic Auth: the request fixture carries no session state, so you attach credentials as an Authorization header built as "Basic " plus a Base64 username:password string via btoa(). A successful delete returns 200, and a custom expect message keeps failures readable in the report.
A one-page method and reference sheet for Section 7. It covers making API calls with Playwright's built-in request fixture (GET, POST, DELETE), asserting responses with response.ok(), response.status(), and response.json(), the setup-verify-cleanup pattern for hybrid API-plus-browser tests, and HTTP Basic Auth on the request fixture. Includes essential links, a quick copy-paste pattern, common quick fixes, and the key gotchas.
"Handling Complex Scenarios" accurately frames the section as the toolkit for the hard cases and reads cleanly in the sidebar. Its only weakness is that it's generic — it doesn't surface the specific, high-search keywords (iframes, dialogs, file upload/download, authentication) that a browsing student might scan for. If you want those in the title, the alternatives spell out the concrete topics. Recommendation: keep the current name for its clean arc, since the specific keywords already appear in the lecture titles below it; switch to an alternative only if you want the sidebar itself to advertise the topics.
Reach the elements that page.locator can't see. Real apps embed payment widgets, videos, and chat tools inside iframes — and an iframe has its own DOM, so a normal locator returns nothing for anything inside it. You'll see the boundary in DevTools (a nested html/body within the page), then fix it with one method: page.frameLocator('iframe') for a single frame, or a CSS selector like #payment-frame when there are several. From the frame, you'll find controls with the same techniques you already know, fill a card number, expiry, and CVV, click Pay, and assert the result — all inside the iframe.
Stop hardcoding test data. The iframe test used a fixed card number, expiry, and CVV — brittle and unrealistic. You'll install Faker (@faker-js/faker), generate those values dynamically, and pass them into your fill() calls (you'll even let Claude wire up the Faker calls for you). It's a small change with a big payoff, and the habit carries far beyond this one test: realistic, varied data instead of the same fixed values every run.
Stop native dialogs from freezing your test. JavaScript alert, confirm, and prompt are browser-level constructs that live outside the DOM — Playwright locators can't touch them, and an unhandled dialog hangs the page until it times out. The fix is the dialog event: you'll register a one-time listener with page.once('dialog', ...) that accepts the dialog, and learn the rule that matters most — register the handler before page.goto(), or Playwright auto-dismisses the dialog and your assertions fail for no clear reason. You'll also use dialog.type() to sanity-check the dialog, and see when to reach for page.on (recurring dialogs) versus page.once (a single expected one).
Handle the dialogs that branch. Unlike an alert (one outcome), confirm and prompt each have two, and your app shows different content depending on the choice. Using the same page.once pattern from the previous lecture, you'll handle a confirm dialog — asserting dialog.type() is 'confirm' and calling dialog.accept() — and a prompt dialog, where accept() can take a string value the app then displays. Only the assertion and the accept argument change; the mechanism stays the same.
Upload files without ever touching the OS file picker. The picker dialog belongs to the operating system, so Playwright can't see inside it — but you don't need to, because Playwright never opens it. You'll inspect the <input type="file"> element, then set the path directly with page.setInputFiles() (the locator or selector first, the file path second), click the upload button, and assert the success popup. No clicking Browse, no OS dialog — just set the path and go.
Test export and download links reliably. The key insight: a download is an event, not something you wait for afterward — so you listen first, then trigger. You'll wrap page.waitForEvent('download') and the click() that starts the download in a single Promise.all(), which prevents a fast download from firing before your listener is ready. Then you'll inspect the resulting download object — suggested filename, local path, readable stream — and assert on it; for most UI tests, confirming the filename is enough.
Keep a visual record of what the page looked like. You'll take a screenshot on demand with page.screenshot({ path, fullPage: true }) (Playwright creates any missing folders for you), capture a single element through a locator's .screenshot(), and — the most useful move — configure automatic screenshots in playwright.config.ts with screenshot: 'only-on-failure', so a failing test attaches an image to the HTML report with no per-test code. You'll also see the mode options: off, on, only-on-failure, and on-first-failure.
Get past the browser's login pop-up. Some pages don't use an HTML form — the browser itself shows a username/password dialog using HTTP Basic Auth (the same standard you met on the API in Section 7). It appears before the page loads and, like a JavaScript dialog, can't be reached with a locator or page.fill. The fix: supply httpCredentials when you create the browser context. You'll use the browser fixture (not page), create a context with credentials, and every page opened from it authenticates automatically at the network level — and you'll see how multiple isolated contexts enable access-control tests.
Log in once and reuse the session everywhere. Running the full login flow in every test wastes seconds that add up to minutes across a suite — on a step you're not even testing. With Playwright's Storage State, you'll write a login test that saves the session (cookies, local and session storage) to auth.json, then apply that file so other tests start already authenticated — via storageState in playwright.config.ts — and mark the login file itself to start from a clean state. The result: faster tests with the login step written exactly once. (This is also the course's closing lecture — thanks for following along, and please leave a rating.)
Everything from Section 8's complex scenarios, condensed onto a one-page reference sheet. Download the attached PDF and keep it beside you as you write your own tests. It covers reaching content inside iframes with frameLocator and generating realistic data with Faker, handling native alert/confirm/prompt dialogs with the dialog event, automating file uploads with setInputFiles and downloads with Promise.all, capturing screenshots (including only-on-failure), and handling browser Basic Auth and storage state to skip repeated logins — plus the key gotchas and links. No need to memorize any of it; just glance at the sheet whenever you need a reminder.
See the payoff first, then the theory. In two steps — neither of which is writing a test — you'll drive a real browser with AI. First, one terminal command registers the Playwright MCP with Claude Code: claude mcp add playwright -- npx @playwright/mcp@latest. Then a plain-English prompt ("open the products page, search for a product, add it to the cart, and tell me the total — use Playwright MCP") does the work. You'll learn what MCP (Model Context Protocol) is — the open bridge between an AI assistant and a live browser — that it works with other AI tools too, and that Playwright MCP reads the page's accessibility tree (roles and labels, like getByRole), not pixels. One honest note: MCP is great for discovery but isn't a replacement for your regression suite, and a fresh registration often needs a new session to appear.
Turn a personal setup into a shared one. The MCP you added in the last lecture was local — private to you, stored in your .claude.json, invisible to teammates, and not travelling with the repo. Here you'll make it official: run claude mcp list to confirm it's connected, check that its scope is local, then re-add it with claude mcp add --scope project. That one flag writes a committed .mcp.json at the project root, so when you push it, the whole team inherits the setup and nobody repeats the lecture-one command. You'll also see the one-time security approval Claude Code asks before it trusts a project-scoped server.
Cross the line from exploration to real testing. Exploration that vanishes when you close the chat isn't testing — so in this lecture you'll describe a flow in plain English ("add a wireless keyboard and an ergonomic mouse to the cart and verify the total updates — use Playwright MCP"), let the assistant explore it live in a real browser, then tell Claude Code to save it as tests/cart.spec.ts. The generated file is ordinary Playwright with getByRole selectors chosen automatically — no strange AI style — so it runs with npx playwright test and you maintain it like any other test. The key lesson: the value isn't the conversation, it's the durable spec file in your repo that gets reviewed and guards the flow on every commit.
Let Playwright's agents plan and build a suite for you. So far you've driven the MCP by hand; now you'll scaffold the three agents Playwright ships — planner, generator, and healer — with npx playwright init-agents --loop=claude (the --loop flag points them at the coding agent you already use). Then the planner turns one sentence ("explore the cart flow… save the plan to specs/cart-plan.md") into a Markdown test plan covering scenarios you'd miss on your own — empty cart, per-order limits, sold-out products. The generator turns that plan into around ten runnable spec.ts files, verifying each step against the live page. The rule that stays: always run and review what the agents produce.
Meet the agent that fixes broken tests. You'll run a set of tests and watch several fail — then, instead of debugging by hand, you'll be introduced to Playwright's own healer agent, which repairs broken tests for you. You'll also learn that healing is available in GitHub Actions, officially provided by Claude, so it can run in your CI/CD pipeline. This short lecture sets up the two hands-on healer lectures that follow — first locally, then unattended in CI.
Heal a broken test with a single prompt. Starting from the red tests in the previous lecture, you'll open Claude Code and prompt the Playwright healer agent to run on a failing test, grant it the Playwright MCP permissions it requests, and watch it modify the file. The healer explains what it changed and why — here, replacing an ambiguous locator with a more robust one and giving you the root cause — and re-running the test shows it now passes. You get the fix with little manual work, while still seeing the reasoning so you stay in control.
Make healing automatic in CI. Running the healer by hand after every deployment doesn't scale, so in this closing lecture you'll run it unattended with one workflow file — heal.yml in .github/workflows. It uses the official Claude Code GitHub Action pointed at the healer definition Playwright already generated, with a plain prompt ("run the suite, heal any failing tests, then open a pull request") and a short list of allowed tools (Bash, read, edit). It needs an Anthropic API key stored as a GitHub secret. And instead of hand-editing YAML, you'll simply ask Claude Code to make changes — like switching from a schedule to a manual trigger — and it figures out the file for you. This is the final lecture of the course — thanks for following along, and please leave a rating.
Everything from Section 9's AI-powered workflows, condensed onto a one-page reference sheet. Download the attached PDF and keep it beside you as you bring AI into your testing. It covers setting up the Playwright MCP (local vs. project scope and .mcp.json), generating tests from plain-English prompts, scaffolding the planner/generator/healer agents with init-agents, and running the healer unattended in a GitHub Actions workflow — plus the honest boundary that AI aids discovery and generation but doesn't replace your regression suite or review. No need to memorize any of it; just glance at the sheet whenever you need a reminder.
Learn Microsoft Playwright the way it's actually used in 2026 — with TypeScript and AI test automation built in from day one.
Playwright has become the tool of choice for modern automation testing, overtaking Cypress and Selenium in real-world adoption. But most Playwright courses still teach it against throwaway demo pages and stop exactly where the interesting problems begin. This one doesn't.
You'll build a complete, professional Playwright test automation framework in TypeScript from scratch — and you'll run it against a real, full-stack web application built specifically for this course. Logins with validation, dynamic data tables, iframes, file uploads, authentication flows, a live REST API, and deliberately tricky pages designed to teach you how to handle flaky, real-world elements. If you've ever finished a software testing course and thought "but the real apps at work are nothing like this," that gap is exactly what this course closes.
What makes this course different
It's built for 2026, not 2020. AI test automation is no longer a buzzword — it's how modern QA automation teams work. You'll learn to use AI where it genuinely helps: generating tests, self-healing broken locators, and speeding up your workflow with Playwright MCP and Claude Code. This isn't a bolt-on "AI" chapter tacked onto the end. It's woven into how you'll actually work as an automation engineer. Most courses only talk about AI-powered testing. Here, you'll watch Playwright MCP work against a real accessibility tree — and then do it yourself.
You'll practice on a real application. Every concept is taught against the course's companion app — a full UI plus a real REST API — so you're not just learning syntax. You're solving the same problems you'll face on the job: iframes, authentication, file handling, dynamic tables, and elements that don't behave. The app stays online after the course ends, so you can keep practicing web automation and API automation for as long as you like.
It goes from zero to job-ready. No automation experience required. You'll start with the fundamentals of UI testing and finish with a maintainable end-to-end testing framework using the Page Object Model, fixtures, reusable components, parallel execution, and CI/CD — the exact skills hiring managers screen for in QA automation and SDET interviews.
Just enough TypeScript. You'll learn the TypeScript you need to write clean, type-safe tests — no more, no less. This is a Microsoft Playwright course, not a programming course, and the language never gets in the way of the testing.
Switching from Selenium or Cypress? You're in the right place. If you're switching from Selenium, you'll immediately appreciate auto-waiting locators, built-in parallelism, and the end of explicit wait spaghetti. If you're migrating from Cypress, you'll get true multi-browser support, real API testing without plugins, and no test-runner lock-in. Throughout the course, I'll point out where Playwright's approach differs from what you already know, so your existing automation testing experience transfers instead of getting in the way.
What you'll learn, step by step
This is a complete Microsoft Playwright tutorial that takes you from your very first test to a production-grade framework:
Playwright fundamentals — installation, configuration, the test runner, and writing your first end-to-end test in TypeScript
Locators and assertions — Playwright's modern locator engine, web-first assertions, and how auto-waiting eliminates the flakiness that plagues Selenium suites
Real-world UI testing — forms and validation, dynamic data tables, iframes, file uploads and downloads, popups, and the deliberately difficult pages in the companion app
Authentication and session handling — logging in once, reusing auth state, and testing role-based access properly
API testing with Playwright — calling the companion app's live REST API, validating responses, and combining API and UI steps in the same test for fast, reliable end-to-end coverage
Framework architecture — the Page Object Model done right, custom fixtures, reusable components, test data management, and a folder structure that scales with your team
Parallel execution and reporting — running suites across browsers and workers, and producing reports your team will actually read
CI/CD with GitHub Actions — running your full suite on every push, so your framework behaves like it would at a real job
AI-powered testing with Playwright MCP and Claude Code — generating tests from plain-English descriptions, exploring the accessibility tree, self-healing broken locators, and knowing when AI helps and when it hurts
Every section is hands-on. You'll write code in every lecture that involves code, and each section ends with practice that pushes you slightly past what was demonstrated — because that's where the learning actually happens.
What you'll build
By the end, you'll have a real, portfolio-ready automation framework: end-to-end UI tests, API tests, a Page Object Model architecture, CI/CD pipelines in GitHub Actions, and AI-assisted workflows — all running against a genuine full-stack application. It's the kind of project you can walk through in a QA automation or Playwright interview and explain every decision, because you made every decision.
Who this course is for
Manual testers and QA engineers moving into automation testing
Aspiring SDETs building the framework skills the role demands
Developers who want to test their own applications properly
Selenium or Cypress users switching to Playwright
Automation engineers who want to add AI-powered testing with Playwright MCP to their toolkit
Anyone preparing for QA automation interviews and software testing roles in 2026
Requirements
Basic familiarity with any programming language is helpful but not required — we start from the beginning
No Playwright or TypeScript experience needed
A computer (Windows, Mac, or Linux) and a willingness to practice
Why learn Playwright now?
Playwright leads QA adoption in 2026, with Selenium declining and Cypress holding a distant third. Job postings increasingly list Microsoft Playwright with TypeScript as the primary requirement for automation roles, and the newest postings add AI-assisted testing on top. Learning Playwright today means learning the stack the industry is hiring for — and adding Playwright MCP puts you ahead of candidates who stopped at scripting.
Ready to become the automation engineer teams are hiring for? Enroll now, build a real framework on a real application, and learn the AI-powered testing skills that will define the next decade of QA. See you in the first lecture.