Here's a carefully curated list of possible Playwright + Java interview questions, including:
-
✅ Core Java (OOPs, exceptions, etc.)
-
✅ Playwright automation
-
✅ TestNG framework
-
✅ BDD with Cucumber
-
✅ Bonus: Code snippets, concepts, and real-life scenarios
Let’s go! ๐ฅ
๐ Playwright + Java Automation – Interview Q&A
1. What is Playwright and how is it different from Selenium?
✅ Answer:
Playwright is a modern automation library for web apps that supports multiple languages (Java, JavaScript, Python, etc.).
It supports:
-
Multiple browsers (Chromium, Firefox, WebKit)
-
Auto-waiting
-
Headless/headful mode
-
Native support for iframes, tabs, and download uploads
-
Built-in screenshot/video capabilities
๐ Unlike Selenium:
2. How do you launch a browser and open a page in Playwright Java?
✅ Code Example:
Playwright playwright = Playwright.create();
Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
Page page = browser.newPage();
page.navigate("https://example.com");
3. How do you locate elements in Playwright Java?
✅ Answer:
๐ Example:
Locator loginBtn = page.locator("#login-button");
loginBtn.click();
4. How do you handle dropdowns in Playwright?
page.selectOption("#dropdown-id", new SelectOption().setLabel("Option 1"));
5. How to capture a screenshot?
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshot.png")));
๐งช TestNG + Playwright
6. How do you integrate Playwright with TestNG?
✅ Answer:
Create a base class with setup/teardown methods using @BeforeClass
, @AfterClass
, and write test methods using @Test
.
✅ Code Sample:
@BeforeClass
public void setup() {
playwright = Playwright.create();
browser = playwright.chromium().launch();
page = browser.newPage();
}
@Test
public void testLogin() {
page.navigate("https://example.com");
page.fill("#username", "admin");
page.fill("#password", "pass");
page.click("#loginBtn");
}
7. How do you take a screenshot on failure in TestNG?
@AfterMethod
public void tearDown(ITestResult result) {
if (ITestResult.FAILURE == result.getStatus()) {
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshots/" + result.getName() + ".png")));
}
}
๐งพ Java + OOPs Interview Questions
8. Explain OOPs Concepts in Java (with real test example)?
✅ Answer:
-
Encapsulation: Page classes hold locators and actions.
-
Inheritance: BaseTest
class is extended by test classes.
-
Polymorphism: Method overloading in utility classes.
-
Abstraction: Interface for Page layer.
9. What’s the difference between ArrayList
and LinkedList
?
✅ Answer:
-
ArrayList
: Fast for retrieval, slower for inserts/removals
-
LinkedList
: Faster for insertions/removals, slower for retrieval
10. What are checked vs unchecked exceptions?
✅ Answer:
๐ง BDD with Cucumber + Java + Playwright
11. How do you implement BDD in Java with Playwright?
✅ Answer:
12. Sample Feature File
Feature: Login functionality
Scenario: Successful login
Given I open the login page
When I enter valid credentials
Then I should see the homepage
13. Step Definition Example
@Given("I open the login page")
public void openLoginPage() {
page.navigate("https://example.com/login");
}
14. How do you share Playwright context between steps?
✅ Answer:
Use a TestContext
or Hooks
class to store and share browser/page instances.
⚙️ Real-World Scenarios
15. How do you handle pop-ups or alerts?
page.onDialog(dialog -> {
System.out.println("Alert Text: " + dialog.message());
dialog.accept();
});
16. How do you handle multiple windows or tabs?
Page newPage = context.waitForPage(() -> {
page.click("#open-new-tab");
});
newPage.bringToFront();
17. How do you wait for an element in Playwright?
page.waitForSelector("#element-id", new Page.WaitForSelectorOptions().setTimeout(5000));
18. How do you verify an element is visible and enabled?
boolean isVisible = page.locator("#submit").isVisible();
boolean isEnabled = page.locator("#submit").isEnabled();
19. Playwright’s default timeout? Can it be changed?
✅ Default: 30 seconds
✅ Override:
page.setDefaultTimeout(10000); // 10 seconds
20. Playwright test best practices
21. Please provide all the possible methods for page.
Navigation & Page Control
navigate(): page.navigate("https://example.com");
reload(): page.reload();
goBack(): page.goBack();
goForward(): page.goForward();
title(): String title = page.title();
url(): String url = page.url();
Element Interaction
click(): page.click("#login");
fill(): page.fill("#username", "admin");
type(): page.type("#search", "Playwright");
press(): page.press("#input", "Enter");
check(): page.check("#accept");
uncheck(): page.uncheck("#accept");
selectOption(): page.selectOption("#country", "India");
dblclick(): page.dblclick(".item");
hover(): page.hover("#menu");
Locators
locator(): Locator button = page.locator("#submit");
getByText(): page.getByText("Login");
getByRole(): page.getByRole(AriaRole.BUTTON);
Assertions and State
Playwright Java - Page Methods Cheat Sheet
isVisible(): page.locator("#msg").isVisible();
isEnabled(): page.locator("#submit").isEnabled();
isChecked(): page.locator("#accept").isChecked();
textContent(): page.locator(".info").textContent();
innerText(): page.locator("#header").innerText();
inputValue(): page.locator("#email").inputValue();
Waits and Synchronization
waitForSelector(): page.waitForSelector("#done");
waitForTimeout(): page.waitForTimeout(3000);
waitForLoadState(): page.waitForLoadState(LoadState.NETWORKIDLE);
waitForURL(): page.waitForURL("**/dashboard");
Screenshots & PDF
screenshot(): page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("shot.png")));
pdf(): page.pdf(new Page.PdfOptions().setPath(Paths.get("page.pdf")));
Frames and Popups
frame(): Frame frame = page.frame("myFrame");
waitForPopup(): Page popup = page.waitForPopup(() -> page.click("#link"));
File Upload & Download
setInputFiles(): page.setInputFiles("#file", Paths.get("data.txt"));
waitForDownload(): Download download = page.waitForDownload(() -> { page.click("#download-btn"); });
download.saveAs(Paths.get("myfile.zip"));
Dialogs / Alerts
onDialog(): page.onDialog(dialog -> {
Playwright Java - Page Methods Cheat Sheet
System.out.println(dialog.message());
dialog.accept();
});
Others
evaluate(): page.evaluate("() => alert('Hi')");
addInitScript(): page.addInitScript("console.log('Script added')");
close(): page.close();
22. Parallel execution with Playwright with java.
1. TestNG Parallel Execution (Recommended)
Playwright + TestNG combo is super effective for parallel tests.
๐ Step-by-Step:
a. Update testng.xml
to enable parallel test classes or methods:
-
parallel="classes"
: Runs each class in a separate thread
-
parallel="methods"
: Runs each test method in a separate thread
-
thread-count
: Number of threads to run in parallel
b. Make sure your browser context is thread-safe:
Use ThreadLocal
or independent instances of Playwright
, Browser
, and Page
in each test.
๐ Example (Thread-safe setup):
Then in your test class, use:
✅ 2. Cucumber + TestNG Parallel Execution (Feature files in parallel)
Want a full example with Cucumber + Playwright + TestNG parallel setup? Let me know!
✅ 3. Custom Java ExecutorService (Advanced)
You can manually create threads to execute different test classes or cases in parallel using Java’s ExecutorService
.
22. Element locating techniques if you are using java and playwright.
Perfect — you're using Playwright with Java and want to know how to locate elements, including in complex scenarios like tables, nested elements, loops, and even Shadow DOM.
Let’s go step-by-step, from basic to advanced ⤵️
๐น 1. Basic Locators in Playwright Java
page.locator("#username").fill("admin");
page.locator(".btn-primary").click();
page.locator("input[name='email']").type("user@example.com");
✅ Supports CSS selectors, text selectors, and built-in queries.
๐น 2. Text Selectors
page.locator("text=Submit").click(); // Exact or partial match
๐น 3. Label Selectors
page.getByLabel("Email").fill("test@example.com");
๐น 4. Role Selectors (ARIA)
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Login")).click();
๐น 5. Placeholder Selectors
page.getByPlaceholder("Enter your name").fill("John Doe");
๐น 6. Table Elements (Complex Table Lookups)
Assume this HTML:
<table>
<tr>
<td>Name</td>
<td>Email</td>
</tr>
<tr>
<td>John</td>
<td>john@example.com</td>
</tr>
</table>
๐ Locate by Cell Text:
Locator row = page.locator("table tr", new Locator.LocatorOptions().setHasText("John"));
String email = row.locator("td:nth-child(2)").textContent();
System.out.println("Email: " + email);
๐น 7. Nested Element (DOM Tree Traversal)
<div class="card">
<div class="header">User Info</div>
<div class="content">
<span>Name:</span>
<span>John Doe</span>
</div>
</div>
๐ Java Locator:
Locator card = page.locator(".card", new Locator.LocatorOptions().setHasText("User Info"));
String name = card.locator(".content span:nth-of-type(2)").textContent();
System.out.println("Name: " + name);
๐น 8. Loop Over Multiple Elements (List/Repeater)
<ul>
<li class="user">Alice</li>
<li class="user">Bob</li>
<li class="user">Charlie</li>
</ul>
๐ Java Code:
Locator users = page.locator("li.user");
int count = users.count();
for (int i = 0; i < count; i++) {
System.out.println("User: " + users.nth(i).textContent());
}
๐น 9. Shadow DOM Handling
<custom-element>
#shadow-root
<input id="shadow-input" />
</custom-element>
๐ Java Code:
Playwright handles shadow DOM automatically when using locator()
:
page.locator("custom-element >> shadow=#shadow-input").fill("Inside Shadow DOM");
✅ The >> shadow=
syntax pierces the shadow root.
๐น 10. Advanced Nested Table with Actions
<table>
<tr>
<td>John</td>
<td><button>Edit</button></td>
</tr>
</table>
๐ Click the "Edit" button for "John"
Locator row = page.locator("tr", new Locator.LocatorOptions().setHasText("John"));
row.locator("button").click();
๐น BONUS: Combine Multiple Conditions
// Find a visible input with class and placeholder
page.locator("input.visible-input[placeholder='Search']:not([disabled])").fill("Playwright");
⚙️ Tools to Help
-
Use npx playwright codegen
(even with Java!) to get a head start on selectors.
-
Use page.locator("selector").highlight()
during debugging (JS only — in Java you can debug with .screenshot()
or log outputs).
23. Any difference when you define lcoator when you use playwright with java or playwright with typescript?
Great question! ๐ก
Yes, there are some differences in how you define and use locators in Playwright when using Java vs. TypeScript, but the core concepts remain the same.
✅ What's the Same?
Concept |
Java |
TypeScript |
CSS selectors |
✅ page.locator("div.class") |
✅ page.locator("div.class") |
Text selectors |
✅ text=Login |
✅ text=Login |
Shadow DOM |
✅ >> shadow= syntax |
✅ >> shadow= syntax |
Locator chaining |
✅ .locator(...).locator(...) |
✅ .locator(...).locator(...) |
ARIA roles / semantic queries |
✅ getByRole(...) |
✅ getByRole(...) |
The underlying selector engine and logic is the same.
๐ What’s Different Between Java and TypeScript?
Here are the key differences ๐
1. Method Syntax / API Style
๐น Java:
Locator button = page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Submit"));
๐น TypeScript:
const button = page.getByRole('button', { name: 'Submit' });
✅ Same logic — Java is just more verbose due to types and method chaining.
2. Options & Locators
-
In Java, you explicitly create options classes like:
new Locator.LocatorOptions().setHasText("User")
-
In TypeScript, you just pass a JS object:
locator("tr", { hasText: "User" })
3. Asynchronous Handling
-
TypeScript is async — almost every Playwright action is await
ed.
await page.click('text=Login');
-
Java is synchronous-like — most methods block until complete.
page.locator("text=Login").click();
But both do auto-waiting behind the scenes.
4. Code Completion & Language Features
-
TypeScript has more fluid intellisense for Playwright APIs.
-
Java needs more manual config (e.g., setting up Maven/Gradle and imports).
-
TypeScript can use playwright.config.ts to configure projects easily.
5. Test Runner Integration
Feature |
TypeScript |
Java |
Built-in test runner |
✅ @playwright/test |
❌ (uses JUnit/TestNG manually) |
Parallel testing |
✅ native |
✅ with test framework |
Fixtures |
✅ built-in |
❌ (you create with setup/teardown) |
๐งช Example Comparison: Fill Email Field
๐จ Java:
page.getByLabel("Email").fill("user@example.com");
๐ฆ TypeScript:
await page.getByLabel('Email').fill('user@example.com');
Same result — just different flavor.
๐ Summary
Feature |
Java |
TypeScript |
Verbose syntax |
✅ Yes (OO-style) |
❌ Shorter, cleaner |
Async handling |
Blocking (sync-like) |
Async with await |
Options/Configs |
Needs classes |
Just pass JS objects |
Test runner |
Use JUnit/TestNG manually |
Built-in @playwright/test runner |
Intellisense |
IDE-dependent |
Superb in VS Code |
24. What is fixtures in playwright? (this was asked in coforge interview)
answer: https://playwright.dev/docs/api/class-fixtures
Fixtures are a set of resources that have to be set up before and cleaned up
Answer: Fixtures in Playwright are a mechanism for setting up and managing the environment and resources required by tests. They promote reusability, reduce code duplication, and improve test organization. Fixtures can provide resources like browser instances, pages, API contexts, or custom objects, ensuring each test has the necessary dependencies without manual setup. They also handle automatic cleanup after the test execution.
Playwright offers built-in fixtures like page
, browser
, context
, and request
, and also allows users to create custom fixtures for specific needs. Fixtures can be defined at different scopes (test, worker, suite) to control their lifecycle and sharing behavior. This enables efficient management of test dependencies and ensures test isolation.
from chatgpt:
Here’s a quick breakdown of the top features of Playwright, especially useful when evaluating or switching from other frameworks like Selenium:
๐ Key Playwright Features
Feature |
Description |
๐ฏ Cross-Browser Support |
Test against Chromium, Firefox, and WebKit using the same API. Great for real-world coverage. |
๐งญ Auto-Waiting |
Automatically waits for elements to be visible/stable before interacting. Reduces flaky tests. |
⚡ Fast Execution |
Executes faster than Selenium thanks to direct browser protocol bindings (no WebDriver). |
๐ต️♂️ Headless & Headed Modes |
Easily switch between headless and headed mode for CI/local debugging. |
๐งช Built-in Test Runner |
@playwright/test includes built-in test runner, assertions, parallelism, and fixtures. |
๐ Parallel Execution |
Supports parallel test execution out of the box using workers. |
๐ฆ Browser Contexts |
Create isolated sessions for each test — no need to restart the browser. |
๐ธ Screenshots & Videos |
Capture screenshots, videos, and even full test traces (great for debugging). |
๐ Network Interception |
Intercept, mock, or modify network requests/responses — ideal for testing without real APIs. |
๐ Powerful Selectors |
Use CSS, XPath, text, role, label, and even custom selectors (page.getByRole() , getByText() ). |
๐ Multi-language Support |
Official support for JavaScript, TypeScript, Python, Java, and C#. |
๐ Authentication Handling |
Can reuse and persist login sessions using storageState , speeding up login-heavy test suites. |
๐งฉ Custom Fixtures |
Easily set up and tear down test environments or data using fixtures. |
๐ ️ Example Feature in Use: Auto-waiting
await page.click('button#submit'); // Waits for the button to be attached, visible, enabled
await expect(page.locator('text=Success')).toBeVisible(); // Waits for the success message
In Playwright, fixtures are a powerful way to manage setup and teardown logic across your tests. They help you share context, initialize resources, and reuse logic—cleanly and efficiently.
๐งฉ What Are Fixtures in Playwright?
Fixtures in Playwright Test are reusable building blocks that provide:
๐ง Default Fixture Example
Playwright provides built-in fixtures like page
, browser
, and context
.
import { test, expect } from '@playwright/test';
test('basic test with default page fixture', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveTitle(/Example/);
});
Here, page
is a built-in fixture.
๐ ️ Custom Fixture Example
Let’s say you want a logged-in user fixture:
// fixtures.ts
import { test as base } from '@playwright/test';
type MyFixtures = {
loggedInPage: typeof base extends { page: infer P } ? P : never;
};
export const test = base.extend<MyFixtures>({
loggedInPage: async ({ page }, use) => {
await page.goto('https://example.com/login');
await page.fill('#username', 'admin');
await page.fill('#password', 'password123');
await page.click('button[type="submit"]');
await use(page); // pass the page to the test
}
});
Use the Fixture in Your Test:
// login.spec.ts
import { test, expect } from './fixtures';
test('dashboard is visible for logged-in user', async ({ loggedInPage }) => {
await expect(loggedInPage.locator('text=Dashboard')).toBeVisible();
});
๐ฆ Benefits of Fixtures
-
Modular: Avoids repeating setup/teardown code.
-
Efficient: Shared setup (like DB connections or login).
-
Clean: Keeps your tests readable and concise.
-
Composable: Combine multiple fixtures for complex scenarios.
Would you like help writing a fixture for something specific like API mocking, database prep, or a custom login flow?
25. What is browser context in playwright? (this was asked in HCL interview)
https://playwright.dev/docs/api/class-browsercontext
Answer: In Playwright, a browser context is a separate, isolated environment within a browser instance. It's akin to a new, incognito profile within a browser, offering a clean slate for running tests or scenarios without interference from other contexts or browser sessions.
Isolation:
Browser contexts provide data isolation, meaning they have their own cookies, local storage, cache, and other browsing data, preventing them from affecting each other. Incognito-like Profiles:
They function similarly to incognito mode in browsers, creating a new, fresh session for each context. Multiple User Sessions:
Browser contexts are useful for simulating multiple users or user roles within the same browser, especially in testing scenarios. Test Isolation:
They are essential for ensuring tests don't interfere with each other, allowing for parallel testing and reliable results. Flexible Settings:
You can customize settings like viewport, geolocation, and other browser-specific options for each context.
- Creation: Browser contexts are created using the
browser.newContext()
method, as seen in the Playwright Java documentation. - Pages: Within a context, you can create multiple pages (tabs or popup windows).
- Context Closure: When you're done with a context, you should close it using
context.close()
, as seen in the Playwright Java documentation.
Parallel Testing:
Run multiple tests in different contexts concurrently without them interfering with each other's state. User Simulation:
Simulate different user experiences (e.g., testing with different user roles or authentication states) within the same browser. Test Isolation:
Ensures that each test runs in a clean state, preventing unintended side effects from other tests.
26. What is the differnce between dependancies and dev depandncies. This qutestion might be asked in interview.
Answer: In a package.json
file (used in Node.js projects), the difference between dependencies and devDependencies is:
1. dependencies
-
These are essential packages needed to run your application.
-
They are installed with npm install
(or yarn install
) in production by default.
-
Examples: express
, react
, lodash
, etc.
-
Declared like:
"dependencies": {
"express": "^4.18.2"
}
2. devDependencies
-
These are packages needed only during development, not in production.
-
Examples: testing libraries, linters, bundlers.
-
Examples: jest
, eslint
, webpack
, etc.
-
Declared like:
"devDependencies": {
"jest": "^29.0.0"
}
Summary Table
Category |
Needed in Production |
Installed with --production flag |
Use Cases |
dependencies |
✅ Yes |
✅ Yes |
App functionality |
devDependencies |
❌ No |
❌ No |
Testing, building, linting |
Would you like an example showing how they’re used in a real project?
Question 27: parallel automation in playwright, when you are using typesccript and node js based project.
Great catch — you're absolutely right.
If you're using Playwright's test runner (@playwright/test
) and you've already specified the browser (e.g., chromium
, firefox
, or webkit
) in your playwright.config.ts
, you do not need to manually call chromium.launch()
.
Instead, you should use the test fixtures like browser
, context
, and page
provided by Playwright. These respect your config and handle setup/teardown automatically.
✅ Correct way with @playwright/test
— No manual launch needed
Here’s how to open two independent contexts (simulating two users) using Playwright's test runner:
import { test, expect, Browser } from '@playwright/test';
test('Two users login using separate contexts', async ({ browser }) => {
// Create first user context
const context1 = await browser.newContext();
const page1 = await context1.newPage();
await page1.goto('https://your-app-url.com');
await page1.fill('[data-test="username"]', 'user1');
await page1.fill('[data-test="password"]', 'password1');
await page1.click('[data-test="login-button"]');
// Create second user context
const context2 = await browser.newContext();
const page2 = await context2.newPage();
await page2.goto('https://your-app-url.com');
await page2.fill('[data-test="username"]', 'user2');
await page2.fill('[data-test="password"]', 'password2');
await page2.click('[data-test="login-button"]');
// Optional: verify successful login for both
await expect(page1).toHaveURL(/dashboard/);
await expect(page2).toHaveURL(/dashboard/);
await context1.close();
await context2.close();
});
๐ฅ Why this is better:
-
Uses browser
from the test fixture — respects your playwright.config.ts
(e.g., browserName: 'firefox'
)
-
No manual launch()
or close()
for the browser itself — just for contexts
-
Cleaner, faster, and integrates properly with test parallelization and retries
Would you like to turn this into a reusable helper function or test fixture for multiple test cases?
Perfect — here's how to turn the multi-user login logic into a reusable helper function or Playwright test fixture for multiple test cases.
✅ Option 1: Reusable Helper Function
You can place this in a utility file like helpers/login.ts
:
helpers/login.ts
import { BrowserContext, Page } from '@playwright/test';
export async function loginUser(context: BrowserContext, username: string, password: string): Promise<Page> {
const page = await context.newPage();
await page.goto('https://your-app-url.com'); // Replace with real URL
await page.fill('[data-test="username"]', username);
await page.fill('[data-test="password"]', password);
await page.click('[data-test="login-button"]');
await page.waitForURL(/dashboard/); // Optional: wait for post-login page
return page;
}
In your test file:
import { test, expect } from '@playwright/test';
import { loginUser } from './helpers/login';
test('Two users login using shared login helper', async ({ browser }) => {
const context1 = await browser.newContext();
const context2 = await browser.newContext();
const page1 = await loginUser(context1, 'user1', 'password1');
const page2 = await loginUser(context2, 'user2', 'password2');
await expect(page1).toHaveURL(/dashboard/);
await expect(page2).toHaveURL(/dashboard/);
await context1.close();
await context2.close();
});
✅ Option 2: Custom Test Fixture (More advanced, cleaner for multiple tests)
If you want cleaner test files with built-in login users, define custom fixtures.
tests/fixtures.ts
import { test as baseTest } from '@playwright/test';
export const test = baseTest.extend<{
user1Page: any;
user2Page: any;
}>({
user1Page: async ({ browser }, use) => {
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://your-app-url.com');
await page.fill('[data-test="username"]', 'user1');
await page.fill('[data-test="password"]', 'password1');
await page.click('[data-test="login-button"]');
await use(page);
await context.close();
},
user2Page: async ({ browser }, use) => {
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://your-app-url.com');
await page.fill('[data-test="username"]', 'user2');
await page.fill('[data-test="password"]', 'password2');
await page.click('[data-test="login-button"]');
await use(page);
await context.close();
}
});
In your test file:
import { test, expect } from './fixtures';
test('Users logged in via fixtures', async ({ user1Page, user2Page }) => {
await expect(user1Page).toHaveURL(/dashboard/);
await expect(user2Page).toHaveURL(/dashboard/);
});
๐ Helper vs Fixture — When to Use Which?
Use Case |
Helper Function |
Custom Fixture |
Quick and flexible |
✅ |
❌ |
Clean test files |
❌ |
✅ |
Multiple users/tests |
✅ |
✅ |
Built-in lifecycle mgmt |
❌ |
✅ |
Would you like me to scaffold a real login.ts
file or generate a fixture structure for your project?
Question: 27: what are the key features when you have to migrate from selenium to playwright( similar kind of qutestion were asksed in coforge interview).
Answer:Migrating from Selenium to Playwright offers several key advantages due to Playwright's modern architecture and developer-friendly features. Here's a breakdown of the most important differences and benefits:
๐ Key Features of Playwright Over Selenium
Feature |
Selenium |
Playwright |
Multiple Browser Support |
Yes (via WebDriver) |
Yes (Chromium, Firefox, WebKit) via one API |
Headless by Default |
Supported |
Headless by default, full control over mode |
Auto-Waiting |
Manual wait needed often |
Built-in auto-waiting for elements |
Built-in Network Interception |
Limited support (with browser extensions) |
First-class network mocking and interception |
Test Isolation / Contexts |
Manual session handling |
Built-in browser contexts for parallelism |
Built-in Test Runner |
No (uses 3rd party like TestNG, JUnit) |
Yes (Playwright Test) |
Screenshots/Videos |
Manual setup |
Built-in screenshot, video, and trace support |
Cross-platform Consistency |
Dependent on drivers |
More consistent due to single protocol |
Modern Async/Sync API |
More verbose, less intuitive |
Simple, modern async API |
Selectors Engine |
Basic (CSS, XPath) |
Powerful selectors (CSS, text, role, nth, etc.) |
Installation Complexity |
Multiple components (drivers, bindings) |
Single package, easy setup |
๐ Migration Highlights
-
Simplified Setup: Playwright requires no separate drivers (unlike ChromeDriver or GeckoDriver in Selenium).
-
More Reliable Tests: Thanks to auto-waiting and smart assertions.
-
Better Debugging: Playwright's trace
viewer and detailed error messages simplify debugging.
-
Faster Execution: Playwright tends to be faster, especially in headless and parallel environments.
-
Modern Language Support: First-class support for TypeScript, JavaScript, Python, .NET, and Java.
Would you like a sample code comparison (Selenium vs Playwright) for a specific task?
Question: 28: There is a test case and you want to test with multiple sets of test data. how will you do that?
answer: based on using playwright.
Here's how you can run a Playwright test with multiple test data sets (i.e., data-driven testing) using the Playwright Test Runner with TypeScript/JavaScript.
✅ Example: Playwright Test with Multiple Data Sets
๐ข Test Scenario: Login test with different users
// login.spec.ts
import { test, expect } from '@playwright/test';
// Define multiple sets of test data
const testData = [
{ username: 'admin', password: 'admin123', expectedMessage: 'Welcome admin!' },
{ username: 'user1', password: 'password1', expectedMessage: 'Welcome user1!' },
{ username: 'user2', password: 'wrongpass', expectedMessage: 'Invalid credentials' },
];
// Loop through each data set and create a test
for (const data of testData) {
test(`Login test: ${data.username}`, async ({ page }) => {
await page.goto('https://example.com/login');
await page.fill('#username', data.username);
await page.fill('#password', data.password);
await page.click('button[type="submit"]');
const message = await page.textContent('#message');
expect(message).toBe(data.expectedMessage);
});
}
๐งช Alternative: test.describe()
+ test.each()
(More elegant)
If you're using Playwright Test v1.30+:
test.describe('Login tests', () => {
const loginCases = [
['admin', 'admin123', 'Welcome admin!'],
['user1', 'password1', 'Welcome user1!'],
['user2', 'wrongpass', 'Invalid credentials'],
];
test.each(loginCases)(
'Login test for %s',
async ({ page }, username, password, expectedMessage) => {
await page.goto('https://example.com/login');
await page.fill('#username', username);
await page.fill('#password', password);
await page.click('button[type="submit"]');
const message = await page.textContent('#message');
expect(message).toBe(expectedMessage);
}
);
});
๐ง Best Practices:
-
Store large test data in a separate .ts
, .json
, or .csv
file.
-
Use .forEach()
or .each()
depending on readability and complexity.
-
Wrap repetitive logic in helper functions if needed.
Would you like an example using external data from a JSON or CSV file?
another thing which interviewer asked if test data is present on excel file, how will you do that?
anser: you can write java code to read excel file.
Question: how to do paralle automation in playwright? what is worker?
In Playwright Test, workers
control parallel test execution. Each worker is an isolated process that runs one test file (or multiple, depending on configuration), enabling faster execution through parallelism.
๐งต Default Workers in Playwright
✅ Default Behavior
By default, Playwright sets the number of workers to the number of CPU cores on your machine.
For example:
-
If your machine has 8 cores, Playwright will run 8 workers in parallel.
-
On CI systems, it auto-adjusts to be efficient and avoids overloading.
๐ง Override Worker Count
You can customize this using:
1. Command Line
npx playwright test --workers=4
2. playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
workers: 4, // fixed number of workers
});
๐ Use Cases for Adjusting Workers
Scenario |
Recommendation |
CI environment |
Use fewer workers (e.g., 2–4) for stability |
Test with shared state/database |
Use 1 worker (serial) to avoid race conditions |
Fast machine & isolated tests |
Use default or increase workers |
๐ Run Tests Serially (1 Worker)
If your tests aren’t isolated (e.g., depend on shared state):
npx playwright test --workers=1
Would you like to see how to group tests for parallel vs serial execution (e.g., using test.describe.configure()
)?
see the test.desccribe.configure below:
Absolutely, I'd be happy to help with that. Grouping tests for parallel vs serial execution—especially using tools like test.describe.configure()
in Playwright—is a smart way to manage test performance and avoid inter-test interference.
Here's a quick overview of how you can do it:
✅ Parallel Test Execution (default)
Playwright runs tests in parallel by default. You don't need to do anything special unless you want to change that behavior.
import { test, expect } from '@playwright/test';
test.describe('parallel group', () => {
test('runs test A', async ({ page }) => {
// test A logic
});
test('runs test B', async ({ page }) => {
// test B logic
});
});
๐ Serial Test Execution
If tests depend on shared state (e.g., same login session or DB state), you can configure them to run serially:
import { test, expect } from '@playwright/test';
test.describe.configure({ mode: 'serial' });
test.describe('serial group', () => {
test('runs test C', async ({ page }) => {
// test C logic
});
test('runs test D', async ({ page }) => {
// test D logic
});
});
⚙️ Notes:
-
mode: 'serial'
ensures the tests inside that describe
block run in order and stop on failure.
-
You can nest parallel and serial groups if needed, but be cautious about shared resources.
Would you like an example showing both in a full test suite?
see how it can be in full suite.
Great! Here's a full Playwright test suite example that demonstrates parallel and serial execution using test.describe.configure()
.
✅ Full Test Suite: Parallel and Serial Groups
// example.spec.ts
import { test, expect } from '@playwright/test';
// ----- PARALLEL GROUP -----
test.describe('Parallel Tests (default)', () => {
test('Test A - runs in parallel', async ({ page }) => {
await page.goto('https://example.com');
expect(await page.title()).toContain('Example Domain');
});
test('Test B - also runs in parallel', async ({ page }) => {
await page.goto('https://example.com');
expect(await page.locator('h1')).toHaveText('Example Domain');
});
});
// ----- SERIAL GROUP -----
test.describe.configure({ mode: 'serial' }); // Important: Applies to *next* describe only
test.describe('Serial Tests (run one after another)', () => {
test('Test C - step 1', async ({ page }) => {
await page.goto('https://example.com');
await page.fill('input[name="q"]', 'Step 1'); // hypothetical example
await expect(page).toHaveURL(/example/);
});
test('Test D - depends on previous step', async ({ page }) => {
// This assumes Test C completed successfully
await page.goto('https://example.com/some-path');
await expect(page.locator('h2')).toBeVisible(); // hypothetical element
});
});
// ----- BACK TO PARALLEL (optional) -----
test.describe.configure({ mode: 'parallel' });
test.describe('More Parallel Tests', () => {
test('Test E - independent', async ({ page }) => {
await page.goto('https://example.com');
expect(await page.content()).toContain('Example');
});
});
๐ Key Takeaways:
-
Each test.describe()
block can have its own configuration.
-
Only the block immediately after test.describe.configure()
is affected.
-
Mixing serial and parallel helps you optimize test speed while managing dependencies.
Would you like to see how this structure could be extended for login workflows or API dependencies?
Question: What is singleton class? Normal defination.
Question: what is hooks? normal in playwright, cuubmer etc...
Question: what is serailizatino and decrationzlaion in api testing.
Question: Suppose you are using typescript with playwright, how will you generate allure report.
Answer: 1. Open terminal in vs code: Add dependancy:
npm install -D allure-playwright
# or
yarn add -D allure-playwright
# or
pnpm add -D allure-playwright
2. open playwright.config.ts
add dependancy:
export default defineConfig({
reporter: [['allure-playwright']],
});
3. in package.json add these
"clean:allure": "rimraf -rf allure-results allure-report",
"prep:allure": "yarn clean:allure && echo 'Now run your test manually.'",
"allure:generate": "allure generate allure-results --clean -o allure-report",
"allure:open": "allure open allure-report",
"allure:report": "yarn allure:generate && yarn allure:open"
4. In terminal please write:
yarn clean: allure
yarn cross-env-shell environmentType=dev HEADLESS=false npx playwright test .RegressionTest/PersistentInterview.spec.ts
yarn allure:generate
yarn allure:open
or if you dont want to write yarn allure:generate and yarn allure:open, you can write yarn allure:report.
5. allure report will be open in chrome.
Question: what is the advatanges of playwright over selenium.
Absolutely! Playwright has become a very popular alternative to Selenium due to its modern architecture, powerful tooling, and built-in features. Here's a detailed comparison highlighting Playwright’s key advantages over Selenium:
✅ Top Advantages of Playwright over Selenium
1. ๐ Trace Viewer
-
Unique to Playwright
-
Records test execution step-by-step with:
-
Screenshots
-
Console logs
-
Network requests
-
Helps debug failures with a visual timeline
-
๐ playwright show-trace trace.zip
2. ๐งช Out-of-the-box Multi-browser Support
-
Chromium, Firefox, WebKit — all with one API
-
✅ Cross-browser testing with no extra config
-
Unlike Selenium, you don’t need separate drivers (e.g., chromedriver
, geckodriver
)
3. ๐ฅ Video Recording Built-in
-
Automatically record videos per test
-
Useful for CI debugging
-
Output options: on, off, retain-on-failure
-
Example:
use: { video: 'on-first-retry' }
4. ๐ฏ Built-in Locator Engine
-
page.getByRole()
, getByText()
, getByLabel()
: semantically meaningful
-
Works better with modern apps and accessibility (a11y)
-
✅ Less reliance on brittle XPath or CSS selectors
5. ๐ ️ Codegen (Auto script generator)
6. ๐จ Faster and More Stable
-
Uses WebSocket protocol, not HTTP like Selenium
-
More reliable element handling: auto-waiting for visibility, clickability, etc.
-
Less flaky in modern SPA apps (React, Angular, etc.)
7. ๐ท Automatic Screenshots
-
Take screenshots on failure or custom points
-
Full-page or specific element
-
Example:
await page.screenshot({ path: 'screenshot.png' });
8. ๐ Parallel Execution and Sharding
-
Parallel tests out of the box
-
Smart test sharding across workers and CI machines
-
No need for extra libraries like TestNG or JUnit
9. ๐ฆ Single Dependency Setup
-
No drivers, separate server, or plugins needed
-
Just install @playwright/test
— done.
10. ๐ Cross-platform and Headless by Default
-
Headless mode with full feature parity
-
Easy to run on Docker, Linux CI, GitHub Actions, etc.
11. ๐ง Powerful Contexts & Multi-tab Support
12. ๐งฉ Network Interception & Mocking
-
Block requests, mock API responses, simulate latency
-
Useful for testing without real backend
await page.route('**/api/data', route => {
route.fulfill({ body: JSON.stringify({ fake: true }) });
});
๐ซ Selenium Limitations in Comparison
Feature |
Playwright ✅ |
Selenium ❌ |
Trace Viewer |
✅ Yes |
❌ No |
Built-in video/screenshot |
✅ Yes |
❌ Plugin needed |
Codegen Recorder |
✅ Yes |
❌ Limited support |
Native multiple browser |
✅ Yes |
❌ Needs drivers |
Auto-waiting |
✅ Smart waits |
❌ Manual waits often |
Headless setup |
✅ Default |
❌ Manual setup |
Network mocking |
✅ Easy |
❌ Very limited |
Parallelization |
✅ Built-in |
❌ Requires setup |
Locator strategies |
✅ Modern |
❌ Mostly XPath/CSS |
Would you like this list in a PDF or formatted slide deck for a presentation?