UI testing validates that your web application’s user interface works correctly. This guide demonstrates how to write UI tests using Playwright, covering element interactions, navigation, and user workflows.
Always test failure cases to ensure proper error handling:
test_login.py (Lines 22-35)
def test_invalid_login(page: Page): page.goto(URL) username_input = page.get_by_placeholder("Username") username_input.fill("standard_user") password_input = page.get_by_placeholder("Password") password_input.fill("secret") # Wrong password login_button = page.locator("input#login-button") login_button.click() error_message = page.get_by_text("Epic sadface: Username and password do not match any user in this service") assert error_message.is_visible
Don’t just test the “happy path”. Invalid inputs, network failures, and edge cases often reveal critical bugs.
# Fill text inputpage.locator("#email").fill("[email protected]")# Clear and fillpage.locator("#email").clear()page.locator("#email").fill("[email protected]")
# Simple clickpage.locator("button#submit").click()# Double clickpage.locator("#element").dblclick()# Right clickpage.locator("#element").click(button="right")
# Select by valuepage.locator("#country").select_option("USA")# Select by labelpage.locator("#country").select_option(label="United States")
Playwright automatically waits for elements, but you can add explicit waits when needed:
# Wait for element to be visiblepage.locator("#loading-spinner").wait_for(state="hidden")# Wait for navigationwith page.expect_navigation(): page.locator("#submit").click()# Wait with timeoutpage.locator("#slow-element").wait_for(timeout=10000) # 10 seconds
Playwright has built-in auto-waiting. You rarely need explicit waits unless dealing with animations, AJAX calls, or custom loading states.