Hi Please check below link for learning appium 2.0.
https://github.com/gourav999/Appium2.0ByGourav
Software testing is not limited to any field or domain. Various application falls into the various domains.
Hi Please check below link for learning appium 2.0.
https://github.com/gourav999/Appium2.0ByGourav
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! ๐ฅ
✅ 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:
Playwright is faster and more reliable due to auto-waiting
Has native support for modern UI elements and multiple tabs
✅ 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");
✅ Answer:
page.locator("css selector")
page.getByText("Login")
page.getByRole(…)
๐ Example:
Locator loginBtn = page.locator("#login-button");
loginBtn.click();
page.selectOption("#dropdown-id", new SelectOption().setLabel("Option 1"));
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshot.png")));
✅ 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");
}
@AfterMethod
public void tearDown(ITestResult result) {
if (ITestResult.FAILURE == result.getStatus()) {
page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get("screenshots/" + result.getName() + ".png")));
}
}
✅ 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.
ArrayList
and LinkedList
?✅ Answer:
ArrayList
: Fast for retrieval, slower for inserts/removals
LinkedList
: Faster for insertions/removals, slower for retrieval
✅ Answer:
Checked: Caught at compile time (IOException
)
Unchecked: Runtime exceptions (NullPointerException
)
✅ Answer:
Use Cucumber for BDD
Define .feature
file
Use Step Definitions to map Gherkin steps to Playwright Java code
Feature: Login functionality
Scenario: Successful login
Given I open the login page
When I enter valid credentials
Then I should see the homepage
@Given("I open the login page")
public void openLoginPage() {
page.navigate("https://example.com/login");
}
✅ Answer:
Use a TestContext
or Hooks
class to store and share browser/page instances.
page.onDialog(dialog -> {
System.out.println("Alert Text: " + dialog.message());
dialog.accept();
});
Page newPage = context.waitForPage(() -> {
page.click("#open-new-tab");
});
newPage.bringToFront();
page.waitForSelector("#element-id", new Page.WaitForSelectorOptions().setTimeout(5000));
boolean isVisible = page.locator("#submit").isVisible();
boolean isEnabled = page.locator("#submit").isEnabled();
✅ Default: 30 seconds
✅ Override:
page.setDefaultTimeout(10000); // 10 seconds
Use Page Object Model
Isolate test data
Use assertions wisely
Capture screenshots on failure
Avoid hard waits, use Playwright's auto-waiting
Playwright + TestNG combo is super effective for parallel tests.
a. Update testng.xml
to enable parallel test classes or methods:
xml<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd" >
<suite name="Playwright Suite" parallel="classes" thread-count="3">
<test name="Tests">
<classes>
<class name="tests.LoginTest"/>
<class name="tests.SearchTest"/>
</classes>
</test>
</suite>
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.
javapublic class BaseTest {
protected ThreadLocal<Playwright> playwright = new ThreadLocal<>();
protected ThreadLocal<Browser> browser = new ThreadLocal<>();
protected ThreadLocal<Page> page = new ThreadLocal<>();
@BeforeMethod
public void setUp() {
playwright.set(Playwright.create());
browser.set(playwright.get().chromium().launch());
page.set(browser.get().newPage());
}
@AfterMethod
public void tearDown() {
page.get().close();
browser.get().close();
playwright.get().close();
}
public Page getPage() {
return page.get();
}
}
Then in your test class, use:
java@Test
public void testLogin() {
Page page = getPage();
page.navigate("https://example.com");
page.fill("#username", "admin");
page.click("#login");
}
Use the dataprovider
+ parallel
option with Cucumber
Split scenarios across multiple threads
Want a full example with Cucumber + Playwright + TestNG parallel setup? Let me know!
You can manually create threads to execute different test classes or cases in parallel using Java’s ExecutorService
.
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 ⤵️
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.
page.locator("text=Submit").click(); // Exact or partial match
page.getByLabel("Email").fill("test@example.com");
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Login")).click();
page.getByPlaceholder("Enter your name").fill("John Doe");
Assume this HTML:
<table>
<tr>
<td>Name</td>
<td>Email</td>
</tr>
<tr>
<td>John</td>
<td>john@example.com</td>
</tr>
</table>
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);
<div class="card">
<div class="header">User Info</div>
<div class="content">
<span>Name:</span>
<span>John Doe</span>
</div>
</div>
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);
<ul>
<li class="user">Alice</li>
<li class="user">Bob</li>
<li class="user">Charlie</li>
</ul>
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());
}
<custom-element>
#shadow-root
<input id="shadow-input" />
</custom-element>
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.
<table>
<tr>
<td>John</td>
<td><button>Edit</button></td>
</tr>
</table>
Locator row = page.locator("tr", new Locator.LocatorOptions().setHasText("John"));
row.locator("button").click();
// Find a visible input with class and placeholder
page.locator("input.visible-input[placeholder='Search']:not([disabled])").fill("Playwright");
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).
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.
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.
Here are the key differences ๐
Locator button = page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Submit"));
const button = page.getByRole('button', { name: 'Submit' });
✅ Same logic — Java is just more verbose due to types and method chaining.
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" })
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.
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.
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) |
page.getByLabel("Email").fill("user@example.com");
await page.getByLabel('Email').fill('user@example.com');
Same result — just different flavor.
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.
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.Here’s a quick breakdown of the top features of Playwright, especially useful when evaluating or switching from other frameworks like Selenium:
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. |
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.
Fixtures in Playwright Test are reusable building blocks that provide:
Context (like a logged-in user)
Shared setup (like launching a browser or database connection)
Custom test environments
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.
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
}
});
// 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();
});
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?
browser.newContext()
method, as seen in the Playwright Java documentation. context.close()
, as seen in the Playwright Java documentation. package.json
file (used in Node.js projects), the difference between dependencies and devDependencies is: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"
}
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"
}
Category | Needed in Production | Installed with --production flag |
Use Cases |
---|---|---|---|
dependencies |
✅ Yes | ✅ Yes | App functionality |
devDependencies |
❌ No | ❌ No | Testing, building, linting |
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.
@playwright/test
— No manual launch neededHere’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();
});
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
Perfect — here's how to turn the multi-user login logic into a reusable helper function or Playwright test fixture for multiple test cases.
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;
}
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();
});
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();
}
});
import { test, expect } from './fixtures';
test('Users logged in via fixtures', async ({ user1Page, user2Page }) => {
await expect(user1Page).toHaveURL(/dashboard/);
await expect(user2Page).toHaveURL(/dashboard/);
});
Use Case | Helper Function | Custom Fixture |
---|---|---|
Quick and flexible | ✅ | ❌ |
Clean test files | ❌ | ✅ |
Multiple users/tests | ✅ | ✅ |
Built-in lifecycle mgmt | ❌ | ✅ |
login.ts
file or generate a fixture structure for your project?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 |
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.
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.
// 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);
});
}
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);
}
);
});
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.
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.
You can customize this using:
npx playwright test --workers=4
playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
workers: 4, // fixed number of 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 |
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:
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
});
});
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
});
});
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()
.
// 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');
});
});
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
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:
Unique to Playwright
Records test execution step-by-step with:
Screenshots
Console logs
Network requests
Helps debug failures with a visual timeline
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
)
Automatically record videos per test
Useful for CI debugging
Output options: on, off, retain-on-failure
Example:
use: { video: 'on-first-retry' }
page.getByRole()
, getByText()
, getByLabel()
: semantically meaningful
Works better with modern apps and accessibility (a11y)
✅ Less reliance on brittle XPath or CSS selectors
Record user actions and generate test code
Command:
npx playwright codegen https://example.com
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.)
Take screenshots on failure or custom points
Full-page or specific element
Example:
await page.screenshot({ path: 'screenshot.png' });
Parallel tests out of the box
Smart test sharding across workers and CI machines
No need for extra libraries like TestNG or JUnit
No drivers, separate server, or plugins needed
Just install @playwright/test
— done.
Headless mode with full feature parity
Easy to run on Docker, Linux CI, GitHub Actions, etc.
Create isolated browser contexts (like incognito) per test
Supports multi-tab/multi-user simulation easily
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 }) });
});
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?