Testing Web Apps Using Playwright: POM Structure and Key Commands Explained
- Sumalatha Thumula
- May 1, 2025
- 4 min read
In the previous blog Part 1, we discussed how to get started with Playwright. We covered:
Installing Node.js and Playwright
Understanding the basic project folder structure
Creating spec files for tests
Importing @playwright/test
Using the test block with async and await (used in every Playwright spec)
Running test cases with Playwright CLI commands
Now, in this part, we'll explore more features and how Playwright simplifies application validation compared to other tools like Selenium.
Understanding package.json in Playwright Projects
Every Node.js project, including Playwright-based automation frameworks, relies on a package.json file. This file serves as the blueprint of your project, defining dependencies, scripts, project metadata, and more.
It's used by npm to manage your packages.
It allows team members to run the same test commands across environments.
It simplifies CI/CD integration by providing standardized script hooks.
When you run npm install, Node looks at package.json and installs everything listed under dependencies and devDependencies.
Project Structure and Page Object Model

I have created a project named DSALGOPLAYWRIGHT. Here's how the structure looks:
tests/ folder contains:
registration.spec.js
login.spec.js
home.spec.js
pages/ folder contains Page Object Models:
registrationPage.js
loginPage.js
homePage.js

Just like Selenium, where we store the base URL in a config file, Playwright allows us to set the base URL in playwright.config.js.
Login Page: Page Object
In the loginPage.js file, we encapsulate all login-related interactions:

In the loginPage.js, all page interactions related to the login process are encapsulated. The constructor takes the page object (provided by Playwright's test runner) and initializes the page elements:
usernameField: Represents the username input field (selector: "#id_username")
passwordField: Represents the password input field (selector: "#id_password")
loginButton: Represents the login button (selector: input element with value 'Login')
page.locator()
A locator is used to find and interact with elements efficiently.
Locators are more powerful than page.$ because they automatically wait for elements to appear and be ready.
The fillLoginForm(username, password) method fills the login form using await, which ensures fields are ready before interaction. The submitLogin() method clicks the login button.
The line module.exports = LoginPage; is a Node.js syntax used to export the class so it can be reused in other files — just like making it public.
Validating Login(login.spec.js)

const { test, expect } = require('@playwright/test');
const LoginPage = require('../pages/loginPage');
test('User can log in successfully', async ({ page }) => {
const loginPage = new LoginPage(page);
await page.goto('/login');
// Fill in the login form
await loginPage.fillLoginForm('Ram@gmail.com', 'Tester123$');
// Submit the login form
await loginPage.submitLogin();
// Validate successful redirection to the home page
await expect(page).toHaveURL('/home');
});
We import Playwright testing functions (test, expect) and the LoginPage POM from the pages folder.
We define a test case "User can log in successfully":
page is injected by Playwright Test runner, giving a fresh browser tab.
An object of the LoginPage class is created using the page object.
page.goto('/login') navigates to the login page (relative to baseURL).
fillLoginForm() and submitLogin() methods are used from the LoginPage class.
Finally, expect(page).toHaveURL('/home') asserts that the user is redirected to the home page after successful login.
If the URL isn’t /home, Playwright will automatically retry for a few seconds — built-in smart waiting.
Okay now I want to do a comparison between selenium and playwright commands for important actions like finding elements, clicking, typing, waiting, and assertions.
Selenium vs Playwright: Command Comparison
Here’s a handy side-by-side comparison of common tasks in Selenium (Java) vs. Playwright (JavaScript):
Action | Selenium (Java) | Playwright (JS) |
Launch page | driver.get("https://...") | await page.goto('https://...') |
Find element | driver.findElement(By.id("user")) | page.locator('#user') |
Type input | el.sendKeys("abc") | await locator.fill("abc") |
Click button | e.click() | await locator.click() |
Wait for element | WebDriverWait + ExpectedConditions | await locator.waitFor() (auto-wait built-in) |
URL assertion | Assert.assertEquals(driver.getCurrentUrl(), "...") | await expect(page).toHaveURL('/home') |
Text assertion | Assert.assertEquals(el.getText(), "...") | await expect(locator).toHaveText('...') |
Playwright Command Cheat Sheet
Here's a Playwright Command Cheat Sheet covering the most commonly used and useful commands for web automation using JavaScript/TypeScript (@playwright/test framework):
Navigation
await page.goto('https://example.com'); // Navigate to URL
await page.reload(); // Reload the page
await page.goBack(); // Go back in browser history
await page.goForward(); //Go forward in browser history Element Selection
const locator = page.locator('selector'); // Create a locator
const button = page.locator('button#submit'); // Example locatorInput Actions
await locator.fill('value'); // Clear + Type value
await locator.type('value'); // Type value (no clear)
await locator.press('Enter'); // Press a key
await locator.click(); // Click an element
await locator.dblclick(); // Double-click
await locator.check(); // Check checkbox
await locator.uncheck(); // Uncheck checkbox
await locator.selectOption('value'); // Select dropdown optionScreenshots
await page.screenshot({ path: 'screenshot.png' }); // Full page
await locator.screenshot({ path: 'element.png' }); // Element onlyFrames and IFrames
const frame = page.frame({ name: 'frameName' }); // By name
const frame = page.frameLocator('#frameID'); // By selector
await frame.locator('selector').click(); // Interact insideAssertions
await expect(page).toHaveURL('https://...'); // Assert page URL
await expect(locator).toHaveText('Hello'); // Assert text content
await expect(locator).toBeVisible(); // Assert visibility
await expect(locator).toHaveValue('abc'); // Assert input value
await expect(locator).toHaveAttribute('type','submit');// Assert attribute
Conclusion
Playwright simplifies end-to-end testing by reducing boilerplate code, handling automatic waits, and integrating powerful features like its own test runner, assertion library, and screenshot capabilities.
If you're already familiar with Selenium, transitioning to Playwright can significantly improve your test speed, stability, and maintainability, making it an ideal tool for modern web application validation.
"Validation is not just about checking if it works — it's about proving that it works every time. With Playwright, reliability meets simplicity in modern web testing."

