Eclipse
Playwright Java Guide
0/10
sessions
Eclipse IDE · Maven · JUnit 5 · Playwright

Playwright + Java
Eclipse Edition

A complete beginner's guide — every screenshot, every menu click, every line of code. Built for Eclipse IDE.

10
Sessions
20h
Total
Eclipse
IDE
15m
Review
Eclipse-specific tutorial
Every step in this guide uses Eclipse IDE menus, shortcuts, and panels — not IntelliJ. All Maven commands are run inside Eclipse, not the terminal.
1
Foundation · Session 1 of 10
Eclipse setup — install everything & run your first test
Set up Eclipse IDE with Java 17, create a Maven project, add Playwright, and run your very first browser test — all without touching the terminal.
Real-world analogy
This is like setting up a new kitchen before cooking. You install the stove (Java), the pantry shelves (Maven), the recipe book holder (Eclipse), and the ingredients delivery (Playwright). Once the kitchen is ready, cooking is easy every day.
What you'll install — in this order
1
Download & install Java 17 (JDK)
Go to adoptium.net → download Eclipse Temurin 17 for your OS. Run the installer. After install, open Command Prompt / Terminal and type java -version — you should see version 17.
2
Download Eclipse IDE for Java Developers
Go to eclipse.org/downloads → click "Download x86_64" → run the installer → choose "Eclipse IDE for Java Developers". This version has Maven built in.
3
Create a Maven project in Eclipse
File → New → Maven Project → check "Create a simple project" → fill in Group ID and Artifact ID → Finish. Eclipse creates pom.xml automatically.
4
Add Playwright to pom.xml
Open pom.xml → click the pom.xml tab at the bottom to see raw XML → paste the dependency XML → right-click project → Maven → Update Project (Alt+F5).
5
Install Playwright browsers
Right-click project → Run As → Maven build… → in Goals type: exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args=install → Run. Eclipse downloads Chrome, Firefox, Safari browsers.
6
Write your first test & run it
Create a class in src/test/java → copy the starter code → right-click the file → Run As → JUnit Test. The JUnit panel at the bottom shows green if it passes.
Eclipse IDE — exact menu paths
Follow these steps exactly in Eclipse. Every menu name matches what you see on screen.
Creating the Maven project in Eclipse
→
Click File in the top menu bar → hover over New → click Maven Project
→
A wizard opens. Check the box "Create a simple project (skip archetype selection)" → click Next
→
Fill in: Group Id: com.mycompany   Artifact Id: playwright-tests   Packaging: jar → click Finish
→
In the Project Explorer (left panel), expand your project → double-click pom.xml to open it
→
At the bottom of the editor, click the tab called pom.xml (not Overview) — this shows the raw XML
→
Paste the Playwright and JUnit dependencies inside <dependencies> → save with Ctrl+S
→
Right-click the project in Project Explorer → Maven → Update Project… → click OK. Eclipse downloads all libraries.
Running your first test in Eclipse
→
In Project Explorer, expand src/test/java → right-click → New → Class → name it FirstTest → Finish
→
Paste the test code from the Code tab into the class
→
Right-click anywhere inside the editor → Run As → JUnit Test
→
The JUnit panel opens at the bottom — a green bar means the test passed. A red bar means it failed (check the error in the Console tab).
Eclipse — JUnit Result Panel
JUnit × ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ← green bar = test passed Runs: 1/1 Errors: 0 Failures: 0 ✓ FirstTest ✓ openGoogle() 0.821 s
pom.xml — paste inside <dependencies></dependencies>
<!-- Playwright library -->
<dependency>
  <groupId>com.microsoft.playwright</groupId>
  <artifactId>playwright</artifactId>
  <version>1.44.0</version>
</dependency>

<!-- JUnit 5 for running tests -->
<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter</artifactId>
  <version>5.10.0</version>
  <scope>test</scope>
</dependency>
Also add inside <build><plugins> — needed for Maven to run JUnit 5
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>3.1.2</version>
</plugin>
src/test/java/FirstTest.java — your very first Playwright test
import com.microsoft.playwright.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class FirstTest {

  @Test
  void openGoogle() {
    // try-with-resources: browser closes automatically when done
    try (Playwright pw = Playwright.create()) {

      Browser browser = pw.chromium().launch();
      Page    page    = browser.newPage();

      page.navigate("https://google.com");

      assertTrue(page.title().contains("Google"));
      System.out.println("✓ Test passed! Title: " + page.title());
    }
  }
}
15-min review — answer these before moving on
?
Can you run the test and see a green bar in the JUnit panel without looking at notes?
?
What does try-with-resources do? (Why do we not need to call browser.close() manually?)
?
In Eclipse, which menu do you use to run a JUnit test? (Right-click → ?)
2
Foundation · Session 2 of 10
Finding elements on a page (Locators)
Before clicking or filling forms, Playwright must find the element. You'll learn 5 strategies — and use Eclipse's auto-complete to make it fast.
Real-world analogy
Telling someone where a chair is: "the red chair near the window" is better than "chair number 4 in row 2, column 3". Playwright's getByRole and getByText work like natural descriptions — far more reliable than position-based CSS selectors.
The 5 locator strategies — learn in this order
1
getByRole — best for buttons, links, headings
Finds elements by their ARIA role. page.getByRole(AriaRole.BUTTON, ...setName("Login")) — the most reliable strategy for interactive elements.
2
getByPlaceholder — best for text inputs
page.getByPlaceholder("Enter email") — finds inputs by the grey hint text inside them.
3
getByLabel — best for form fields with labels
page.getByLabel("Username") — finds inputs associated with a <label> tag. Preferred for accessible forms.
4
getByText — for any visible text on page
page.getByText("Welcome back") — finds elements containing exact or partial text. Great for error messages.
5
locator("#id") — CSS fallback
page.locator("#login-button") or page.locator(".btn-primary") — use only when the above don't work. Less readable but works everywhere.
Eclipse auto-complete shortcut
Type page. and then press Ctrl+Space to see all available methods including getByRole, getByText, getByLabel. This is the fastest way to discover Playwright's API in Eclipse.
Running Codegen from Eclipse (auto-record locators)
→
Right-click the project → Run As → Maven build…
→
In the Goals field, type exactly: exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="codegen saucedemo.com"
→
Click Run. A browser window opens — click around the site and Eclipse shows generated Java code in the Console panel
→
Copy the generated locators into your test class
Inspecting elements in Eclipse's built-in browser
→
When a test fails with "Element not found", open a regular Chrome browser → go to the test page → right-click the element → Inspect → find the id, class, or text to use in your locator
→
Eclipse Console tab (bottom panel) shows all System.out.println output — add System.out.println(page.title()) to debug what the page looks like
All 5 locator strategies with examples
// 1. By ARIA role — most reliable for buttons, links, headings
page.getByRole(AriaRole.BUTTON,
    new Page.GetByRoleOptions().setName("Login"))

// 2. By placeholder — for text inputs
page.getByPlaceholder("Username")

// 3. By label — for labeled form fields
page.getByLabel("Email address")

// 4. By visible text — for any element showing text
page.getByText("Welcome back")

// 5. CSS selector — fallback only
page.locator("#login-button")
page.locator(".product-title")

// Common actions on any locator
locator.click();           // click
locator.fill("text");     // type into input
locator.check();           // tick a checkbox
locator.selectOption("value"); // select dropdown
locator.hover();           // mouse hover
src/test/java/LoginTest.java — practice with saucedemo.com
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.AriaRole;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class LoginTest {

  @Test
  void loginWithGoodCredentials() {
    try (Playwright pw = Playwright.create()) {
      Browser browser = pw.chromium().launch(
        new BrowserType.LaunchOptions().setHeadless(false) // see the browser!
      );
      Page page = browser.newPage();
      page.navigate("https://www.saucedemo.com");

      // Use getByPlaceholder — clear and readable
      page.getByPlaceholder("Username").fill("standard_user");
      page.getByPlaceholder("Password").fill("secret_sauce");

      // Use getByRole for the button
      page.getByRole(AriaRole.BUTTON,
        new Page.GetByRoleOptions().setName("Login")).click();

      assertTrue(page.url().contains("inventory"),
        "Should redirect to inventory after login");
    }
  }
}
15-min review
?
What is the difference between getByRole and getByText?
?
In Eclipse, what shortcut shows all available methods after you type page.?
?
Why is getByPlaceholder better than a CSS ID for finding an input field?
3
Foundation · Session 3 of 10
Structuring tests with JUnit 5 hooks
Stop opening a new browser inside every test. JUnit 5's @BeforeEach and @AfterEach manage the browser lifecycle — your tests become short, clean, and independent.
Real-world analogy
@BeforeEach is like getting dressed before going out. You do it once before each task — not halfway through. @AfterEach is putting everything away when you return. Eclipse runs these hooks automatically around each @Test method.
Step-by-step
1
Move browser setup to @BeforeEach
Declare Playwright playwright, Browser browser, Page page as class fields. Initialize them in a method annotated with @BeforeEach.
2
Close the browser in @AfterEach
Call browser.close() and playwright.close() in @AfterEach. Eclipse runs this after every test — even if the test fails.
3
Switch to Playwright's assertThat()
assertThat(page).hasURL() and assertThat(locator).isVisible() are smarter than assertTrue — they wait automatically and give better error messages.
4
Write 3 tests in one class
Login success, login failure, URL check. All share the same @BeforeEach setup. Run the class in Eclipse with right-click → Run As → JUnit Test.
Running all tests in a class
Right-click the class file → Run As → JUnit Test runs ALL @Test methods in the class at once. The JUnit panel shows a separate row for each test.
Reading Eclipse's JUnit results panel
→
Green bar = all tests passed. Red bar = one or more failed. The number of failures shows in the top-right of the JUnit panel.
→
Click any test name in the JUnit panel to see its error message in the Failure Trace section below.
→
If Eclipse shows "No tests found" — check that your method is annotated with @Test and imported from org.junit.jupiter.api.Test (JUnit 5), not JUnit 4.
→
To rerun just the failed tests: right-click the red X test → Run. No need to rerun the whole class.
Fix: Eclipse running JUnit 4 instead of 5
→
If you see "JUnit 4" in the run configuration, right-click the test class → Run As → Run Configurations… → under Test runner, change from JUnit 4 to JUnit 5
src/test/java/SaucedemoTest.java — clean JUnit 5 structure
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.AriaRole;
import org.junit.jupiter.api.*;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.*;

public class SaucedemoTest {

  // Class-level fields — shared by all tests
  Playwright playwright;
  Browser    browser;
  Page       page;

  @BeforeEach                     // runs before EACH @Test
  void setUp() {
    playwright = Playwright.create();
    browser    = playwright.chromium().launch(
      new BrowserType.LaunchOptions().setHeadless(false));
    page       = browser.newPage();
    page.navigate("https://www.saucedemo.com");
  }

  @AfterEach                      // runs after EACH @Test — always
  void tearDown() {
    browser.close();
    playwright.close();
  }

  @Test
  void loginSucceeds() {
    page.getByPlaceholder("Username").fill("standard_user");
    page.getByPlaceholder("Password").fill("secret_sauce");
    page.getByRole(AriaRole.BUTTON,
      new Page.GetByRoleOptions().setName("Login")).click();
    assertThat(page).hasURL("https://www.saucedemo.com/inventory.html");
  }

  @Test
  void loginFails_wrongPassword() {
    page.getByPlaceholder("Username").fill("standard_user");
    page.getByPlaceholder("Password").fill("wrong123");
    page.getByRole(AriaRole.BUTTON,
      new Page.GetByRoleOptions().setName("Login")).click();
    assertThat(page.getByText("Epic sadface")).isVisible();
  }

  @Test
  void pageTitle_isCorrect() {
    assertThat(page).hasTitle("Swag Labs");
  }
}
15-min review
?
What happens if you forget @AfterEach — what is the real problem over time?
?
Name 3 assertThat() matchers you've used (e.g. hasURL, isVisible…)
?
In Eclipse, if you see "No tests found", what is the most likely fix?
4
Core Skills · Session 4 of 10
Auto-waiting — why tests stop being flaky
Playwright waits for elements to be ready before acting. You never need Thread.sleep(). Understanding this one concept eliminates 80% of test failures beginners face.
Real-world analogy
Like waiting for a microwave to finish before opening the door. Playwright checks: is the button visible? is it not moving? is it enabled? If any check fails, it retries — up to 30 seconds. You don't need Thread.sleep(3000) just to "wait for the page".
⚠️   Most common beginner mistake: Adding Thread.sleep(2000) when tests fail. This is fragile — always waits 2 seconds even if the page loaded in 200ms. Use Playwright's built-in waits instead.
The 3 actionability checks Playwright does automatically
1
Visible — is the element on screen?
If it's hidden (display:none or opacity:0), Playwright retries until it appears. If it never appears in 30s, the test fails with a clear timeout message.
2
Stable — has it stopped animating?
If the button is sliding in from the right, Playwright waits for the animation to finish before clicking. No more clicking mid-animation.
3
Enabled — is it not disabled?
A Submit button that's disabled (grey) will be waited on automatically. When it becomes enabled, Playwright clicks it.
When to add explicit waits
4
waitForURL — for single-page apps
After clicking Login, the URL changes from /login to /dashboard. Use page.waitForURL("**/dashboard") to wait for this navigation to complete.
5
waitForSelector — for dynamic content
When a React or Angular app loads data after the page opens, use page.waitForSelector(".product-card") to wait until products appear.
Debugging timeouts in Eclipse
When a test times out, Eclipse shows the full stack trace in the Failure Trace panel. Look for "Timeout" in the message — it tells you exactly which locator wasn't found.
Reading timeout errors in Eclipse
→
Click the failed test in the JUnit panel → look at Failure Trace below → find the line starting with TimeoutError
→
The error says which locator failed, e.g. Locator.click: Timeout 30000ms exceeded. Locator: getByRole("button", {name: "Submit"})
→
Open Chrome → go to the page → right-click → Inspect → confirm the button text is exactly "Submit" (not "Submit Form" or "SUBMIT")
→
To add a temporary debug print: add System.out.println(page.content()) before the failing line — Eclipse Console shows the full HTML so you can find the element
Auto-wait vs explicit wait — complete examples
// ✓ AUTO-WAIT (happens automatically — no code needed)
// Playwright checks: visible + stable + enabled before each action
page.getByRole(AriaRole.BUTTON,
  new Page.GetByRoleOptions().setName("Submit")).click();

// ✗ NEVER DO THIS — Thread.sleep is fragile and slow
// Thread.sleep(3000); // bad: always wastes 3 seconds

// ✓ EXPLICIT WAIT — for URL changes after navigation
page.getByRole(AriaRole.BUTTON,
  new Page.GetByRoleOptions().setName("Login")).click();
page.waitForURL("**/inventory.html");  // wait for redirect

// ✓ EXPLICIT WAIT — for dynamic content to appear
page.waitForSelector(".inventory_item");  // wait for products

// ✓ EXPLICIT WAIT — for all network activity to finish
page.waitForLoadState(LoadState.NETWORKIDLE);

// ✓ CHANGE TIMEOUT for one slow-loading element
page.getByText("Results loaded").waitFor(
  new Locator.WaitForOptions().setTimeout(10000)); // 10s just this once
15-min review
?
What are the 3 things Playwright checks before clicking an element?
?
When is it okay to use an explicit wait? Give a real example.
?
In Eclipse, where do you see the timeout error message when a test fails?
5
Core Skills · Session 5 of 10
Page Object Model (POM) — clean, maintainable tests
POM puts all locators in one class per page. When a button changes, you update one file instead of 20 tests. This is the single most important design pattern in automation.
Real-world analogy
A contact book. Instead of writing your friend's phone number in every message you send them, you store it in one place. If the number changes, you update it once. POM does the same for locators — store once, use everywhere.
Step-by-step — build a 2-page POM
1
Create a pages package in Eclipse
In Project Explorer → right-click src/test/java → New → Package → name it pages. All Page Object classes go here.
2
Create LoginPage.java in that package
Right-click the pages package → New → Class → name it LoginPage. Add the Page field, constructor, and action methods.
3
Create InventoryPage.java
Same steps. This page represents what you see after logging in — product list, cart button, etc.
4
Use both POMs in your test
new LoginPage(page).navigate().login("user","pass") — the test has no locators, just readable method calls. When locators change, only the page class changes.
Organizing packages in Eclipse Project Explorer
→
Right-click src/test/java → New → Package → name: pages → Finish
→
Right-click the pages package → New → Class → name: LoginPage → Finish
→
Create a separate package tests under src/test/java for your test classes. This keeps page objects and tests separate.
Eclipse shortcut — fix missing imports
When Eclipse shows a red underline on a class name, press Ctrl+Shift+O to auto-import all missing classes. This works perfectly with Playwright's many classes.
Recommended folder structure
src/test/java/ ├── pages/ │ ├── LoginPage.java │ ├── InventoryPage.java │ └── BasePage.java └── tests/ ├── LoginTest.java └── InventoryTest.java
src/test/java/pages/LoginPage.java
package pages;

import com.microsoft.playwright.*;
import com.microsoft.playwright.options.AriaRole;

public class LoginPage {

  private final Page page;

  // All locators in ONE place — easy to update when UI changes
  private final Locator username;
  private final Locator password;
  private final Locator loginBtn;

  public LoginPage(Page page) {
    this.page     = page;
    this.username = page.getByPlaceholder("Username");
    this.password = page.getByPlaceholder("Password");
    this.loginBtn = page.getByRole(AriaRole.BUTTON,
      new Page.GetByRoleOptions().setName("Login"));
  }

  public void navigate() {
    page.navigate("https://www.saucedemo.com");
  }

  // One clean method — hides all the locator details
  public void login(String user, String pass) {
    username.fill(user);
    password.fill(pass);
    loginBtn.click();
  }

  public String getErrorMessage() {
    return page.locator("[data-test='error']").textContent();
  }
}
src/test/java/tests/LoginTest.java — test using POM
package tests;

import com.microsoft.playwright.*;
import org.junit.jupiter.api.*;
import pages.LoginPage;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.*;

public class LoginTest {

  Playwright playwright;
  Browser    browser;
  Page       page;

  @BeforeEach
  void setUp() {
    playwright = Playwright.create();
    browser    = playwright.chromium().launch(
      new BrowserType.LaunchOptions().setHeadless(false));
    page       = browser.newPage();
  }

  @AfterEach
  void tearDown() {
    browser.close();
    playwright.close();
  }

  @Test
  void validLogin_succeeds() {
    LoginPage loginPage = new LoginPage(page);
    loginPage.navigate();
    loginPage.login("standard_user", "secret_sauce");
    assertThat(page).hasURL("https://www.saucedemo.com/inventory.html");
  }

  // Notice: no locators in the test — only readable method calls
}
15-min review
?
If the Login button's text changes from "Login" to "Sign In", how many files do you edit with POM vs without?
?
In Eclipse, what shortcut fixes the red underline on a missing import?
?
Write a 5-line LoginPage skeleton from memory — just the constructor and one method.
6
Core Skills · Session 6 of 10
Network interception & API testing
Playwright can make REST API calls directly — like Postman but in Java. It can also intercept browser network requests and return fake responses, which is perfect for testing error states.
Real-world analogy
Instead of going through the whole shop website to add a product to your database (10 clicks), you call the backend API directly (1 second), then open the shop page to verify it appears. Like using the staff entrance instead of queuing at the front.
Step-by-step
1
Make a direct GET API call
playwright.request().newContext() creates an API client. Call .get("/api/users") and check the status code — no browser needed.
2
Make a POST request with a body
Use request.post("/api/users", options.setData(...)) to create test data via API before your UI test runs.
3
Intercept & mock a browser request
page.route("**/api/products", route -> route.fulfill(...)) intercepts the browser's network call and returns your fake data. Great for testing loading states and error screens.
Viewing API responses in Eclipse Console
Add System.out.println(response.text()) after your API call. Eclipse's Console tab (bottom) shows the full JSON response — useful for debugging.
Using Maven to add Gson (JSON parser) in Eclipse
→
Open pom.xml → pom.xml tab → add the Gson dependency (from Code tab) → save → right-click project → Maven → Update Project
→
Use Ctrl+Shift+O in your test class to auto-import com.google.gson.JsonObject
Add Gson to pom.xml for JSON parsing
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.10.1</version>
</dependency>
Direct REST API call — no browser needed
@Test
void apiReturnsUsers() {
  try (Playwright pw = Playwright.create()) {
    APIRequestContext req = pw.request().newContext(
      new APIRequest.NewContextOptions()
        .setBaseURL("https://reqres.in")
    );

    APIResponse response = req.get("/api/users?page=1");
    assertEquals(200, response.status());

    // Print response in Eclipse Console
    System.out.println("Response: " + response.text());
  }
}
Intercept & fake an API response
@Test
void showErrorWhen_APIFails() {
  // Route ALL requests matching this URL pattern to our fake response
  page.route("**/api/products", route -> {
    route.fulfill(new Route.FulfillOptions()
      .setStatus(500)                   // fake a server error
      .setContentType("application/json")
      .setBody("{\"error\": \"Server down\"}"));
  });

  page.navigate("https://your-app.com/products");
  assertThat(page.getByText("Something went wrong")).isVisible();
}
15-min review
?
When is it faster to set up test data via API instead of clicking through the UI?
?
What does route.fulfill() do to the browser's network request?
?
In Eclipse Console, how do you print and see the full API response text?
7
Power Patterns · Session 7 of 10
Testing in multiple browsers
Playwright bundles Chrome, Firefox, and Safari — no separate downloads. One @ParameterizedTest annotation runs the same test on all 3 browsers automatically.
Real-world analogy
Printing the same document on 3 different printers — same document, different output. Same test, different browsers. Playwright's switch statement picks the right browser engine based on a string parameter.
Step-by-step
1
Know the 3 browser types
pw.chromium() = Chrome and Edge. pw.firefox() = Firefox. pw.webkit() = Safari. All bundled — you already installed them in session 1.
2
Use BrowserContext — not Browser — per test
BrowserContext is like an incognito window — fresh cookies, fresh storage. Create one per test so tests don't share login state.
3
Add @ParameterizedTest + @ValueSource
Replace @Test with @ParameterizedTest and add @ValueSource(strings = {"chromium","firefox","webkit"}). JUnit 5 runs the test 3 times — once per browser.
Reading parameterized test results in Eclipse
→
After running a @ParameterizedTest, the JUnit panel shows a tree: the method name expands to show 3 child rows — one per browser (chromium, firefox, webkit)
→
If webkit fails but chromium passes, click the webkit row to see the specific error — a Safari-only rendering bug
→
To run only one browser during development: change @ValueSource(strings = {"chromium"}) temporarily — run full suite before committing
Eclipse JUnit — Parameterized test results
▼ loginWorksOnAllBrowsers(String) ✓ [1] chromium 1.2s ✓ [2] firefox 1.8s ✓ [3] webkit 2.1s
Multi-browser parameterized test
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class MultiBrowserTest {

  @ParameterizedTest
  @ValueSource(strings = {"chromium", "firefox", "webkit"})
  void loginWorksOnAllBrowsers(String browserName) {
    try (Playwright pw = Playwright.create()) {

      // Pick browser engine from the parameter
      BrowserType bt = switch (browserName) {
        case "firefox" -> pw.firefox();
        case "webkit"  -> pw.webkit();  // Safari engine
        default        -> pw.chromium();
      };

      Browser        browser = bt.launch();
      // BrowserContext = fresh session, like incognito — use per test
      BrowserContext ctx     = browser.newContext();
      Page           page    = ctx.newPage();

      page.navigate("https://www.saucedemo.com");
      page.getByPlaceholder("Username").fill("standard_user");
      page.getByPlaceholder("Password").fill("secret_sauce");
      page.getByRole(AriaRole.BUTTON,
        new Page.GetByRoleOptions().setName("Login")).click();

      assertThat(page).hasURL("https://www.saucedemo.com/inventory.html");

      ctx.close();     // close context
      browser.close(); // close browser
    }
  }
}
15-min review
?
What is BrowserContext and why create a new one per test instead of reusing the Browser?
?
Which Playwright browser type engine tests Safari?
?
In Eclipse's JUnit panel, how do parameterized test results appear?
8
Power Patterns · Session 8 of 10
Debugging with Trace Viewer & screenshots
When tests fail in CI you can't see the browser. Playwright's Trace Viewer records every click, DOM state, and network request — replay it like a video to find any bug.
Real-world analogy
A plane's black box recorder. After a crash (test failure), engineers replay the recording to see exactly what happened — every instrument reading, every pilot action. Playwright's trace is that recording for your tests.
Step-by-step
1
Start tracing in @BeforeEach
Add context.tracing().start() with setScreenshots(true) and setSnapshots(true). Playwright records everything from this point forward.
2
Stop and save trace in @AfterEach
Call context.tracing().stop() with a path to save a .zip file. Always save — not just on failure — so you can review passing tests too.
3
Save screenshot on failure
In @AfterEach, check if the test threw an exception using TestInfo. If yes, save a full-page screenshot as PNG.
4
Open the trace from Eclipse
Right-click project → Run As → Maven build… → Goals: exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="show-trace traces/test.zip" → Run. A browser opens with the full trace viewer.
Opening Trace Viewer from Eclipse — exact steps
→
Right-click your project → Run As → Maven build…
→
In Goals, paste: exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="show-trace traces/your_test.zip"
→
Click Run. A Chrome window opens automatically with Playwright's Trace Viewer — an interactive timeline of every action
Finding trace files in Eclipse
Trace .zip files are saved relative to your project root. In Eclipse Project Explorer, press F5 to refresh — then expand the traces/ folder to see the files.
Complete @BeforeEach / @AfterEach with tracing + screenshots
import java.nio.file.Paths;
import org.junit.jupiter.api.*;

public class TracedTest {

  Playwright     playwright;
  Browser        browser;
  BrowserContext context;   // needed for tracing
  Page           page;

  @BeforeEach
  void setUp() {
    playwright = Playwright.create();
    browser    = playwright.chromium().launch();
    context    = browser.newContext();

    // Start recording everything
    context.tracing().start(new Tracing.StartOptions()
      .setScreenshots(true)   // capture screenshots
      .setSnapshots(true));   // capture DOM snapshots

    page = context.newPage();
  }

  @AfterEach
  void tearDown(TestInfo testInfo) {
    String name = testInfo.getDisplayName()
      .replaceAll("[^a-zA-Z0-9]", "_");

    // Always save trace — review if test fails
    context.tracing().stop(new Tracing.StopOptions()
      .setPath(Paths.get("traces/" + name + ".zip")));

    // Screenshot ONLY if test failed
    if (testInfo.getExecutionException().isPresent()) {
      page.screenshot(new Page.ScreenshotOptions()
        .setPath(Paths.get("screenshots/" + name + ".png"))
        .setFullPage(true));
    }

    context.close();
    browser.close();
    playwright.close();
  }

  @Test
  void exampleTracedTest() {
    page.navigate("https://www.saucedemo.com");
    assertThat(page).hasTitle("Swag Labs");
  }
}
15-min review
?
In Eclipse, which Maven goal command opens the Trace Viewer?
?
What 2 options do you enable in tracing.start() to capture full state?
?
How do you refresh Eclipse's Project Explorer to see newly created trace files?
9
Production · Session 9 of 10
CI/CD with GitHub Actions — tests run automatically
Push code to GitHub and your tests run automatically in the cloud — no human needed. This is how every professional team works. You set it up once, it runs forever.
Real-world analogy
Setting up a robot on a factory assembly line. You build the robot once (the YAML file) — it checks every product (every code push) automatically, 24/7, without you having to be there.
Step-by-step
1
Create a GitHub repository
Go to github.com/new → name it playwright-java-tests → Public → Create. This is where your code lives in the cloud.
2
Push your Eclipse project to GitHub
In Eclipse: right-click project → Team → Share Project → Git → select your repo → commit and push. Eclipse has a built-in Git panel.
3
Create the workflow file
In Eclipse, create the folder .github/workflows/ in your project root → create tests.yml inside it → paste the YAML from the Code tab → commit & push.
4
Watch tests run in GitHub
Go to your repo on github.com → click the Actions tab → you'll see tests running in the cloud. Green check = passed. Red X = failed.
Using Eclipse's built-in Git support
→
Right-click project → Team → Share Project… → select Git → check "Use or create repository in parent folder" → click "Create Repository" → Finish
→
Right-click project → Team → Commit… → the Git Staging panel opens → drag all files to "Staged Changes" → write a message → click Commit and Push
→
Enter your GitHub repository URL (https://github.com/yourname/playwright-java-tests.git) and your GitHub credentials
Creating .github/workflows in Eclipse
Eclipse doesn't show hidden folders by default. Create the folder via: right-click project → New → Folder → type .github → inside it create another folder workflows → inside that, New → File → name it tests.yml.
.github/workflows/tests.yml — paste this exactly
name: Playwright Tests

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Java 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Install Playwright browsers
        run: |
          mvn exec:java -e \
            -Dexec.mainClass=com.microsoft.playwright.CLI \
            -Dexec.args=install \
            --no-transfer-progress

      - name: Run all tests
        run: mvn test --no-transfer-progress

      - name: Upload screenshots on failure
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: failure-screenshots
          path: screenshots/
          retention-days: 7

      - name: Upload traces on failure
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: test-traces
          path: traces/
          retention-days: 7
15-min review
?
In Eclipse, what menu path do you use to commit and push code to GitHub?
?
In the YAML file, what does if: failure() mean on the upload step?
?
Where do you go in GitHub to see if the tests passed or failed?
10
Production · Session 10 of 10
Capstone — build your portfolio project
Use everything from sessions 1–9 to build a real 10-test suite for saucedemo.com with full POM, tracing, CI pipeline, and a GitHub badge. This is your proof of skill.
Real-world analogy
Your final open-book exam. All tools available, all notes allowed. The goal: a GitHub repo with a green CI badge you can show a hiring manager and say "I built this." That's your portfolio project.
Build your complete portfolio project
1
Plan 10 tests on paper — before touching code
Write plain English sentences: "User can log in with valid credentials." "Cart shows correct item count." Planning prevents wasted rework. 5 minutes planning saves 50 minutes debugging.
2
Create page objects in Eclipse
New Package pages → LoginPage, InventoryPage, CartPage, CheckoutPage. Each holds locators + action methods from session 5.
3
Write 10 tests using your POMs
Each test: 5–10 lines max. No locators inside tests — only method calls. Run each test in Eclipse as you write it — don't write all 10 then run.
4
Add tracing + screenshots from session 8
Copy your @BeforeEach/@AfterEach with tracing code. Every test gets recorded automatically.
5
Push to GitHub, make pipeline green
Commit and push from Eclipse → watch GitHub Actions → fix any failures → when all 10 pass, add a status badge to README.md. Done.
Running all 10 tests at once in Eclipse
→
Right-click the tests package → Run As → JUnit Test — runs every test class in the package at once
→
Or right-click the project → Run As → Maven test — same as running mvn test from the terminal
Adding a CI badge to README in Eclipse
→
Right-click project → New → File → name it README.md
→
Paste: ![Tests](https://github.com/YOUR_NAME/YOUR_REPO/actions/workflows/tests.yml/badge.svg) — replace YOUR_NAME and YOUR_REPO
→
Commit and push — the badge appears on your GitHub repo page showing green (passing) or red (failing) in real time
Eclipse — Final Project Structure
playwright-java-tests/ ├── .github/workflows/tests.yml ├── src/test/java/ │ ├── pages/ │ │ ├── BasePage.java │ │ ├── LoginPage.java │ │ ├── InventoryPage.java │ │ ├── CartPage.java │ │ └── CheckoutPage.java │ └── tests/ │ ├── AuthTest.java (3 tests) │ ├── InventoryTest.java (3 tests) │ └── CheckoutTest.java (4 tests) ├── pom.xml └── README.md ← add CI badge here
Your 10 test plan — write these as plain text first
// AUTH TESTS — 3
1. validLogin_redirectsToInventory()
2. invalidPassword_showsErrorMessage()
3. lockedUser_showsLockedMessage()

// INVENTORY TESTS — 3
4. inventoryPage_showsProducts()
5. sortByPriceLowToHigh_works()
6. addToCart_updatesCartBadgeCount()

// CART & CHECKOUT TESTS — 4
7. addItem_appearsInCart()
8. removeItem_removesFromCart()
9. checkout_completesSuccessfully()
10. checkout_failsWithoutAddress()
README.md — add CI badge (replace YOUR_NAME and YOUR_REPO)
# Playwright Java Test Suite

![Tests](https://github.com/YOUR_NAME/YOUR_REPO/actions/workflows/tests.yml/badge.svg)

A complete Playwright + Java automation suite using:
- Eclipse IDE
- Maven
- JUnit 5
- Page Object Model
- GitHub Actions CI

## Running locally in Eclipse
Right-click project → Run As → JUnit Test
Final review — you're done when you can say YES to all 3
?
Can you clone the project to a new machine, run it in Eclipse, and get all 10 tests green in under 10 minutes?
?
Is there a green CI badge on your GitHub README that updates automatically?
?
If a test fails, can you open the trace file from Eclipse and identify the failing step?