Playwright Test Reviewer
When to Use
- Auditing existing Playwright test files before PR merge
- Identifying flaky test patterns early
- Enforcing team coding standards
- Improving selector resilience
- Reducing CI/CD failure noise
What This Skill Reviews
1. Selector Quality Checker
Copilot will flag these bad selectors and suggest fixes:
| Anti-Pattern | Risk | Better Alternative |
|---|---|---|
page.click("div > div > span") |
Breaks on DOM change | page.click("[data-testid='submit']") |
page.click(".btn-primary") |
CSS class can change | page.getByRole('button', { name: 'Submit' }) |
page.click("#id_123abc") |
Auto-generated IDs | page.getByLabel('Email') |
page.locator("xpath=//div[3]") |
Position-dependent | page.getByText('Dashboard') |
Preferred Selector Priority (Playwright best practice):
# 1. Role-based — most resilient
page.get_by_role("button", name="Login")
# 2. Label-based — accessible
page.get_by_label("Email address")
# 3. Placeholder
page.get_by_placeholder("Enter username")
# 4. Test ID — stable custom attribute
page.get_by_test_id("submit-btn") # data-testid="submit-btn"
# 5. Text-based
page.get_by_text("Welcome back")
# AVOID — fragile
page.locator("div.container > form > button:nth-child(2)")
2. Flakiness Pattern Detector
Copilot will flag these flaky patterns:
# ❌ FLAKY — hard-coded sleep
import time
time.sleep(3)
page.click("#submit")
# ✅ FIXED — auto-wait
page.click("#submit") # Playwright auto-waits for actionability
# ❌ FLAKY — no wait before assertion
assert page.is_visible("#dashboard")
# ✅ FIXED — wait for element
page.wait_for_selector("#dashboard")
assert page.is_visible("#dashboard")
# ❌ FLAKY — race condition on navigation
page.click("#login-btn")
assert "dashboard" in page.url # URL may not have changed yet
# ✅ FIXED — wait for URL
page.click("#login-btn")
page.wait_for_url("**/dashboard")
assert "dashboard" in page.url
3. Test Isolation Checker
# ❌ BAD — shared state between tests
class TestLogin:
page = None # class-level — shared across tests!
def test_one(self):
self.page.goto(...)
def test_two(self):
self.page.click(...) # depends on test_one state
# ✅ GOOD — fixture-based isolation
class TestLogin:
@pytest.fixture(autouse=True)
def setup(self, page): # fresh page per test
self.page = page.page
self.page.goto("https://app.example.com/login")
4. Assertion Quality Checker
# ❌ WEAK assertion
assert page.is_visible("#msg")
# ✅ STRONG — Playwright's expect() with auto-retry
from playwright.sync_api import expect
expect(page.locator("#msg")).to_be_visible()
expect(page.locator("#msg")).to_have_text("Login successful")
expect(page).to_have_url("**/dashboard")
expect(page.locator("#count")).to_have_text("5")
# ✅ Negative assertions
expect(page.locator(".error")).not_to_be_visible()
5. Page Object Compliance Checker
Copilot checks if raw locators are leaking into test files:
# ❌ BAD — locators directly in test
def test_login(page):
page.fill("#username", "admin")
page.fill("#password", "pass")
page.click("#loginBtn")
# ✅ GOOD — locators inside page object only
def test_login(page):
login = LoginPage(page)
login.login("admin", "pass")
6. Screenshot on Failure Hook Checker
# ❌ Missing — no failure evidence
@pytest.fixture(scope="function")
def page(browser_context):
page = browser_context.new_page()
yield page
page.close()
# ✅ CORRECT — auto-screenshot on failure
@pytest.fixture(scope="function")
def page(browser_context, request):
page = browser_context.new_page()
yield page
if request.node.rep_call.failed:
page.screenshot(path=f"reports/screenshots/FAIL_{request.node.name}.png")
page.close()
7. Full Review Checklist
When you ask Copilot to review a Playwright test file, it will check:
- No
time.sleep()calls - Selectors use role/label/test-id over CSS/XPath
-
expect()used instead of rawassert is_visible() - Each test uses a fresh page/context (no shared state)
- Page objects used — no raw locators in test files
- Screenshot on failure hook is present
- Trace recording enabled in CI mode
- No hard-coded credentials in test files
- Network mocking used where API calls are not under test
- Tests are independent — no execution order dependency
Usage
Ask Copilot:
"Review this Playwright test file for best practices and flag any anti-patterns"
"Check my selectors for flakiness risks"
"Does this test follow Page Object Model correctly?"