Generate Playwright Tests with AI: Stable Locators and Real Assertions
AI will happily write a Playwright test for a page it has never seen. It will guess the locators, and the test may fail or, worse, pass for the wrong reason. In this lesson you will generate Playwright tests with AI using real page details, stable locators and assertions that prove something.
📖 What You’ll Learn
- A safe workflow for generating a test
- How to choose stable locators
- What makes an assertion meaningful
- How to prove a test can really fail
💡 How to Generate Playwright Tests with AI Safely
Explain Like I’m 5: Plan, Then Build
Imagine: You draw your sandcastle first. Then you build it. It is easier to fix a drawing than a castle.
What it really means: Agree the test plan before asking for code.
In testing: Review scenarios first, then generate one test.
- Write down the behaviour to test.
- Collect real details about the page.
- Ask AI for one test.
- Read the code.
- Run it.
- Break the behaviour, and confirm the test fails.
🔍 Give AI Real Page Details
AI cannot see your page unless you show it. You can paste the relevant HTML, use a browser tool such as Playwright MCP, or use Codegen to record real locators.
Here is real HTML from our Automation Practice Page:
<button onclick="loadAjax(true)">Load Success</button>
<p id="loader"></p>
<input type="text" id="username" name="username" placeholder="Enter username">
<input type="checkbox" id="python"><label for="python">Python</label>
🧩 Choosing Stable Locators
Explain Like I’m 5: Stable Locators
Imagine: “The boy in the red hat” works until he changes hats. “Asha” still works.
What it really means: A stable locator keeps working when the page’s appearance changes.
In testing: Find a button by its role and name, not by its position.
| Prefer | Example | Avoid |
|---|---|---|
| Role and name | getByRole('button', { name: 'Load Success' }) | div > button:nth-child(2) |
| Label | getByRole('checkbox', { name: 'Python' }) | Long XPath |
| Placeholder | getByPlaceholder('Enter username') | Auto-generated class names |
| Test ID | getByTestId('checkout') | Position on the page |
An ID such as #loader is fine when no better user-facing option exists. Learn more in Playwright Locators.
🛠️ Meaningful Assertions
Explain Like I’m 5: Checking the Real Result
Imagine: You press the light switch. Seeing the switch move is not enough. You check that the light came on.
What it really means: An assertion should prove the behaviour worked.
In testing: Check the success message, not only that a button exists.
| Weak | Stronger |
|---|---|
| Button is visible after clicking | Success message has the exact text |
| Page did not crash | Saved value appears after reload |
| Response has a body | Response contains the expected data |
🌍 Real-Life Example: Two Useful Tests
import { test, expect } from '@playwright/test';
const PAGE_URL = 'https://sqatools.in/automation-practice-page/';
test.beforeEach(async ({ page }) => {
await page.goto(PAGE_URL);
});
test('Load Success shows the success message', async ({ page }) => {
await page.getByRole('button', { name: 'Load Success' }).click();
await expect(page.locator('#loader')).toHaveText('Data loaded successfully!');
});
test('a language checkbox can be selected', async ({ page }) => {
const python = page.getByRole('checkbox', { name: 'Python' });
await expect(python).not.toBeChecked();
await python.check();
await expect(python).toBeChecked();
});
Notice the check before the action. If the box was already selected, the second test would otherwise prove nothing.
await expect(...).toHaveText(...) retries until the text appears or the timeout ends. That removes the need for fixed waits.
🔑 Prove the Test Can Fail
Explain Like I’m 5: Testing the Smoke Alarm
Imagine: You press the test button on the smoke alarm. An alarm that never rings is no help.
What it really means: A test is only useful if it fails when the behaviour breaks.
In testing: Change the expected text briefly and watch it fail.
Try one of these on a temporary copy:
- Change the expected text.
- Click the wrong button.
- Remove the action step.
If the test still passes, it is not checking what you thought.
Do not edit expected results to get green
When a test fails, find out why. The product may be wrong, and the test may have just found a real bug.
🧪 Try It Yourself
- Pick another feature from the practice page, such as the country dropdown.
- Copy its real HTML.
- Run the prompt below.
- Read the code, and run it.
- Make it fail on purpose, then restore it.
📋 Ready-to-Copy Prompt
You are a senior Playwright engineer. Write one Playwright Test in
TypeScript.
Behaviour to test: [behaviour]
Page URL: [approved test URL]
Real HTML from the page:
[paste relevant HTML]
Rules:
- Use only elements shown in the HTML.
- Prefer getByRole, getByLabel, getByPlaceholder and getByTestId.
- Use web-first assertions with await expect.
- Do not use fixed waits or CSS position selectors.
- The assertion must prove the behaviour, not only that an element exists.
- If the expected result is not provided, write a TODO and ask me.
After the code, tell me how to make this test fail on purpose.
⚠️ Common Mistakes
- Letting AI guess locators it has not seen
- Accepting
toBeVisibleas the only check - Using
waitForTimeoutto hide timing problems - Running a generated test only once
- Never checking whether the test can fail
🎯 Key Takeaways
- Give AI real page details, and generate one test at a time.
- Prefer locators based on what users see.
- Assert the outcome of the behaviour.
- Prove that each new test can fail.
🎤 Interview Questions
1. How do you generate reliable Playwright tests with AI?
Model answer: I define the behaviour first and give the tool real HTML or browser access. I require stable locators and meaningful assertions, then read and run the test, and confirm it fails when the behaviour is broken.
2. Which Playwright locators do you prefer, and why?
Model answer: I prefer role, label and test ID locators because they match how users find elements or are designed for testing. They usually survive layout and styling changes better than long CSS or XPath selectors.
3. What are web-first assertions?
Model answer: They are Playwright assertions such as toHaveText that automatically retry until the condition is met or the timeout ends. This handles dynamic pages without fixed waits.
4. How can a generated test pass but be useless?
Model answer: It may only check that a page loaded, assert the wrong thing or never reach the behaviour. I review what it proves and verify that it fails when I break the behaviour.
5. What would you do if an AI-generated locator fails?
Model answer: I inspect the real page and see whether the locator was invented, the page changed or the element is not ready. I fix the cause using a stable locator, and I avoid adding waits just to hide it.
📝 Assignment
Generate three tests for different features of the practice page. For each test, record the locator choice, the assertion and how you proved that it can fail. Rewrite at least one weak assertion.
❓ FAQ
Can AI use my live browser to write tests?
Yes, tools such as Playwright Test Agents can explore a page. Keep them on approved test environments and review what they produce.
Should every element get a test ID?
Not necessarily. Use accessible roles and labels first, and add test IDs where they are not practical.
🚀 Next Steps
Well done on finishing this lesson. Complete the assignment, then continue with Page Object Model with AI: Design a Clean Playwright Framework.