⚙️ Setup & Installation Beginner
Maven Dependencies
<!-- Playwright Java -->
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.40.0</version> </dependency>
Install Browsers
# Install all browsers (Chromium, Firefox, WebKit)"install"
# Install specific browser
mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D
exec.args="install chromium"
Basic Setup - Playwright Hierarchy
🎭 Playwright Hierarchy: Playwright → Browser →
BrowserContext → Page
This hierarchy provides better isolation and efficiency compared to Selenium.
This hierarchy provides better isolation and efficiency compared to Selenium.
import com.microsoft.playwright.*;
// 1. Create Playwright instance
Playwright playwright = Playwright.create();
// 2. Launch browser
Browser browser = playwright.chromium().launch();
// 3. Create browser context (isolated session)// 4. Create page
Page page = context.newPage();
// Navigate
page.navigate("https://example.com");
// Cleanup (reverse order)
page.close(); context.close(); browser.close(); playwright.close();
💡 Playwright Advantage: BrowserContext provides
isolation without launching new browsers, making tests faster and
more efficient.
Browser Launch Options
// Chromium (default)
Browser browser = playwright.chromium().launch(newfalse) .setSlowMo(100) // Slow down by 100ms
);
// Firefox
Browser browser = playwright.firefox().launch();
// WebKit (Safari engine)
Browser browser = playwright.webkit().launch();
// Advanced options
Browser browser = playwright.chromium().launch(newtrue) .setSlowMo(50) .setTimeout() .setDevtools(true) // Open DevTools
.setArgs(Arrays.asList("--start-maximized"
Browser Context Options
BrowserContext context = browser.newContext(new// Viewport size
.setViewportSize(1920, 1080)
// User agent
.setUserAgent("Custom User Agent")
// Geolocation
.setGeolocation(37.7749, -122.4194)
.setPermissions(Arrays.asList("geolocation"// Timezone
.setTimezoneId("America/New_York")
// Locale
.setLocale("en-US")
// Color scheme
.setColorScheme(ColorScheme.DARK)
// Accept downloads
.setAcceptDownloads(true)
// Ignore HTTPS errors
.setIgnoreHTTPSErrors(true)
// Record video
.setRecordVideoDir(Paths.get("videos/")) .setRecordVideoSize(1280,
720)
// HTTP credentials
.setHttpCredentials("username", "password") );
Mobile Emulation
import
com.microsoft.playwright.options.devices;
// Use predefined device
BrowserContext context = browser.newContext(
new
Browser.NewContextOptions(devices.get("iPhone 12 Pro"// Available devices
devices.get("iPhone SE") devices.get("iPhone 12")
devices.get("iPhone 12 Pro") devices.get("iPhone 12 Pro Max")
devices.get("Galaxy S9+") devices.get("Pixel 5") devices.get("iPad Pro 11")
📘 Basic Commands Beginner
Navigation
// Navigate to URL
page.navigate("https://example.com");
// Navigate with options
page.navigate("https://example.com", new Page.NavigateOptions()
.setTimeout(30000) .setWaitUntil(WaitUntilState.NETWORKIDLE) );
// Go back
page.goBack();
// Go forward
page.goForward();
// Reload
page.reload();
// Get current URL
String url = page.url();
// Get page title
String title = page.title();
// Get page content
String html = page.content();
Wait Until States
| State | Description | Use Case |
|---|---|---|
| LOAD | Page load event fired | Default, basic page load |
| DOMCONTENTLOADED | DOM is ready | Faster, DOM manipulation |
| NETWORKIDLE | No network connections for 500ms | SPA, AJAX heavy pages |
| COMMIT | Navigation committed | Rare, low-level control |
Page Methods
// Wait for timeout
page.waitForTimeout(3000); // 3 seconds (avoid if possible)
// Wait for URL
page.waitForURL("**/dashboard");
// Wait for load state
page.waitForLoadState(LoadState.NETWORKIDLE);
// Screenshot
page.screenshot(new
Page.ScreenshotOptions().setPath(Paths.get("screenshot.png"// Full page screenshot
page.screenshot(new
Page.ScreenshotOptions() .setPath(Paths.get("full.png")) .setFullPage(true) );
// PDF (Chromium only)
page.pdf(new
Page.PdfOptions().setPath(Paths.get("page.pdf"// Close page
page.close();
🎯 Locators Beginner Better than Selenium
🎭 Playwright Locators vs Selenium: Playwright
locators are lazy, auto-retry, and support chaining. They don't
evaluate until an action is performed, making them more reliable.
Basic Locators (Recommended)
// By role (Recommended - Accessibility-first)new
Page.GetByRoleOptions().setName("Submit"));
// By text
page.getByText("Sign Up"); page.getByText("Sign");
// Partial match
// By label (form fields)
page.getByLabel("Username"); page.getByLabel("Email Address");
// By placeholder
page.getByPlaceholder("Enter email");
// By alt text (images)
page.getByAltText("Company Logo");
// By title
page.getByTitle("Close");
// By test ID (data-testid attribute)
page.getByTestId("submit-button");
CSS and XPath Locators
// CSS selector
page.locator("css=button.primary"); page.locator("button.primary");
// 'css=' is default
// XPath
page.locator("xpath=//button[@id='submit']"); page.locator("//button[@id='submit']");
// ID shorthand
page.locator("#username");
// Class shorthand
page.locator(".btn-primary");
Chaining Locators
// Filter by text
page.locator("button").filter("Submit"// Filter by another locator
page.locator("article").filter(".featured"// Find within locator (scoping)
page.locator(".container").locator(// First/Last/Nth
page.locator("li").first(); page.locator("li").last();
page.locator("li").nth(// Count
int count = page.locator(// All text contents
List<String> texts = page.locator("li"// All inner texts
List<String> innerTexts = page.locator("li"
Locator Assertions
import static
com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
// Visibility
assertThat(page.locator("#message")).isVisible(); assertThat(page.locator(// Text content
assertThat(page.locator("#message")).hasText("Success");
assertThat(page.locator("#message")).containsText("Succ");
// Count
assertThat(page.locator("li")).hasCount(5);
// Attributes
assertThat(page.locator("input")).hasAttribute("type",
"text"); assertThat(page.locator()).hasAttribute("href", "/home");
// Value
assertThat(page.locator("input")).hasValue("test@example.com");
// CSS class
assertThat(page.locator("button")).hasClass("active");
// Enabled/Disabled
assertThat(page.locator("button")).isEnabled(); assertThat(page.locator(// Checked
assertThat(page.locator("#agree")).isChecked();
Aria Roles (Accessibility Testing)
| Role | Element | Example |
|---|---|---|
| BUTTON | Buttons | getByRole(AriaRole.BUTTON) |
| LINK | Links | getByRole(AriaRole.LINK) |
| TEXTBOX | Input fields | getByRole(AriaRole.TEXTBOX) |
| CHECKBOX | Checkboxes | getByRole(AriaRole.CHECKBOX) |
| RADIO | Radio buttons | getByRole(AriaRole.RADIO) |
| HEADING | Headings | getByRole(AriaRole.HEADING) |
| LISTITEM | List items | getByRole(AriaRole.LISTITEM) |
🖱️ Element Interactions Intermediate
Basic Actions
// Click
page.locator("button").click();
// Click with options
page.locator("button").click(// Right click .setClickCount() // Double click .setDelay(// Delay between mousedown and mouseup
.setForce(true) // Bypass actionability checks
.setModifiers(Arrays.asList(KeyboardModifier.SHIFT)) );
// Double click
page.locator("button").dblclick();
// Right click
page.locator("button").click(// Fill input (auto-clears first)
page.locator("#email").fill(// Type (character by character)
page.locator("#search").type(); page.locator("#search").type(new
Locator.TypeOptions().setDelay(100));
// Press key
page.locator("#search").press(); page.locator("#search").press(); page.locator("#search").press(// Clear input
page.locator("#email").clear();
// Check/Uncheck
page.locator("#agree").check(); page.locator("#agree").uncheck();
page.locator("#agree").setChecked(// Focus
page.locator("#email").focus();
// Hover
page.locator(".menu").hover();
// Scroll into view
page.locator("#footer").scrollIntoViewIfNeeded();
// Tap (touch devices)
page.locator("button").tap();
Get Element Information
// Text content
String text = page.locator("#message").textContent();
// Inner text (visible text only)
String innerText = page.locator("#message"// Inner HTML
String innerHTML = page.locator("#container"// Get attribute
String href = page.locator("a").getAttribute("href"); String value =
page.locator("input").getAttribute(// Input value
String inputValue = page.locator("input").inputValue();
// Is visible
boolean visible = page.locator(// Is hidden
boolean hidden = page.locator(// Is enabled
boolean enabled = page.locator(// Is disabled
boolean disabled = page.locator(// Is checked
boolean checked = page.locator(// Bounding box
BoundingBox box = page.locator("#element").boundingBox(); double width =
box.width; double height = box.height; double x = box.x;
double y = box.y;
Dropdowns/Select
// Select by value
page.locator("select").selectOption("value1");
// Select by label
page.locator("select").selectOption(new
SelectOption().setLabel("Option 1"));
// Select by index
page.locator("select").selectOption(new
SelectOption().setIndex(2));
// Select multiple
page.locator("select").selectOption(new String[]{"value1", "value2"});
File Upload
// Upload single file
page.locator("input[type='file']").setInputFiles(Paths.get("file.pdf"));
// Upload multiple files
page.locator("input[type='file']").setInputFiles(new Path[]{
Paths.get("file1.pdf"), Paths.get(// Clear file input
page.locator("input[type='file']").setInputFiles(new Path[0]);
Drag and Drop
// Drag and drop
page.locator("#source").dragTo(page.locator("#target"));
// Drag by coordinates
page.locator("#draggable").dragTo(page.locator("#draggable"),
new Locator.DragToOptions() .setTargetPosition(100,
200) );
Screenshots
// Element screenshot
page.locator("#logo").screenshot("logo.png"// Full page screenshot
page.screenshot(new
Page.ScreenshotOptions() .setPath(Paths.get("fullpage.png")) .setFullPage(true) );
// Screenshot as bytes
byte[] screenshot = page.screenshot();
⏰ Auto-Waiting Intermediate Major Advantage
🎭 Playwright's Auto-Waiting: Playwright
automatically waits for elements to be actionable before performing
actions. No explicit waits needed in most cases!
Actionability Checks (Automatic)
Before every action, Playwright performs these checks:
- ✅ Element is attached to DOM
- ✅ Element is visible
- ✅ Element is stable (not animating)
- ✅ Element receives events (not obscured)
- ✅ Element is enabled
// No wait needed! Playwright waits automatically"button").click(); // Waits for button to be clickable
// In Selenium, you'd need:
// WebDriverWait wait = new WebDriverWait(driver, 10);//
wait.until(ExpectedConditions.elementToBeClickable(button));
// button.click();
Explicit Waits (When Needed)
// Wait for selector
page.waitForSelector("#message");
// Wait for selector with options
page.waitForSelector("#message", new Page.WaitForSelectorOptions()
.setState(WaitForSelectorState.VISIBLE) .setTimeout(// Wait for element to be hidden
page.waitForSelector("#loading", new Page.WaitForSelectorOptions()
.setState(WaitForSelectorState.HIDDEN) );
// Wait for element to be detached
page.waitForSelector("#temp", new Page.WaitForSelectorOptions()
.setState(WaitForSelectorState.DETACHED) );
// Wait for URL
page.waitForURL("**/dashboard"); page.waitForURL(url -> url.contains(// Wait for load state
page.waitForLoadState(LoadState.NETWORKIDLE);
page.waitForLoadState(LoadState.DOMCONTENTLOADED);
// Wait for function
page.waitForFunction("() => document.querySelector('#message').innerText ===
'Ready'");
// Wait for timeout (avoid if possible)
page.waitForTimeout(1000); // 1 second
// Wait for response
page.waitForResponse("**/api/data", () -> { page.locator("button").click();
});
// Wait for request
page.waitForRequest("**/api/submit", () -> { page.locator("button").click();
});
Polling/Retry
// Locators retry automatically (polling every 100ms by
default)
assertThat(page.locator("#status")).hasText("Complete");
// Custom timeout for assertion
assertThat(page.locator("#message")) .hasText("Success",
new LocatorAssertions.HasTextOptions() .setTimeout(10000) );
🚀 Advanced Features Advanced
Dialogs (Alerts/Confirms/Prompts)
// Handle dialog before it appears
page.onDialog(dialog -> { System.out.println(dialog.message());
dialog.accept(); // or dialog.dismiss()
});
// Handle prompt with input
page.onDialog(dialog -> { dialog.accept("My Input"// Get dialog type
page.onDialog(dialog -> { System.out.println(dialog.type());
// alert, confirm, prompt, beforeunload
dialog.accept(); });
Frames/iFrames
// By name or ID
FrameLocator frame = page.frameLocator("iframe[name='myframe']"); frame.locator("button").click();
// Nested frames
page.frameLocator("#outer-frame") .frameLocator("#inner-frame")
.locator("button") .click();
// Get all frames
List<Frame> frames = page.frames();
// Get frame by URL
Frame frame = page.frameByUrl("https://example.com/frame"
Multiple Pages/Windows
// Wait for new page
Page newPage = context.waitForPage(() -> { page.locator(// Open new page
Page newPage = context.newPage(); newPage.navigate(// Get all pages
List<Page> pages = context.pages();
// Switch between pages
pages.get(0).bringToFront();
// Close page
newPage.close();
// Handle popup
Page popup = page.waitForPopup(() -> { page.locator(
Network Interception
// Route API calls
page.route("**/api/data", route -> { route.fulfill(new
Route.FulfillOptions() .setStatus(200) .setBody() .setContentType("application/json") ); });
// Abort requests (e.g., block images)
page.route("**/*.{png,jpg,jpeg}", route -> route.abort());
// Continue request with modifications
page.route("**/api/**", route -> { route.continue_(new
Route.ContinueOptions() .setHeaders(Map.of("Authorization", "Bearer token")) ); });
// Monitor requests
page.onRequest(request -> { System.out.println(// Monitor responses
page.onResponse(response -> { System.out.println(" - " + response.status()); });
// Wait for specific response
Response response = page.waitForResponse("**/api/user", () -> { page.locator("button").click(); }); System.out.println(response.json());
Downloads
// Handle download
Download download = page.waitForDownload(() -> {
page.locator("a[download]").click(); });
// Get suggested filename
String filename = download.suggestedFilename();
// Save download
download.saveAs(Paths.get("downloads/" + filename));
// Get path to temporary file
Path path = download.path();
Authentication & Storage State
// Save authentication state
context.storageState(new
BrowserContext.StorageStateOptions() .setPath(Paths.get(// Reuse authentication state
BrowserContext context = browser.newContext(new// This loads cookies and local storage
Video Recording
// Enable video recording
BrowserContext context = browser.newContext(new)) .setRecordVideoSize(1280, 720) );
// Video is saved when page/context closes
Tracing & Debugging
// Start tracing
context.tracing().start(new
Tracing.StartOptions() .setScreenshots(true) .setSnapshots(true) );
// Your test code here
page.navigate("https://example.com");
// Stop tracing and save
context.tracing().stop(new
Tracing.StopOptions() .setPath(Paths.get("trace.zip"// View trace: npx playwright show-trace trace.zip
✨ Best Practices & Tips
Locator Strategy
✅ Recommended Locator Priority:
1.
2.
3.
4.
5.
6. CSS/XPath - Last resort
1.
getByRole() - Accessibility-first, resilient2.
getByLabel() - For form fields3.
getByPlaceholder() - For inputs4.
getByText() - For text content5.
getByTestId() - For test-specific IDs6. CSS/XPath - Last resort
Playwright vs Selenium Comparison
| Feature | Playwright | Selenium |
|---|---|---|
| Auto-Waiting | ✅ Built-in | ❌ Manual explicit waits |
| Browser Support | Chromium, Firefox, WebKit | Chrome, Firefox, Safari, Edge |
| Speed | ~50% faster | Baseline |
| Network Interception | ✅ Native support | ❌ Requires browser DevTools |
| Mobile Emulation | ✅ Built-in devices | ✅ Chrome DevTools |
| Parallel Testing | ✅ BrowserContext isolation | ❌ Multiple browser instances |
| Maturity | Newer (2020) | Established (2004) |
✅ DO:
- Use accessibility locators (getByRole, getByLabel)
- Leverage auto-waiting instead of explicit waits
- Use BrowserContext for test isolation
- Save and reuse authentication state
- Use network interception for mocking APIs
- Enable tracing for debugging
- Use locator chaining for scoped selections
❌ DON'T:
- Don't use waitForTimeout() unless absolutely necessary
- Don't rely on CSS/XPath when semantic locators work
- Don't create new browser instances for each test
- Don't ignore actionability checks with force:true
- Don't hardcode waits when auto-wait is available
Common Patterns
// Page Object Model with Playwright
public class LoginPage { private final Page page;
private final Locator usernameInput; private final Locator passwordInput;
private final Locator loginButton;
public LoginPage(Page page) { this.page = page;
this.usernameInput = page.getByLabel("Username");
this.passwordInput = page.getByLabel("Password");
this.loginButton = page.getByRole(AriaRole.BUTTON,
new
Page.GetByRoleOptions().setName("Login")); }
public void login(String username, String password) { usernameInput.fill(username); passwordInput.fill(password);
loginButton.click(); } }
Performance Tips
🚀 Speed Up Your Tests:
- Use BrowserContext instead of new browsers
- Run tests in parallel with isolated contexts
- Save authentication state to skip login
- Use network interception to mock slow APIs
- Set aggressive timeout values for fast failures
- Use headless mode in CI/CD
- Disable unnecessary resources (images, CSS)