Playwright Interview Questions for Freshers: Your First QA Job Prep Guide (2025)

Top 25+ Playwright and JavaScript Interview Questions for QA Testers (2025 Guide)



In today’s fast-paced software development world, automation testing has become an essential skill for QA professionals. As companies shift towards modern frameworks, Playwright is gaining popularity for its powerful browser automation capabilities. Combine that with JavaScript, and you have a robust testing stack that many organizations now prefer.

Whether you're a fresher or an experienced QA engineer preparing for your next interview, this blog covers top Playwright and JavaScript interview questions, complete with real-world context to help you ace your QA interview in 2025.


🔍 Why Playwright + Java/JavaScript is a Powerful QA Combo?

While Playwright is primarily used with JavaScript or TypeScript, it's now compatible with multiple languages including Java. QA teams are leveraging Java’s mature ecosystem alongside Playwright’s modern browser control to:

  • Automate web UI tests across Chromium, Firefox, and WebKit.

  • Handle real-world scenarios like file uploads, authentication, geolocation.

  • Integrate easily with CI/CD pipelines and reporting tools.


📋 Playwright & Java Interview Questions (With Contextual Tips)

Basic Questions (Freshers / 0-2 Years Experience)

  1. What is Playwright, and how does it differ from Selenium?
    Playwright is a Node.js library for browser automation by Microsoft. Unlike Selenium, it supports modern web features like single-page apps better and handles multiple browser contexts efficiently. Unlike Cypress, it supports multiple browser engines (Chromium, Firefox, WebKit), multiple tabs, and native iframe handling.
    Tip: Talk about multi-browser support, auto-waiting, faster execution, and better developer experience.

  2. Can Playwright be used with Java? How?
    Yes. Playwright for Java is officially supported via Maven. Talk about setup using playwright-java package.

  3. How do you launch a browser and open a page using Playwright in Java?

    Playwright playwright = Playwright.create();
    Browser browser = playwright.chromium().launch();
    Page page = browser.newPage();
    page.navigate("https://example.com");
    
  4. What are auto-waiting and retry-ability in Playwright?
    Playwright is known for being flaky-test resistant due to its built-in auto-waiting and retry-ability mechanisms. These features reduce the need for manual waits (setTimeout, waitForTimeout, etc.) and make your tests faster and more stable.

    🔄 Auto-Waiting (Built-in Waits)

    Playwright automatically waits for elements to be:

    • Visible

    • Enabled

    • Attached to the DOM

    ✅ Example:

    await page.click('button#submit');
    

    No need to manually wait — Playwright will wait until the button is clickable.


    🔁 Retry-ability (Smart Retrying)

    Playwright retries actions and assertions until they succeed or timeout.

    ✅ Example:

    await expect(page.locator('#status')).toHaveText('Success');
    

    It keeps checking until the text is "Success" (within timeout), no manual loops needed.


    📌 Benefit:

    • No waitForTimeout() needed

    • Reduces flaky tests

    • Cleaner & smarter test scripts

    Let me know if you want real test case examples!

  5. Difference between page.waitForSelector() and page.locator().waitFor()
    waitForSelector() is older and returns an element handle.
    locator().waitFor() is newer and used with Locator API (recommended in newer versions).

  6. How do you validate title and URL in Playwright?

    expect(await page.title()).toBe('Expected Title');
    expect(page.url()).toBe('https://expected-url.com');
  7. How do you launch a browser and open a page in Playwright using JavaScript?

    const { chromium } = require('playwright');
    (async () => {
      const browser = await chromium.launch();
      const context = await browser.newContext();
      const page = await context.newPage();
      await page.goto('https://example.com');
      await browser.close();
    })();
  8. What is the difference between page.click() and locator.click()?

    🔹 page.click(selector)

    • Works with string-based selectors (e.g., CSS, XPath).

    • Executes the click immediately after resolving the selector.

    • No smart waiting — only basic checks.

    • More prone to flakiness on dynamic UIs.

    ✅ Example:

    await page.click('#submitBtn');
    

    🔹 locator.click()

    • Uses Locator API, which is more robust and reliable.

    • Automatically waits for the element to be:

      • Attached to the DOM

      • Visible

      • Enabled

    • Supports chaining and filtering.

    • Recommended for modern, stable automation.

    ✅ Example:

    const button = page.locator('#submitBtn');
    await button.click();
    

    🆚 Key Differences

    Feature page.click() locator.click()
    Syntax Selector string Locator object
    Auto-waiting Limited ✅ Yes (better handling)
    Retry-ability ❌ No ✅ Yes
    Reliability Moderate ✅ High
    Chaining support ❌ No ✅ Yes

    ✅ Recommendation:

    ➡️ Use **locator.click()** for more reliable, stable, and maintainable tests.



  9. How do you wait for element visibility or clickability?

    await page.locator('#element').waitFor({ state: 'visible' });
    await page.click('#element');
  10. How does Playwright handle synchronization differently than Selenium?

    Playwright and Selenium are both browser automation tools, but Playwright handles synchronization more intelligently and automatically than Selenium.

    Here's a short and clear comparison:


    🔹 Synchronization in Selenium

    • Manual waits are often needed, like:

      • Thread.sleep()

      • WebDriverWait + ExpectedConditions

    • You have to explicitly wait for elements to load, be visible, or clickable.

    • Tests may become flaky if timing is not handled well.

    ❌ Example in Selenium:

    WebDriverWait wait = new WebDriverWait(driver, 10);
    wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("loginBtn")));
    driver.findElement(By.id("loginBtn")).click();
    

    🔹 Synchronization in Playwright

    • Auto-waits by default for:

      • Element to be attached to DOM

      • Element to be visible

      • Element to be enabled and stable

    • No need to add explicit waits for most actions.

    • More stable and reliable for dynamic web apps.

    ✅ Example in Playwright:

    await page.locator('#loginBtn').click(); // Auto-waits under the hood
    

    🆚 Summary Table

    Feature Selenium Playwright
    Default auto-waiting ❌ No ✅ Yes
    Manual wait needed often ✅ Yes ❌ Rarely
    Flakiness in dynamic UIs ❌ High chance ✅ Reduced
    Easy handling of async UI ❌ Complex ✅ Built-in

    ✅ Verdict:

    Playwright is better at handling synchronization automatically, reducing the need for manual waits and making your test scripts cleaner and more reliable.


  11. How do you capture a screenshot in Playwright using Java?

    To capture a screenshot in Playwright using Java, you can use the screenshot() method provided by the Page class.


    Example Code: Capture Full Page Screenshot

    import com.microsoft.playwright.*;
    
    public class ScreenshotExample {
      public static void main(String[] args) {
        try (Playwright playwright = Playwright.create()) {
          Browser browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));
          Page page = browser.newPage();
          page.navigate("https://example.com");
    
          // Capture screenshot
          page.screenshot(new Page.ScreenshotOptions()
            .setPath(Paths.get("screenshot.png"))
            .setFullPage(true));
    
          System.out.println("✅ Screenshot saved as 'screenshot.png'");
        }
      }
    }
    

    📌 Key Notes:

    • setPath(Paths.get("filename.png")) → saves the screenshot to the specified file.

    • setFullPage(true) → captures the entire scrollable page. Omit this to capture just the visible area.


    📸 To Capture a Screenshot of an Element:

    Locator element = page.locator("h1");
    element.screenshot(new Locator.ScreenshotOptions()
      .setPath(Paths.get("element.png")));
    


  12. Explain the page object model (POM) in the context of Playwright and JavaScript.

    The Page Object Model (POM) is a popular design pattern used in test automation that helps create a clean separation between test logic and UI interactions. In Playwright with JavaScript or TypeScript, POM improves code readability, reusability, and maintainability.


    What is Page Object Model (POM)?

    POM suggests that each web page (or component) in your application should have a corresponding JavaScript class. That class:

    • Defines the locators for elements on the page

    • Encapsulates interactions (e.g., clicking, filling, validating)


    📦 Folder Structure Example:

    tests/
      └── login.spec.js
    pages/
      └── loginPage.js
    

    📄 Example: loginPage.js

    // pages/loginPage.js
    
    export class LoginPage {
      constructor(page) {
        this.page = page;
        this.usernameInput = page.locator('#username');
        this.passwordInput = page.locator('#password');
        this.loginButton = page.locator('#login');
      }
    
      async goto() {
        await this.page.goto('https://example.com/login');
      }
    
      async login(username, password) {
        await this.usernameInput.fill(username);
        await this.passwordInput.fill(password);
        await this.loginButton.click();
      }
    }
    

    📄 Example: login.spec.js

    import { test, expect } from '@playwright/test';
    import { LoginPage } from '../pages/loginPage';
    
    test('Successful login', async ({ page }) => {
      const loginPage = new LoginPage(page);
      await loginPage.goto();
      await loginPage.login('admin', 'password123');
    
      await expect(page).toHaveURL('https://example.com/dashboard');
    });
    

    ✅ Benefits of Using POM in Playwright:

    Feature Benefit
    Reusability Methods like login() can be reused across tests
    Maintainability UI changes in locators only need updates in one place
    Readability Test files are cleaner and focus on test intent
    Scalability Easier to add more pages and tests

    📌 Summary:

    POM with Playwright + JavaScript means:

    • Creating separate Page classes

    • Keeping UI logic out of test files

    • Writing modular, readable, and maintainable automation


  13. How do you handle dropdowns or select elements in Playwright?

    In Playwright, handling dropdowns or <select> elements is simple and can be done using the .selectOption() method.


    ✅ Basic Syntax

    await page.selectOption('select#dropdownId', 'value');
    

    🎯 Example: Selecting from a Dropdown

    HTML:

    <select id="fruits">
      <option value="apple">Apple</option>
      <option value="banana">Banana</option>
      <option value="mango">Mango</option>
    </select>
    

    Playwright Code:

    await page.selectOption('#fruits', 'mango');
    

    🔁 Select by Label or Value

    You can use:

    • value: actual value attribute

    • label: visible text

    // By value
    await page.selectOption('#fruits', { value: 'banana' });
    
    // By label
    await page.selectOption('#fruits', { label: 'Apple' });
    

    📋 Multiple Selection Example

    For <select multiple>:

    await page.selectOption('#multi-select', ['option1', 'option2']);
    

    🧠 Tips:

    • Always wait for the dropdown to be visible if it's dynamic:

      await page.waitForSelector('#fruits');
      await page.selectOption('#fruits', 'mango');
      
    • For custom dropdowns (not <select>), use click() and locator.getByText().



  14. What are locators in Playwright, and how are they different from selectors?

    In Playwright, both locators and selectors are used to find elements on a page, but they serve slightly different purposes and offer different levels of abstraction and power.


    ✅ What is a Selector?

    A selector is a string used to query an element from the DOM.

    Examples:

    await page.click('text=Submit');
    await page.click('#login-button');
    await page.click('.nav > li:nth-child(2)');
    

    ✅ What is a Locator?

    A locator is a Playwright-specific object that encapsulates a selector and provides additional methods for interaction.

    Syntax:

    const button = page.locator('text=Submit');
    await button.click();
    

    🔍 Key Differences

    Feature Selector Locator
    Type String Object
    Retry-ability No (must manage retries manually) ✅ Built-in auto-retry until stable
    Readability Can become messy with complex logic ✅ Cleaner and reusable
    Performance One-time DOM query ✅ Lazy evaluation (waits for conditions)
    Methods Available Basic query only ✅ Rich API (click(), fill(), isVisible(), etc.)

    🎯 Locator Example

    const usernameField = page.locator('#username');
    await usernameField.fill('myuser');
    await usernameField.press('Enter');
    

    🧠 Summary:

    • Selectors are useful for quick, one-off actions.

    • Locators are recommended for all robust and maintainable test automation — they auto-wait, are more stable, and chainable.



🔧 Advanced Playwright & JavaScript QA Interview Questions for 2–4 Years              Experience.

  1. Explain test parallelism in Playwright and how it improves test speed.

    ✅ Test Parallelism in Playwright – Explained

    Test parallelism in Playwright means running multiple test files or test cases simultaneously rather than one after the other. This is done using multiple worker threads, and it significantly improves test execution speed, especially in large test suites.


    🔧 How It Works

    Playwright uses a test runner that can spawn multiple workers, each running one or more tests in parallel. Each worker gets its own browser instance, ensuring test isolation and no shared state.


    ⚙️ Enable Parallelism (Default Behavior)

    By default, Playwright automatically runs test files in parallel (if system resources allow).

    In playwright.config.js:

    // playwright.config.js
    const config = {
      workers: 4, // Number of parallel workers (threads)
    };
    
    module.exports = config;
    

    📈 Benefits of Parallelism

    Benefit Description
    🚀 Faster Execution Reduces total test time by running tests at the same time.
    🧪 Better Resource Use Utilizes multiple CPU cores and browser instances.
    🧼 Test Isolation Each test runs in a separate browser context to avoid side effects.

    🛠 Example Command

    Run with 3 parallel workers:

    npx playwright test --workers=3
    

    🔒 Optional: Disable Parallelism for Debugging

    In the test config or CLI, you can run tests serially for debugging:

    npx playwright test --workers=1
    

    ✅ Best Practices

    • Avoid shared state (e.g., global variables, shared sessions).

    • Use test.describe.configure({ mode: 'serial' }) when a group of tests must run in order.

    • Use beforeEach/afterEach hooks for test isolation.



  2. How do you handle browser context in Playwright? Why is it useful?

    🔍 What is a Browser Context?

    In Playwright, a browser context is an isolated session within a single browser instance — just like using incognito tabs in Chrome.
    Each context has its own cookies, cache, localStorage, and session — so they do not share state.


    🎯 Why It’s Useful

    Feature Benefit
    🧪 Test Isolation Each test runs in its own clean environment (no shared cookies, etc).
    🔄 Multiple Logins You can simulate multiple users (e.g., admin vs. customer) in one test.
    🚀 Parallel Testing Run tests in the same browser instance but with separate sessions.
    🔐 Better Security Mimics real-world user behavior like private/incognito browsing.

    🛠 How to Use Browser Context in Playwright (JavaScript Example)

    const { chromium } = require('playwright');
    
    (async () => {
      const browser = await chromium.launch();
      
      // Create a new browser context
      const context = await browser.newContext();
    
      // Create a new page inside the context
      const page = await context.newPage();
      await page.goto('https://example.com');
    
      // Do your testing actions here...
    
      await browser.close();
    })();
    

    🧪 Simulating Multiple Users

    const userContext = await browser.newContext();
    const adminContext = await browser.newContext();
    
    const userPage = await userContext.newPage();
    const adminPage = await adminContext.newPage();
    
    await userPage.goto('https://yourapp.com/login');
    await adminPage.goto('https://yourapp.com/admin');
    

    📌 Pro Tip:

    • Use context.storageState() and context.addCookies() to manage sessions or reuse logins.

    • Especially useful in e2e testing or testing microservices with multiple roles.



  3. What is the best way to manage test data in Playwright test automation?

    Managing test data efficiently is crucial in any Playwright test automation strategy to ensure tests are reliable, maintainable, and scalable. Here's the best way to manage test data in Playwright:


    ✅ 1. Use External Data Files (JSON / CSV / Excel)

    • Why? Keeps test data separate from test logic, making maintenance easier.

    • Example (JSON):

    // testData.json
    {
      "login": {
        "username": "testuser",
        "password": "testpass"
      }
    }
    
    // test.spec.js
    const testData = require('./testData.json');
    
    await page.fill('#username', testData.login.username);
    await page.fill('#password', testData.login.password);
    

    ✅ 2. Use Data-Driven Testing (via test.describe() or loops)

    Run the same test for multiple datasets:

    const users = [
      { username: 'admin', password: 'adminpass' },
      { username: 'user1', password: 'userpass1' }
    ];
    
    for (const user of users) {
      test(`Login test for ${user.username}`, async ({ page }) => {
        await page.goto('/login');
        await page.fill('#username', user.username);
        await page.fill('#password', user.password);
        await page.click('button[type="submit"]');
        // Assertions...
      });
    }
    

    ✅ 3. Use Fixtures for Test Setup and Teardown

    Fixtures (especially in Playwright Test Runner) help set up dynamic test data.

    // Using a fixture to create user data before tests
    test.beforeEach(async ({ page }) => {
      await createTestUser('userA'); // Custom function calling API or DB
    });
    

    4. Seed and Clean Test Data Using APIs or DB Hooks

    • Use Playwright to call REST APIs or scripts to seed/cleanup test data before or after test runs.

    await request.post('/api/testdata/seed', { data: { user: 'testuser' } });
    

    ✅ 5. Use .env Files for Configurable Secrets

    • Store dynamic values or environment-based data (like API keys, base URL) in .env file using dotenv.

    BASE_URL=https://staging.app.com
    ADMIN_USER=admin
    
    require('dotenv').config();
    await page.goto(process.env.BASE_URL);
    

    ✅ Summary of Best Practices:

    Practice Why It's Good
    Use JSON/CSV for static data Separation of concerns
    Use API/DB setup for dynamic data Ensure tests run on fresh, known data
    Use fixtures Standardized setup & cleanup
    Use .env configs Easy environment switching
    Avoid hardcoded values Makes tests brittle and hard to scale


  4. How do you handle alerts, pop-ups, and confirmation dialogs in Playwright using JavaScript?

    In Playwright (JavaScript), handling alerts, pop-ups, and confirmation dialogs (like alert(), confirm(), prompt()) is done using the page.on('dialog', callback) event.


    ✅ How it works:

    Playwright listens for dialog events and allows you to interact with them (accept, dismiss, read the message, etc.).


    📌 Example 1: Handling alert()

    page.on('dialog', async dialog => {
      console.log('Alert message:', dialog.message());
      await dialog.accept();
    });
    
    await page.click('#trigger-alert');  // This button triggers alert()
    

    📌 Example 2: Handling confirm()

    page.on('dialog', async dialog => {
      console.log('Confirm message:', dialog.message());
      await dialog.accept();  // or dialog.dismiss();
    });
    
    await page.click('#trigger-confirm');  // Triggers a confirmation popup
    

    📌 Example 3: Handling prompt()

    page.on('dialog', async dialog => {
      console.log('Prompt message:', dialog.message());
      await dialog.accept('My input');  // Send input to the prompt
    });
    
    await page.click('#trigger-prompt');  // Triggers a prompt dialog
    

    🔒 Important Notes:

    • dialog.accept([promptText]): Accepts the dialog (optionally sending input for prompt).

    • dialog.dismiss(): Dismisses the dialog (like clicking Cancel).

    • You must handle dialogs before they appear, otherwise the page may hang.


    🧠 Pro Tip:

    For reliability, attach the page.on('dialog', ...) handler before the action that triggers the popup.



  5. How do you perform API testing in Playwright JavaScript? Can Playwright do backend checks?

    Yes, Playwright (JavaScript) supports API testing and backend checks using its built-in request API — so you can test RESTful APIs alongside your UI tests.


    Why use Playwright for API testing?

    • You can send HTTP requests directly (GET, POST, PUT, DELETE, etc.).

    • You can chain backend validation with frontend actions.

    • No need for extra libraries like Postman or Axios.


    📌 Example: Basic API Test in Playwright

    import { test, expect, request } from '@playwright/test';
    
    test('API Test - Validate GET User', async ({ request }) => {
      const response = await request.get('https://jsonplaceholder.typicode.com/users/1');
      expect(response.ok()).toBeTruthy();
    
      const body = await response.json();
      expect(body.name).toBe('Leanne Graham');
    });
    

    📌 Example: Backend Check After UI Action

    test('Create User via UI and validate backend', async ({ page, request }) => {
      // Perform frontend action
      await page.goto('https://example.com/create-user');
      await page.fill('#name', 'John Doe');
      await page.click('#submit');
    
      // Validate on backend
      const apiResponse = await request.get('https://api.example.com/users?name=John Doe');
      const result = await apiResponse.json();
      expect(result[0].name).toBe('John Doe');
    });
    

    🧪 Available HTTP methods:

    • request.get(url)

    • request.post(url, { data })

    • request.put(url, { data })

    • request.delete(url)


    🎯 Real-World Use Cases:

    • Validating DB records via APIs after form submission.

    • Auth token testing.

    • CRUD operations on REST APIs.

    • Smoke tests for microservices.


    🔐 You can also pass headers and authentication:

    const apiContext = await request.newContext({
      baseURL: 'https://api.example.com',
      extraHTTPHeaders: {
        'Authorization': `Bearer your_token_here`
      }
    });
    


  6. What is BrowserContext and how is it different from a Browser in Playwright?

    In Playwright, Browser and BrowserContext are core concepts for managing test environments. Here's the difference in a simple and clear way:


    What is a Browser in Playwright?

    • A Browser instance represents the entire running browser (like Chrome, Firefox, or WebKit).

    • It’s like launching Chrome manually — all users (tabs/windows) share the same memory, cookies, etc.

    const browser = await chromium.launch(); // Starts a full browser
    

    ✅ What is a BrowserContext?

    • A BrowserContext is like an isolated browser profile/session within the same browser.

    • Each context is independent — separate cookies, storage, sessions, and cache.

    • Great for parallel tests without interference.

    const context = await browser.newContext(); // Like an incognito window
    const page = await context.newPage();
    

    🎯 Key Differences

    Feature Browser BrowserContext
    Scope Entire browser A single session/profile
    Session Storage Shared across all pages Isolated
    Cookies/Cache Shared Isolated
    Use Case One per test suite One per user/test to avoid conflicts
    Performance Heavy (full browser instance) Lightweight (faster, memory-efficient)

    🧪 Example: Creating Two Isolated Sessions

    const browser = await chromium.launch();
    
    const context1 = await browser.newContext();
    const page1 = await context1.newPage();
    await page1.goto('https://example.com');
    
    const context2 = await browser.newContext();
    const page2 = await context2.newPage();
    await page2.goto('https://example.com'); // Separate session
    
    await browser.close();
    

    Why Use BrowserContext?

    • Run parallel tests without launching multiple browsers.

    • Simulate multiple users with different sessions.

    • Improve performance and reduce test flakiness.



  7. How do you handle authentication (like login) in Playwright tests?

    Handling authentication (login) in Playwright can be done in several efficient ways depending on the use case. Here's a short and practical breakdown with code examples:


    ✅ 1. UI-Based Login (Form Login)

    Perform login like a real user:

    test('Login using UI', async ({ page }) => {
      await page.goto('https://example.com/login');
      await page.fill('#username', 'yourUsername');
      await page.fill('#password', 'yourPassword');
      await page.click('button[type="submit"]');
      await expect(page).toHaveURL('https://example.com/dashboard');
    });
    

    🔁 Use only if login is part of the test or for initial setup.


    ✅ 2. API Login (Faster & Headless)

    Use API call to authenticate and reuse cookies or tokens:

    test('Login via API and reuse session', async ({ browser }) => {
      const context = await browser.newContext();
      const page = await context.newPage();
    
      // Send API login request
      const response = await page.request.post('https://example.com/api/login', {
        data: {
          username: 'yourUsername',
          password: 'yourPassword',
        },
      });
    
      const token = (await response.json()).token;
    
      // Set token as local storage or cookie
      await context.addCookies([{
        name: 'auth_token',
        value: token,
        domain: 'example.com',
        path: '/',
        httpOnly: true,
        secure: true,
        sameSite: 'Lax'
      }]);
    
      // Proceed with authenticated page
      await page.goto('https://example.com/dashboard');
    });
    

    3. Storage State (Recommended for Reuse)

    Login once, save the session, and reuse it across tests.

    Step 1: Create login script (login.setup.js)

    const { chromium } = require('@playwright/test');
    
    (async () => {
      const browser = await chromium.launch();
      const context = await browser.newContext();
      const page = await context.newPage();
    
      await page.goto('https://example.com/login');
      await page.fill('#username', 'yourUsername');
      await page.fill('#password', 'yourPassword');
      await page.click('button[type="submit"]');
    
      await context.storageState({ path: 'auth.json' });
      await browser.close();
    })();
    

    Step 2: Use in tests

    test.use({ storageState: 'auth.json' });
    
    test('Dashboard loads with logged-in user', async ({ page }) => {
      await page.goto('https://example.com/dashboard');
      await expect(page.locator('text=Welcome')).toBeVisible();
    });
    

    🎯 Best Practice

    • ✅ Use storageState for speed and reusability.

    • ✅ Use API login if frontend login is slow or flaky.

    • ❌ Avoid logging in via UI in every test — it's time-consuming.



  8. What kind of reporting frameworks can be integrated with Playwright Java (e.g., Allure, ExtentReports)?

    Playwright with JavaScript (using Playwright Test Runner or Jest) supports integration with several popular reporting frameworks to generate clean, detailed test reports. Here are the most commonly used ones:


    ✅ 1. Allure Report (Most Popular)

    Allure is widely used for its rich UI, step-by-step details, and attachments (screenshots, logs, etc.).

    🔧 Setup:

    npm i -D allure-playwright
    

    🔌 Configuration:

    In playwright.config.ts or .js:

    reporters: [
      ['allure-playwright'],
    ]
    

    📸 Run tests and generate report:

    npx playwright test
    npx allure generate ./allure-results --clean -o ./allure-report
    npx allure open ./allure-report
    

    2. HTML Reporter (Built-in)

    Playwright comes with a built-in HTML reporter:

    reporters: ['html']
    

    Run:

    npx playwright show-report
    

    📌 Good for quick local viewing. Interactive UI with test details.


    3. JSON & JUnit Reporters

    Useful for CI/CD integration (like Jenkins, GitHub Actions, Azure DevOps).

    reporters: [
      ['json', { outputFile: 'report.json' }],
      ['junit', { outputFile: 'results.xml' }]
    ]
    

    📂 Use these for downstream processing or visual dashboards in CI pipelines.


    ✅ 4. ExtentReports (Not native but possible via plugins/wrappers)

    While not officially supported like Allure, you can use ExtentReports with:

    • Jest + custom reporter wrappers

    • Playwright + Cucumber + ExtentReports (in BDD setups)

    🛠️ Requires more manual setup, but possible for teams already using ExtentReports in Selenium.


    5. Custom HTML Reporter

    You can write a custom reporter if you need full control over format:

    // custom-reporter.js
    class MyReporter {
      onTestBegin(test) { /* logic */ }
      onTestEnd(test, result) { /* logic */ }
    }
    module.exports = MyReporter;
    

    In config:

    reporters: [['./custom-reporter.js']]
    

    🎯 Recommended Setup for Playwright JS:

    reporters: [
      ['list'],  // console logs
      ['html'],  // local interactive reports
      ['allure-playwright'],  // advanced reporting
      ['junit', { outputFile: 'results.xml' }]  // CI
    ]
    


  9. How do you handle dynamic content in Playwright that loads after scrolling or clicking?

    In Playwright, handling dynamic content (like infinite scroll, lazy-loaded elements, or AJAX-loaded sections) requires waiting and interaction strategies. Here's how to effectively deal with such content:


    1. Wait for Element to Appear

    Use Playwright’s auto-waiting or await locator.waitFor() to wait for elements that load dynamically.

    await page.locator('.dynamic-item').waitFor({ state: 'visible' });
    

    2. Scroll to Load More Content

    If the content appears on scroll, simulate scrolling using page.evaluate() or page.mouse.wheel().

    await page.evaluate(() => {
      window.scrollBy(0, window.innerHeight);
    });
    await page.waitForTimeout(1000); // wait for content to load
    

    ✅ Use in a loop if you're scrolling multiple times:

    for (let i = 0; i < 5; i++) {
      await page.mouse.wheel(0, 1000);
      await page.waitForTimeout(1500);
    }
    

    3. Wait for Network to Be Idle

    Wait for all AJAX/XHR requests to finish:

    await page.waitForLoadState('networkidle');
    

    4. Click to Load More Content

    Click a button and wait for new content to load:

    await page.click('button.load-more');
    await page.locator('.new-item').waitFor({ state: 'visible' });
    

    5. Use locator.first() or locator.last() for Dynamic Lists

    const lastItem = page.locator('.list-item').last();
    await lastItem.scrollIntoViewIfNeeded();
    

    🔁 Full Example:

    for (let i = 0; i < 3; i++) {
      await page.mouse.wheel(0, 1000);
      await page.waitForLoadState('networkidle');
      await page.waitForTimeout(2000); // wait for items to render
    }
    



🧠 Advanced & Real-Time Scenario Questions (4+ Years Experience)

  1. You have flaky tests in Playwright. How would you debug and stabilize them?

    Here’s a simplified version of the explanation on how to debug and fix flaky tests in Playwright:


    🧪 How to Fix Flaky Tests in Playwright

    Flaky tests are tests that pass sometimes and fail randomly, usually due to timing, animations, or dynamic content. Here’s how to fix them:


    1. Use Smart Locators (locator.click() not page.click())

    Instead of:

    await page.click('#submit');
    

    Use:

    await page.locator('#submit').click();
    

    Why? Because locator.click() waits for the element to be ready.


    ⏱️ 2. Avoid Hardcoded Timeouts

    ❌ Bad:

    await page.waitForTimeout(3000);
    

    ✅ Better:

    await page.locator('#message').waitFor({ state: 'visible' });
    

    Let Playwright wait for the right condition, not just time.


    🔁 3. Add Retry Logic for CI

    In your playwright.config.js:

    retries: process.env.CI ? 2 : 0
    

    This makes tests more stable on CI servers.


    🔍 4. Use Trace Viewer to Debug

    Run tests with:

    npx playwright test --trace on
    

    After failure:

    npx playwright show-trace trace.zip
    

    This shows a full timeline of what happened.


    🧼 5. Keep Tests Isolated

    Each test should have its own browser context or data to avoid interference. Don’t let tests share state.


    🚫 6. Don’t Depend on Animations or Loading Delays

    If something appears after a scroll or click, wait for it properly:

    await page.locator('#loadedContent').waitFor({ state: 'visible' });
    

    🧠 Final Tip

    Flaky tests waste time and hurt confidence. Fix them by:

    • Using smart waits

    • Avoiding fixed delays

    • Debugging with traces

    • Keeping tests independent



  2. How do you integrate Playwright with CI/CD tools like Jenkins or GitHub Actions?

    Integrating Playwright with CI/CD tools like Jenkins or GitHub Actions is essential for running tests automatically on every code push. Here's a simple explanation for your understanding:


    ✅ Why CI/CD Integration?

    CI/CD ensures your Playwright tests run automatically:

    • After each commit

    • On pull requests

    • In clean environments

    Let’s look at how to do it.


    🛠️ Jenkins Integration

    1. Install Dependencies on Jenkins Server

    Make sure Jenkins has:

    • Node.js

    • Git

    • Playwright (install with npx playwright install)

    2. Create Jenkins Pipeline (Declarative)

    pipeline {
      agent any
    
      stages {
        stage('Install Dependencies') {
          steps {
            sh 'npm ci'
            sh 'npx playwright install --with-deps'
          }
        }
    
        stage('Run Tests') {
          steps {
            sh 'npx playwright test'
          }
        }
    
        stage('Archive Results') {
          steps {
            archiveArtifacts 'playwright-report/**'
          }
        }
      }
    }
    

    3. Optional: Publish HTML Report

    After test run, archive or serve playwright-report/index.html.


    💥 GitHub Actions Integration

    1. Create .github/workflows/playwright.yml

    name: Playwright Tests
    
    on: [push, pull_request]
    
    jobs:
      test:
        runs-on: ubuntu-latest
    
        steps:
          - uses: actions/checkout@v3
    
          - name: Setup Node.js
            uses: actions/setup-node@v3
            with:
              node-version: '18'
    
          - name: Install dependencies
            run: |
              npm ci
              npx playwright install --with-deps
    
          - name: Run tests
            run: npx playwright test
    
          - name: Upload Playwright report
            if: failure()
            uses: actions/upload-artifact@v3
            with:
              name: playwright-report
              path: playwright-report
    

    📦 Bonus Tips

    • Use retries in config to reduce flakiness in CI:

    retries: process.env.CI ? 2 : 0
    
    • Enable tracing:

    npx playwright test --trace on
    

    🔍 Summary

    CI Tool Steps Needed
    Jenkins Pipeline + Shell commands
    GitHub .yml Workflow + Upload artifacts

    Integrating Playwright with CI/CD makes your test suite automated, scalable, and reliable 💪



  3. What challenges have you faced while migrating from Selenium to Playwright?

    Migrating from Selenium to Playwright can be a big step forward — but it comes with some challenges. Here's a concise and breakdown:


    1. ⚙️ Rewriting All Tests

    • Challenge: Playwright uses a completely different API compared to Selenium.

    • Impact: Existing test scripts must be rewritten from scratch.

    • Tip: Focus on key flows first, then gradually migrate others.


    2. 🎯 Locator Strategy Differences

    • Challenge: Selenium heavily relies on XPath or CSS selectors; Playwright encourages getByRole, getByText, etc.

    • Impact: Locators need to be updated for better auto-waiting and stability in Playwright.


    3. 🧪 Switching from TestNG/JUnit to Playwright Test (or Jest)

    • Challenge: Selenium tests are usually built with Java frameworks like TestNG or JUnit.

    • Impact: Test structure needs a revamp using Playwright Test Runner or other JS/TS test frameworks.


    4. 🔐 Authentication & Session Handling

    • Challenge: Selenium stores cookies/sessions differently.

    • Playwright Solution: Use storageState.json for reusing authenticated sessions — a new concept for Selenium users.


    5. 🧰 Framework & Language Shift

    • Challenge: Moving from Java (Selenium) to JavaScript/TypeScript (Playwright).

    • Impact: Requires learning a new language, test runner, and ecosystem (e.g., Node.js, npm).


    6. 📄 Reporting Tools Compatibility

    • Challenge: Tools like Allure, ExtentReports, etc., work out-of-the-box in Selenium Java.

    • Playwright Solution: Needs manual setup or plugins to integrate with custom reports.


    7. 📦 Parallel Execution & Isolation

    • Challenge: Playwright encourages using multiple browser contexts and parallelism.

    • Impact: Tests need to be written keeping parallel-safe practices in mind.


    8. 🔄 Mindset Shift

    • Challenge: Selenium users manually wait for elements.

    • Playwright Advantage: Built-in auto-waiting and retry-ability — requires a new approach to test flow design.


    ✅ Final Thought

    While the migration requires effort, the payoff is huge: faster execution, better stability, and modern automation features.



  4. How would you design a scalable Playwright test framework using JavaScript?

    1. Project Folder Structure

    Organizing files in a structured way helps maintain and grow your test suite.

    playwright-framework/
    ├── tests/                → Contains test files
    ├── pages/                → Page Object classes for UI elements and actions
    ├── utils/                → Helper functions (e.g., random data, API calls)
    ├── fixtures/             → Test data (JSON, JS)
    ├── reports/              → Test execution reports
    ├── playwright.config.js  → Central configuration file
    └── package.json          → Scripts and dependencies
    

    2. Page Object Model (POM)

    Separate UI locators and actions into their own classes.

    Example:

    // pages/LoginPage.js
    class LoginPage {
      constructor(page) {
        this.page = page;
        this.username = page.locator('#username');
        this.password = page.locator('#password');
        this.loginBtn = page.locator('button[type="submit"]');
      }
    
      async login(user, pass) {
        await this.username.fill(user);
        await this.password.fill(pass);
        await this.loginBtn.click();
      }
    }
    
    module.exports = { LoginPage };
    

    3. Writing Tests

    Use Playwright's built-in test runner to write readable and maintainable tests.

    Example:

    const { test, expect } = require('@playwright/test');
    const { LoginPage } = require('../pages/LoginPage');
    
    test('Login with valid credentials', async ({ page }) => {
      const loginPage = new LoginPage(page);
      await page.goto('https://example.com/login');
      await loginPage.login('admin', 'admin123');
      await expect(page).toHaveURL('https://example.com/dashboard');
    });
    

    4. Reuse Setup with Hooks

    Add repeated actions like login, navigation in beforeEach.

    test.beforeEach(async ({ page }) => {
      await page.goto('https://example.com');
    });
    

    5. Managing Test Data

    You can use static files like .json or use dynamic data with faker.js.

    const users = require('../fixtures/users.json');
    

    6. Reports

    Use built-in HTML reporting:

    npx playwright test --reporter=html
    

    Or install Allure for advanced reports:

    npm i -D allure-playwright
    npx allure generate ./allure-results --clean
    npx allure open
    

    7. Multi-Environment Support

    Use environment variables to switch between staging, QA, and production.

    In playwright.config.js:

    use: {
      baseURL: process.env.ENV === 'staging' ? 'https://staging.site.com' : 'https://prod.site.com',
    }
    

    Run with:

    ENV=staging npx playwright test
    

    8. Continuous Integration

    Add test scripts to package.json:

    "scripts": {
      "test": "npx playwright test"
    }
    

    Use this in GitHub Actions or Jenkins to trigger tests on every push or PR.


    9. Tips for Stability

    • Use proper locators (e.g., getByRole, locator('data-test-id'))

    • Retry flaky tests using test.retry(2)

    • Keep your tests atomic and independent

    • Run tests in parallel using workers setting in playwright.config.js



  5. What’s your approach to handling cross-browser testing with Playwright and JavaScript?

    Cross-browser testing with Playwright and JavaScript is simple and efficient, thanks to Playwright’s built-in support for Chromium, Firefox, and WebKit.


    1. Built-in Multi-Browser Support

    Playwright supports:

    • Chromium (Chrome, Edge)

    • Firefox

    • WebKit (Safari)

    You don't need to install anything extra — Playwright downloads all browser binaries automatically.


    2. Configure Browsers in playwright.config.js

    // playwright.config.js
    import { defineConfig, devices } from '@playwright/test';
    
    export default defineConfig({
      projects: [
        {
          name: 'Chromium',
          use: { browserName: 'chromium' },
        },
        {
          name: 'Firefox',
          use: { browserName: 'firefox' },
        },
        {
          name: 'WebKit',
          use: { browserName: 'webkit' },
        },
      ],
    });
    

    3. Writing Tests (No Change Needed)

    Your test cases remain the same. Playwright runs each test against all configured browsers.

    test('Cross-browser login test', async ({ page }) => {
      await page.goto('https://example.com');
      // your test steps...
    });
    

    4. Running Tests

    npx playwright test
    

    This runs the test in all three browsers defined in the config.


    5. Reporting by Browser

    Each browser will generate its own set of results. You can:

    • Use built-in HTML report

    • Use Allure for advanced reporting per browser/project

    npx playwright show-report
    

    ✅ Benefits of This Approach

    • Zero setup for browser drivers

    • Same test code runs on all browsers

    • Easy CI/CD integration for multi-browser execution

    • Supports both desktop and mobile emulation


    🧠 Pro Tip

    You can also limit browsers in CI to speed up execution or only test critical paths in Firefox/WebKit.



💡 Bonus Tips for Your QA Interview

  • Speak from experience: Interviewers love real-world examples.

  • Mention challenges and solutions: Show problem-solving skills.

  • Talk about tools: Mention integrations (Jenkins, Git, Docker, Allure, etc.).

  • Keep learning: Playwright is evolving—follow their GitHub for updates.


🔚 Final Thoughts

Mastering Playwright and JavaScript together can significantly boost your value as a QA automation engineer. These interview questions are designed not only to help you crack interviews but also deepen your understanding of modern test automation practices.

If you're preparing for roles in 2025, focus on practical knowledge, hands-on testing, and tool integration experience. Employers are looking for engineers who can build, maintain, and scale automation frameworks—not just write test cases.

Previous Post Next Post

Contact Form