Who Is This Course For?
This course is designed for Java and Selenium engineers who are ready to adopt Playwright — Microsoft's modern, next-generation browser automation framework. You will master the full Playwright Java API, build a production-grade POM framework, integrate TestNG and ExtentReports, handle real-world test challenges, and leave with a complete, GitHub-hosted framework ready for your portfolio.
- Playwright — free, open-source Microsoft framework (2020); supports Chromium, Firefox, WebKit from one API
- Key advantages: built-in auto-waiting, network interception, Trace Viewer, no driver manager needed
- Creating a Maven project; adding
com.microsoft.playwrightdependency topom.xml
Playwright.create()→playwright.chromium().launch()→browser.newContext()→context.newPage()LaunchOptions:setHeadless(false)to run with a visible browser window- Try-with-resources pattern — auto-closing Playwright, Browser, and Page objects
- Static vs non-static variables and methods — class-level shared state vs instance-level state
- Constructor chaining with
this();this.keyword to differentiate instance and local variables - Inheritance and
super— used inBaseTestpattern across the full framework
@FunctionalInterface— interfaces with exactly one abstract method; lambda shorthand- Lambda syntax:
(params) -> expression; used inpage.frameByUrl(url -> url.contains("...")) - Built-in functional types:
Predicate<T>,Consumer<T>,Function<T,R>,Supplier<T>
page.navigate("url")— load a URL;page.goBack()/page.goForward()/page.reload()page.title(),page.url(),page.content()— read back page informationpage.close()/browser.close();page.waitForTimeout(ms)— hard wait (use sparingly)- Multiple browser contexts — isolated sessions with separate cookies and storage state
page.getByLabel("text"),page.getByPlaceholder("text"),page.getByAltText("text")page.getByTitle("text"),page.getByText("text"),page.getByTestId("id")page.getByRole(AriaRole.BUTTON)— ARIA role-based locator;GetByRoleOptions.setName("label")page.locator("selector")— CSS or XPath;LocatorOptions.setExact(true)for exact matchingpage.pause()— opens Playwright Inspector for live locator debugging in the browser
locator.first(),locator.nth(index),locator.last()— target a specific matchlocator.all()— returnsList<Locator>; iterate all matching elements in a loop
#id— ID selector;.class— class selector;tag— element typetag[attribute='value']exact match;^=starts-with;*=contains;$=ends-with- Combining:
tag.class#id[attr='val']— all conditions on the same element - Relational:
parent child(descendant),parent > child(direct child),+adjacent sibling - Pseudo-classes:
:nth-child(n),:first-child,:last-childfor positional targeting
- Relative XPath:
//tag[@attribute='value']— robust, preferred over absolute paths contains(@attr,'partial'),starts-with(@attr,'prefix'),ends-with(@attr,'suffix')//tag[text()='exact text']— match by visible text content- Logical operators:
and,or,not()in predicates
- Index:
(//tag[@attr='val'])[1]— select nth occurrence (1-based indexing) - Parent navigation:
//child/../sibling— move up the DOM tree to find siblings - Axes:
following-sibling::tag,preceding-sibling::tag,ancestor::tag - Using XPath in Playwright:
page.locator("xpath=//...")with explicit prefix
locator.fill("text")— clear and type;locator.press("Enter"),"Tab","ArrowDown"locator.click(),locator.dblClick(),locator.hover(),locator.clear()locator.check()/locator.uncheck();locator.dragTo(targetLocator)
locator.isChecked(),locator.isDisabled(),locator.isEnabled(),locator.isVisible()locator.getAttribute("name"),locator.textContent(),locator.innerText(),locator.innerHTML()locator.boundingBox()— returns{x, y, width, height}for position calculationslocator.screenshot()— capture a screenshot of just this elementpage.onceDialog(dialog -> dialog.accept())— handle JS alert / confirm / prompt pop-ups
page.frame("frameName")— access by name attribute; returnsFrameobjectpage.frameLocator("#frameId")— access by CSS selector; returnsFrameLocatorpage.frameByUrl(url -> url.contains("part"))— access by URL pattern using lambda- Chain locators inside frame:
frameLocator.locator("input").fill("text") - Nested iFrames:
frameLocator().frameLocator()— chain multiple levels
selectOption()locator.selectOption("visibleText")— select by label;.setValue("val")by value attribute.setIndex(2)— select by position;.setLabel("label")— select by label attribute- Multi-select: passing an array of values; limitations with non-standard controls
page.evaluate("JS expression")— run JavaScript in the browser; return value to Java- Passing Java values into JS:
page.evaluate("(val) => document.getElementById('id').value = val", "text") - Reading JS values:
(String) page.evaluate("window.location.href")
locator.scrollIntoViewIfNeeded()— auto-scroll element into the visible viewportpage.mouse().wheel(deltaX, deltaY)— programmatic mouse wheel scroll up/down/left/right- Scroll to bottom:
page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
page.setDefaultTimeout(ms)— global timeout for all actions;setDefaultNavigationTimeout(ms)for navigation- Playwright auto-waiting — built-in retries on actionability (visible, enabled, stable) before every action
page.waitForTimeout(ms)— hard wait; avoid except as last resort
locator.waitFor()— waits until locator is actionable;page.waitForSelector("css")page.waitForURL("url");page.waitForLoadState(LoadState.NETWORKIDLE)page.waitForPopup()/page.waitForClose()— sync with new windowspage.waitForCondition(BooleanSupplier)— custom condition waitpage.waitForDownload();page.waitForFileChooser();page.waitForFunction("JS")assertThat(locator).isVisible()— Playwright assertion; retries for 5 seconds by default
@Test:priority,enabled,groups,dependsOnMethods- Lifecycle:
@BeforeSuite,@BeforeTest,@BeforeClass,@BeforeMethod→ test runs →@AfterMethod,@AfterClass,@AfterTest,@AfterSuite testng.xml— suite config;Reporter.log("msg")→ appears in emailable-report.html
@DataProvider(name="dp")+@Test(dataProvider="dp")— run one test with multiple data rows@Parameters({"param"})— read environment/browser fromtestng.xml- Parallel:
parallel="methods"/"classes"/"tests"intestng.xml - Groups:
include,exclude,alwaysRun=true
Assert.assertEquals(actual, expected)— hard assert; stops test on first failureSoftAssert sa = new SoftAssert();sa.assertAll()— collect all failures, report together- Re-run failed tests using
surefire-reports/testng-failed.xml
ExtentSparkReporter— HTML report path and theme;ExtentReports.attachReporter()extent.createTest("name")— create test entry;test.pass(),test.fail(),test.skip(),test.info()- Attach screenshot on failure:
test.fail(MediaEntityBuilder.createScreenCaptureFromPath("path").build()) - Static vs non-static placement of
ExtentReportsobject in@BeforeSuite/@AfterSuite
config.properties— browser, URL, credentials outside code;Properties.load(FileInputStream),p.getProperty("key")- Apache POI:
poiandpoi-ooxmlMaven dependencies XSSFWorkbook→XSSFSheet→XSSFRow→XSSFCell.getStringCellValue()- Loop Excel rows into
@DataProviderfor fully data-driven test execution
npx playwright install— install browsers on the server machinenpx playwright run-server --port=7777— start remote WebSocket serverplaywright.chromium().connect("ws://hostname:7777")— connect Java client to remote servernpx playwright show-trace trace.zip— open Trace Viewer for step-by-step test debugging
- BrowserStack:
playwright.chromium().connect("wss://cdp.browserstack.com/...")with username + access key - MCP (Microsoft Cloud Playwright) — fully managed, no infrastructure to maintain
- Parallel cloud execution — cross-browser, cross-OS matrix in a single test run
- Manual test case → automation: page → elements → actions mapping strategy
- Page classes:
LoginPage,HomePageetc.; constructor acceptingPageobject BaseTestclass with shared@BeforeSuite,@BeforeMethod,@AfterMethod,@AfterSuite- Test classes extend
BaseTest— inherit browser setup/teardown; focus only on test logic
@BeforeSuite— initialiseExtentSparkReporter+ExtentReports; createPlaywrightinstance@BeforeMethod— readconfig.properties; launch browser;setDefaultTimeout(); navigate to URL@Test— read Excel via POI; call POM page methods;Assertresults; log toExtentTest@AfterMethod— screenshot on failure; closepage+browser; save video if enabled@AfterSuite—extent.flush()to write HTML report; closeplaywright
- Create GitHub repo with
.gitignorefor Java/Maven; generate personal access token - Eclipse Team/Git:
Team > Share Project; push toorigin main - Import from GitHub:
Import > Git > Projects from Git
Playwright vs Selenium — Auto-waiting, Page replaces WebDriver, built-in assertions, no driver manager, network mocking out of the box
Locator Priority — getByRole → getByLabel → getByTestId → CSS → XPath. Most resilient to UI changes first
Wait Strategy — Playwright auto-waits before every action; waitForTimeout only as absolute last resort; prefer waitFor() or assertThat()
Framework Design — BaseTest for setup/teardown, page classes for each screen, config.properties for env, Excel for data, ExtentReports for visibility
iFrame Handling — frameLocator() returns a FrameLocator; chain locators directly; no need for switchTo().frame() like in Selenium
Cloud Testing — One-line change: playwright.chromium().connect("wss://...") replaces local launch; BrowserStack or MCP for cross-browser matrix