Koding Tree

Best Software Testing Training Institute in Bangalore

Koding Tree

Software Training Institute

Best Software Testing Training Institute in Bangalore

Koding Tree

Software Training Institute

Best Software Testing Training Institute in Bangalore

Koding Tree

Software Training Institute

Our Programs

Playwright with AI

Koding Tree’s Playwright with AI is a 6-month professional course covering everything from core logic to advanced system architecture and multithreading.

What You Will Learn

  • Playwright – free, open-source, by Microsoft; vs Selenium comparison
  • Install Node.js and verify with node --version
  • Set "type":"module" in package.json for modern ES imports
  • Every Playwright method is async – always use await
  • test(title, async ({page}) => {}){page} fixture is auto-injected
  • Configure headless/headed in playwright.config.js
  • Browser support: Chromium (Chrome/Edge), Firefox, WebKit (Safari)
  • Set up a project with npm init playwright@latest and select JavaScript
  • Playwright ships its own browsers – not the ones installed on your laptop
  • Run: npx playwright test demo.spec.js --headed
  • Install “Playwright Test for VS Code” extension – run tests with one click
  • Available fixtures in tests: {page}, {context}, {browser}

 

WHY THIS MODULE

Playwright is now the industry’s fastest-growing automation tool – adopted by Microsoft, Google, and hundreds of product companies globally. Setting it up correctly from the start, especially understanding async/await and the {page} fixture, means every module that follows will make immediate sense. Companies hiring for Playwright roles expect you to be able to initialise and run a project from scratch in an interview.

What You Will Learn

  • Every button, input, and link is built from HTML – tag + attributes + text
  • Object hierarchy: playwright → browser → context → page
  • page.goBack() / goForward() / reload() / close()
  • page.evaluate(fn) – run JavaScript directly inside the browser
  • Open DevTools (F12) and inspect the code behind any element
  • page.goto(url) – open a web address
  • page.title() – read current title
  • page.setViewportSize({width, height}) – resize the browser window
  • launchOptions: { slowMo: 2000 } – slow down each action by 2 seconds

WHY THIS MODULE

You cannot automate something you do not understand. Knowing that every web element is a piece of HTML with a tag, attributes, and text is what makes every locator module possible. The playwright → browser → context → page hierarchy is also how Playwright isolates test sessions — understanding it prevents hours of debugging when you later run tests in parallel or manage multiple tabs.

What You Will Learn

  • getByAltText() – matches the alt attribute on images; not case-sensitive, allows partial match
  • getByPlaceholder() – matches the greyed-out hint text inside inputs
  • getByText() – finds any element by its visible text content
  • getByRole(role, {name}) – finds by ARIA type: button, textbox, link, etc.
  • Timeout error after 30s when locator finds zero elements
  • Debug live with Playwright Inspector: npx playwright test --headed --debug
  • getByTitle() – matches the title tooltip attribute; not case-sensitive, allows partial match
  • getByLabel() – finds an input by the label that describes it
  • getByTestId() – matches data-testid; case-sensitive, no partial match
  • { exact: true } – force case-sensitive exact match (works for locators 1–5, 7)
  • Strict mode violation when locator matches more than one element
  • Open inspector mid-test: await page.pause()

WHY THIS MODULE

Playwright’s smart locators (getByRole, getByLabel, getByText) are designed to survive UI redesigns — they look for meaning, not HTML structure. Using them means your tests keep working even when developers change a button’s class or ID. This is the approach Playwright’s own documentation recommends first, and what experienced automation engineers use before writing a single XPath.

What You Will Learn

  • Standard CSS syntax: tag[attributeName='value']
  • Class shortcut: button[class='btn']button.btn
  • AND condition: [name='n1'][title='click me'] – both must match
  • Partial match:
    • ^= starts-with
    • *= contains
    • $= ends-with
  • ID shortcut: input[id='u1']input#u1#u1
  • Multi-class element: button.btn.btn-lg.btn-primary
  • OR condition: [name='n1'], [title='click me'] – either matches
  • Text support via Playwright pseudo-classes: :has(), :text(), :text-is()
  • Verify selectors in DevTools → Elements → Ctrl+F before using in code
  • CSS limitation: no native text support – use pseudo-classes or smart locators instead

WHY THIS MODULE

CSS is the fastest locator strategy in Playwright and often the most readable — #login-btn is much cleaner than a long XPath. Understanding partial match operators like *= and ^= is especially useful when element IDs are generated dynamically (e.g., item-4892) — you can target just the stable prefix. CSS is also the backbone of the :has-text() pseudo-class used heavily in test filtering.

What You Will Learn

  • XPath describes the path to an element like an address in the HTML tree
  • Relative: //input[@name='username'] – search anywhere in the tree (preferred)
  • Wildcard: //*[@id='a1'] – any tag with that attribute
  • Logical OR: //input[@name='x' or @id='y']
  • Exact text: //a[text()='Google'] – or dot notation: //a[.='Google']
  • Partial text – contains: //button[contains(.,'Login')]
  • Absolute: /html/body/div[2]/input – full path from root (fragile)
  • Index (1-based): //input[1], (//img)[last()], (//img)[3]
  • Logical AND: //input[@name='x' and @type='text']
  • Logical NOT: //input[not(@placeholder='p')]
  • Partial text – starts-with: //p[starts-with(text(),'User')]
  • Browser supports XPath 1.0 only – ends-with() is not available natively

WHY THIS MODULE

XPath is the most powerful locator strategy — it is the only one that can match elements by their text content, navigate up to parent elements, and handle completely dynamic pages. Every automation engineer needs it in their toolkit for situations where CSS and smart locators fall short. Understanding contains() and and/or/not is what separates a capable engineer from one who gets stuck on hard pages.

What You Will Learn

  • child / – navigate to a direct child element
  • descendant // – reach any element inside a container, any depth
  • following-sibling – move sideways to the next element:
    //th[text()='Subject']/following-sibling::th
  • IE & DE pattern – start from a stable known element (IE) and navigate to a dynamic one (DE)
  • Checkbox by row: //td[.='soap']/../..//input[@type='checkbox']
  • parent /.. – move up to the containing element
  • ancestor – find the table that contains a specific cell:
    //th[text()='Subject']/ancestor::table
  • preceding-sibling – move back to an earlier sibling with optional index
  • Full traversal example:
    //td[.='Pencil']/../td[8] – find price next to product name
  • Real-world practice on Flipkart, Amazon, and MakeMyTrip dynamic listings

WHY THIS MODULE

Most real-world automation challenges involve dynamic tables, e-commerce listings, and dashboards where prices, statuses, and IDs change every page load. The IE & DE pattern — anchor to something stable, navigate to something dynamic — is the professional solution. This is exactly the technique used in production frameworks to automate complex data-entry and verification tasks that no other locator strategy can handle.

Filtering & Multi-Element Handling

  • .filter({ hasText: '...' }) – keep only elements containing this text
  • .filter({ has: page.locator('...') }) – keep elements that contain a child element
  • .first() / .last() / .nth(n) – pick by position (0-indexed)
  • .and(locator) / .or(locator) – combine two locator conditions
  • .allTextContents() / .allInnerTexts() – all visible text as string array
  • .filter({ hasNotText: '...' }) – exclude elements containing this text
  • .filter({ visible: true }) – visible elements only
  • .count() – total number of matched elements
  • .all() – get all matches as an array to loop through

iFrames & Shadow DOM

  • An <iframe> is a page embedded inside another page – common in payment forms and ads
  • page.locator('#f1').contentFrame().locator('#t2') – via content frame method
  • page.frames()[1] – access frame by index in the frames array
  • page.frameLocator('#f1').locator('#t2') – locate the frame then the element inside
  • page.frame({ name: 'n1' }) / page.frame({ url: '...' }) – access by name or URL
  • Shadow DOM – Playwright can reach elements inside shadow roots directly without special handling

WHY THIS MODULE

Real applications show dozens of similar elements — rows in a table, cards in a grid, items in a list. Filtering lets you target the exact one you need without brittle index numbers. And iFrames appear constantly in the real world: payment gateways, embedded maps, chat widgets, and social login buttons all live inside frames. Being comfortable with frameLocator is what makes you productive on real projects from day one.

Interaction Methods

  • click() – left-click
  • click({ button: 'right' }) – right-click
  • dblclick() – double-click
  • fill(value) – clear and type into an input
  • clear() – clear only
  • pressSequentially(text) – type one character at a time like a human
  • press('Enter') – press any keyboard key
  • check() / uncheck() – tick or untick a checkbox
  • hover() – mouse over to reveal tooltip or dropdown
  • dragTo(targetLocator) – drag and drop one element onto another
  • scrollIntoViewIfNeeded() – scroll until element is visible
  • boundingBox() – get position and size as {x, y, width, height}
  • focus() / blur() / highlight() – focus management and debug aid

State Checks & Data Extraction

  • isVisible() / isHidden() / isEnabled() / isChecked()
  • textContent() – all text including hidden
  • innerText() – visible text only
  • getAttribute(name) – read any HTML attribute value
  • inputValue() – current value of an input or textarea
  • screenshot({ path }) – capture just this element
  • page.screenshot() – full page
  • page.dragAndDrop(src, dst) – drag between two selectors on the page
  • page.mouse.move(x, y) / page.keyboard.down('Control') – raw input APIs
  • Run with trace: --trace=on ; replay at trace.playwright.dev

WHY THIS MODULE

Locators tell Playwright what to interact with — actions tell it how. These 33 methods cover nearly every browser interaction. Knowing the difference between fill() (clear then type) and pressSequentially() (key by key) matters for apps that validate input as you type. The trace viewer is one of the most powerful debugging tools in Playwright — replaying failures step by step helps you quickly fix broken tests.

Select / Listbox Handling

  • Listbox built with <select> and <option> tags
  • selectOption({ label: 'Chennai' }) – select by visible label text
  • Multi-select: selectOption(['val1','val2']) – select multiple options at once
  • selectOption({ value: 'b' }) – select by the option’s value attribute
  • selectOption({ index: 3 }) – select by zero-based position
  • Read available options in DevTools console: $("option[value='a']")

JavaScript Popups, HTML Modals & New Tabs

  • JS popup types:
    • alert (message only)
    • confirm (OK/Cancel)
    • prompt (text input)
  • dialog.dismiss() – click Cancel
  • dialog.fill(text) – type into a prompt
  • page.once('dialog', d => d.accept()) – handle the next popup once
  • HTML modal popups – interact as normal elements using regular locators
  • New tab from a click:

     
    const [newPage] = await Promise.all([
    context.waitForEvent(‘page’),
    button.click()
    ])
     
  • Switch between tabs by using the newPage object for subsequent actions

WHY THIS MODULE

Dropdowns, alerts, and popups appear in almost every real application — login pages, forms, confirmation dialogs, and checkout flows all use them. selectOption is simpler than Selenium’s Select class. Handling JS alerts correctly (using page.once before triggering the action) is one of the most commonly asked interview topics for Playwright roles.

What You Will Learn

  • Playwright can test backend APIs – not just browser pages
  • request.post(url, { data: {...} }) – send a POST with a JSON body
  • response.json() – parse and read the response body
  • Browser context – isolated session with its own cookies and storage
  • Combine API + browser testing in the same test – e.g., create a user via API, verify via browser
  • request.get(url) – send a GET request and capture the response
  • response.status() – check the HTTP status code (200, 404, 500)
  • Verify broken links: collect all <a href> elements, request each, check for non-200 status
  • Multiple contexts per browser = multiple isolated sessions running in parallel
  • Use API to set up login state without clicking through the login UI

WHY THIS MODULE

Modern QA roles expect you to test both UI and APIs. Playwright’s built-in request fixture means you don’t need a separate tool like Postman inside your automation suite. More practically, setting up test state via API (like creating users or seeding data) is much faster than doing it through the UI — and it makes your UI tests more reliable because there’s less setup that can fail.

Timeout Configuration

  • Default test timeout: 30,000 ms – override with test.setTimeout(n)
  • test.slow() – triple the current test timeout with one call
  • page.setDefaultTimeout(n) – applies to every action on this page
  • page.setDefaultNavigationTimeout(n) – overrides only for goto/reload/goBack
  • Config-level: use: { actionTimeout: 7000, navigationTimeout: 5000 }
  • Config-level test timeout: timeout: 40000 in defineConfig()

Smart Wait Methods

  • page.waitForTimeout(ms) – blind wait (use only as last resort)
  • States: attached, visible, hidden, detached
  • locator.waitFor() – wait until element is visible (default state)
  • page.waitForSelector('#id') – CSS/XPath version of waitFor
  • page.waitForURL('exact-url') – wait for full URL match after navigation
  • page.waitForURL(url => url.toString().endsWith('home')) – predicate match
  • page.waitForLoadState('networkidle') – page fully settled, no pending requests
  • page.waitForFunction(fn) – wait until a JavaScript condition returns true

WHY THIS MODULE

Flaky tests — tests that sometimes pass and sometimes fail — are the biggest productivity killer in automation. The root cause is almost always a timing problem: the script moves faster than the page. Understanding the difference between a blind waitForTimeout (slow, unreliable) and a smart waitFor or waitForLoadState (fast, reliable) is what separates test suites that just work from ones that constantly need fixing.

Page-Level Assertions

  • expect(page).toHaveTitle('...') – assert current page title
  • expect(page).toHaveURL('...') – assert current URL
  • expect(page).toHaveScreenshot() – visual regression for the full page

Element-Level Assertions

  • toHaveAttribute(name, value) – verify any HTML attribute
  • toBeChecked() / toBeEditable() / toBeAttached() / toBeEmpty()
  • toHaveText('...') – visible text content of an element
  • toHaveCSS('color', 'rgb(0,0,0)') – verify computed CSS style
  • toBeVisible() / toBeHidden() / toBeEnabled() / toBeDisabled()
  • toHaveValue('...') – current value of an input
  • toHaveClass('...') / toHaveId('...')
  • toHaveScreenshot() – visual regression for a single element

Value-Level Assertions & Configuration

  • toBe() / toEqual() / toContain() – strict, deep, and substring checks
  • Default expect timeout: 5000ms – override per assertion: { timeout: 7000 }
  • Global: expect: { timeout: 6000 } in config applies to all assertions
  • toBeLessThan(n) / toBeGreaterThan(n) / toBeLessThanOrEqual(n)
  • Hard assert (default) – stops test immediately on failure
  • Soft assert:
    await expect.soft(el).toHaveValue('...') – continues, collects all failures
  • Negate any assertion:
    await expect(page).not.toHaveTitle('Wrong Title')

WHY THIS MODULE

Without assertions, a test cannot pass or fail — it can only run. Playwright’s expect API is powerful because it automatically retries until the condition becomes true or times out, reducing flaky failures. Knowing when to use soft assertions (collect multiple failures) versus hard assertions (fail fast) is something interviewers often check.

What You Will Learn

  • Import JSON test data:
    import users from './users.json'
    assert { type: 'json' }
  • Read Excel data:
    npm install xlsx
    XLSX.readFile()sheet_to_json()
  • Remote server:
    npx playwright run-server --port 56789 – on the remote machine
  • SauceLabs – cloud platform; configure via saucectl + .sauce/config.yml
  • Limit workers:
    --workers=1 or workers: 2 in config

  • Loop through JSON array with for...of – run one test per data row
  • Compatibility testing – same script runs on Chromium, Firefox, and WebKit
  • Connect from local:
    await chromium.connect('ws://localhost:56789/')
  • Parallel execution:
    npx playwright test --headed – default workers = half your CPUs
  • Run tests in same file in parallel:
    fullyParallel: true in config

WHY THIS MODULE

Data-driven testing transforms a single test into a full test suite. Instead of writing 50 login tests for 50 users, you write one test and drive it from an Excel or JSON file. Parallel execution then runs all tests simultaneously, dramatically reducing execution time and giving faster feedback to developers. These two skills together make automation genuinely useful in real-world teams.


Page Object Model (POM)

  • Encapsulation – declare #private fields, expose via getter/setter
  • export class from each page file; import in spec files
  • Test files use only human-readable method calls – no raw locators
  • JSDoc:

     
    /** @param {import(‘@playwright/test’).Page} page */
     

    – enables VS Code autocomplete

  • One class per page: LoginPage, HomePage, ItemsPage, ItemEditPage
  • Update one POM class when UI changes – all tests fixed instantly

Hooks, Custom Fixtures & Login-Once Strategy

  • test.beforeEach / test.afterEach – auto-run before/after each test in a file
  • test.beforeAll / test.afterAll – run once per file
  • Hooks accept { page, browser, context, browserName, baseURL } fixtures
  • test.skip / test.only / test.describe.skip
  • test.describe('group', () => {}) – group tests with shared setup
  • Custom fixture in base_test.js – reusable beforeEach / afterEach across all files
  • global.setup.js – login once, save state to storageState.json
  • Config: storageState: 'storageState.json' – every test inherits logged-in session
  • global.teardown.js – delete storageState.json after all tests complete

Allure Reports, Tags, GitHub & Jenkins

  • Install:
    npm install --save-dev allure-playwright allure-commandline
  • Generate report:
    npx allure generate allure-results --clean -o allure-report
  • Open report:
    npx allure open allure-report
  • Run by tag:
    npx playwright test --grep @smoke
  • GitHub:
    git init → VS Code Source Control → publish to private repo
  • Build steps:
    call npm installcall npx playwright installcall npx playwright test
  • Automatic trigger: build after code changes – runs when dev deploys
  • Config:
    { "allure-playwright": { "outputFolder": "allure-results" } }
  • Tags:
    test('login @smoke', async (page) => {}) – word starting with @
  • OR tags:
    --grep "@smoke|@sanity"
  • Jenkins Free Style project – SCM: GitHub URL + credentials + branch /main
  • Post-build: Allure plugin; Schedule cron: 0 20 * * * → 8 PM daily

WHY THIS MODULE

This is where everything comes together. The B149_AFW framework is a production-ready automation suite — the same pattern used in professional QA teams at product companies. By the end, you will have a real GitHub repository with POM classes, data-driven tests, Allure reports, and Jenkins integration. This portfolio project is what turns interviews from “tell me about automation” into “let me show you my framework.”

Our Programs

Playwright with AI

Koding Tree’s Playwright with AI is a 6-month professional course covering everything from core logic to advanced system architecture and multithreading.

What You Will Learn

  • Playwright – free, open-source, by Microsoft; vs Selenium comparison
  • Install Node.js and verify with node --version
  • Set "type":"module" in package.json for modern ES imports
  • Every Playwright method is async – always use await
  • test(title, async ({page}) => {}){page} fixture is auto-injected
  • Configure headless/headed in playwright.config.js
  • Browser support: Chromium (Chrome/Edge), Firefox, WebKit (Safari)
  • Set up a project with npm init playwright@latest and select JavaScript
  • Playwright ships its own browsers – not the ones installed on your laptop
  • Run: npx playwright test demo.spec.js --headed
  • Install “Playwright Test for VS Code” extension – run tests with one click
  • Available fixtures in tests: {page}, {context}, {browser}

 

WHY THIS MODULE

Playwright is now the industry’s fastest-growing automation tool – adopted by Microsoft, Google, and hundreds of product companies globally. Setting it up correctly from the start, especially understanding async/await and the {page} fixture, means every module that follows will make immediate sense. Companies hiring for Playwright roles expect you to be able to initialise and run a project from scratch in an interview.

What You Will Learn

  • Every button, input, and link is built from HTML – tag + attributes + text
  • Object hierarchy: playwright → browser → context → page
  • page.goBack() / goForward() / reload() / close()
  • page.evaluate(fn) – run JavaScript directly inside the browser
  • Open DevTools (F12) and inspect the code behind any element
  • page.goto(url) – open a web address
  • page.title() – read current title
  • page.setViewportSize({width, height}) – resize the browser window
  • launchOptions: { slowMo: 2000 } – slow down each action by 2 seconds

WHY THIS MODULE

You cannot automate something you do not understand. Knowing that every web element is a piece of HTML with a tag, attributes, and text is what makes every locator module possible. The playwright → browser → context → page hierarchy is also how Playwright isolates test sessions — understanding it prevents hours of debugging when you later run tests in parallel or manage multiple tabs.

What You Will Learn

  • getByAltText() – matches the alt attribute on images; not case-sensitive, allows partial match
  • getByPlaceholder() – matches the greyed-out hint text inside inputs
  • getByText() – finds any element by its visible text content
  • getByRole(role, {name}) – finds by ARIA type: button, textbox, link, etc.
  • Timeout error after 30s when locator finds zero elements
  • Debug live with Playwright Inspector: npx playwright test --headed --debug
  • getByTitle() – matches the title tooltip attribute; not case-sensitive, allows partial match
  • getByLabel() – finds an input by the label that describes it
  • getByTestId() – matches data-testid; case-sensitive, no partial match
  • { exact: true } – force case-sensitive exact match (works for locators 1–5, 7)
  • Strict mode violation when locator matches more than one element
  • Open inspector mid-test: await page.pause()

WHY THIS MODULE

Playwright’s smart locators (getByRole, getByLabel, getByText) are designed to survive UI redesigns — they look for meaning, not HTML structure. Using them means your tests keep working even when developers change a button’s class or ID. This is the approach Playwright’s own documentation recommends first, and what experienced automation engineers use before writing a single XPath.

What You Will Learn

  • Standard CSS syntax: tag[attributeName='value']
  • Class shortcut: button[class='btn']button.btn
  • AND condition: [name='n1'][title='click me'] – both must match
  • Partial match:
    • ^= starts-with
    • *= contains
    • $= ends-with
  • ID shortcut: input[id='u1']input#u1#u1
  • Multi-class element: button.btn.btn-lg.btn-primary
  • OR condition: [name='n1'], [title='click me'] – either matches
  • Text support via Playwright pseudo-classes: :has(), :text(), :text-is()
  • Verify selectors in DevTools → Elements → Ctrl+F before using in code
  • CSS limitation: no native text support – use pseudo-classes or smart locators instead

WHY THIS MODULE

CSS is the fastest locator strategy in Playwright and often the most readable — #login-btn is much cleaner than a long XPath. Understanding partial match operators like *= and ^= is especially useful when element IDs are generated dynamically (e.g., item-4892) — you can target just the stable prefix. CSS is also the backbone of the :has-text() pseudo-class used heavily in test filtering.

What You Will Learn

  • XPath describes the path to an element like an address in the HTML tree
  • Relative: //input[@name='username'] – search anywhere in the tree (preferred)
  • Wildcard: //*[@id='a1'] – any tag with that attribute
  • Logical OR: //input[@name='x' or @id='y']
  • Exact text: //a[text()='Google'] – or dot notation: //a[.='Google']
  • Partial text – contains: //button[contains(.,'Login')]
  • Absolute: /html/body/div[2]/input – full path from root (fragile)
  • Index (1-based): //input[1], (//img)[last()], (//img)[3]
  • Logical AND: //input[@name='x' and @type='text']
  • Logical NOT: //input[not(@placeholder='p')]
  • Partial text – starts-with: //p[starts-with(text(),'User')]
  • Browser supports XPath 1.0 only – ends-with() is not available natively

WHY THIS MODULE

XPath is the most powerful locator strategy — it is the only one that can match elements by their text content, navigate up to parent elements, and handle completely dynamic pages. Every automation engineer needs it in their toolkit for situations where CSS and smart locators fall short. Understanding contains() and and/or/not is what separates a capable engineer from one who gets stuck on hard pages.

What You Will Learn

  • child / – navigate to a direct child element
  • descendant // – reach any element inside a container, any depth
  • following-sibling – move sideways to the next element:
    //th[text()='Subject']/following-sibling::th
  • IE & DE pattern – start from a stable known element (IE) and navigate to a dynamic one (DE)
  • Checkbox by row: //td[.='soap']/../..//input[@type='checkbox']
  • parent /.. – move up to the containing element
  • ancestor – find the table that contains a specific cell:
    //th[text()='Subject']/ancestor::table
  • preceding-sibling – move back to an earlier sibling with optional index
  • Full traversal example:
    //td[.='Pencil']/../td[8] – find price next to product name
  • Real-world practice on Flipkart, Amazon, and MakeMyTrip dynamic listings

WHY THIS MODULE

Most real-world automation challenges involve dynamic tables, e-commerce listings, and dashboards where prices, statuses, and IDs change every page load. The IE & DE pattern — anchor to something stable, navigate to something dynamic — is the professional solution. This is exactly the technique used in production frameworks to automate complex data-entry and verification tasks that no other locator strategy can handle.

Filtering & Multi-Element Handling

  • .filter({ hasText: '...' }) – keep only elements containing this text
  • .filter({ has: page.locator('...') }) – keep elements that contain a child element
  • .first() / .last() / .nth(n) – pick by position (0-indexed)
  • .and(locator) / .or(locator) – combine two locator conditions
  • .allTextContents() / .allInnerTexts() – all visible text as string array
  • .filter({ hasNotText: '...' }) – exclude elements containing this text
  • .filter({ visible: true }) – visible elements only
  • .count() – total number of matched elements
  • .all() – get all matches as an array to loop through

iFrames & Shadow DOM

  • An <iframe> is a page embedded inside another page – common in payment forms and ads
  • page.locator('#f1').contentFrame().locator('#t2') – via content frame method
  • page.frames()[1] – access frame by index in the frames array
  • page.frameLocator('#f1').locator('#t2') – locate the frame then the element inside
  • page.frame({ name: 'n1' }) / page.frame({ url: '...' }) – access by name or URL
  • Shadow DOM – Playwright can reach elements inside shadow roots directly without special handling

WHY THIS MODULE

Real applications show dozens of similar elements — rows in a table, cards in a grid, items in a list. Filtering lets you target the exact one you need without brittle index numbers. And iFrames appear constantly in the real world: payment gateways, embedded maps, chat widgets, and social login buttons all live inside frames. Being comfortable with frameLocator is what makes you productive on real projects from day one.

Interaction Methods

  • click() – left-click
  • click({ button: 'right' }) – right-click
  • dblclick() – double-click
  • fill(value) – clear and type into an input
  • clear() – clear only
  • pressSequentially(text) – type one character at a time like a human
  • press('Enter') – press any keyboard key
  • check() / uncheck() – tick or untick a checkbox
  • hover() – mouse over to reveal tooltip or dropdown
  • dragTo(targetLocator) – drag and drop one element onto another
  • scrollIntoViewIfNeeded() – scroll until element is visible
  • boundingBox() – get position and size as {x, y, width, height}
  • focus() / blur() / highlight() – focus management and debug aid

State Checks & Data Extraction

  • isVisible() / isHidden() / isEnabled() / isChecked()
  • textContent() – all text including hidden
  • innerText() – visible text only
  • getAttribute(name) – read any HTML attribute value
  • inputValue() – current value of an input or textarea
  • screenshot({ path }) – capture just this element
  • page.screenshot() – full page
  • page.dragAndDrop(src, dst) – drag between two selectors on the page
  • page.mouse.move(x, y) / page.keyboard.down('Control') – raw input APIs
  • Run with trace: --trace=on ; replay at trace.playwright.dev

WHY THIS MODULE

Locators tell Playwright what to interact with — actions tell it how. These 33 methods cover nearly every browser interaction. Knowing the difference between fill() (clear then type) and pressSequentially() (key by key) matters for apps that validate input as you type. The trace viewer is one of the most powerful debugging tools in Playwright — replaying failures step by step helps you quickly fix broken tests.

Select / Listbox Handling

  • Listbox built with <select> and <option> tags
  • selectOption({ label: 'Chennai' }) – select by visible label text
  • Multi-select: selectOption(['val1','val2']) – select multiple options at once
  • selectOption({ value: 'b' }) – select by the option’s value attribute
  • selectOption({ index: 3 }) – select by zero-based position
  • Read available options in DevTools console: $("option[value='a']")

JavaScript Popups, HTML Modals & New Tabs

  • JS popup types:
    • alert (message only)
    • confirm (OK/Cancel)
    • prompt (text input)
  • dialog.dismiss() – click Cancel
  • dialog.fill(text) – type into a prompt
  • page.once('dialog', d => d.accept()) – handle the next popup once
  • HTML modal popups – interact as normal elements using regular locators
  • New tab from a click:

     
    const [newPage] = await Promise.all([
    context.waitForEvent(‘page’),
    button.click()
    ])
     
  • Switch between tabs by using the newPage object for subsequent actions

WHY THIS MODULE

Dropdowns, alerts, and popups appear in almost every real application — login pages, forms, confirmation dialogs, and checkout flows all use them. selectOption is simpler than Selenium’s Select class. Handling JS alerts correctly (using page.once before triggering the action) is one of the most commonly asked interview topics for Playwright roles.

What You Will Learn

  • Playwright can test backend APIs – not just browser pages
  • request.post(url, { data: {...} }) – send a POST with a JSON body
  • response.json() – parse and read the response body
  • Browser context – isolated session with its own cookies and storage
  • Combine API + browser testing in the same test – e.g., create a user via API, verify via browser
  • request.get(url) – send a GET request and capture the response
  • response.status() – check the HTTP status code (200, 404, 500)
  • Verify broken links: collect all <a href> elements, request each, check for non-200 status
  • Multiple contexts per browser = multiple isolated sessions running in parallel
  • Use API to set up login state without clicking through the login UI

WHY THIS MODULE

Modern QA roles expect you to test both UI and APIs. Playwright’s built-in request fixture means you don’t need a separate tool like Postman inside your automation suite. More practically, setting up test state via API (like creating users or seeding data) is much faster than doing it through the UI — and it makes your UI tests more reliable because there’s less setup that can fail.

Timeout Configuration

  • Default test timeout: 30,000 ms – override with test.setTimeout(n)
  • test.slow() – triple the current test timeout with one call
  • page.setDefaultTimeout(n) – applies to every action on this page
  • page.setDefaultNavigationTimeout(n) – overrides only for goto/reload/goBack
  • Config-level: use: { actionTimeout: 7000, navigationTimeout: 5000 }
  • Config-level test timeout: timeout: 40000 in defineConfig()

Smart Wait Methods

  • page.waitForTimeout(ms) – blind wait (use only as last resort)
  • States: attached, visible, hidden, detached
  • locator.waitFor() – wait until element is visible (default state)
  • page.waitForSelector('#id') – CSS/XPath version of waitFor
  • page.waitForURL('exact-url') – wait for full URL match after navigation
  • page.waitForURL(url => url.toString().endsWith('home')) – predicate match
  • page.waitForLoadState('networkidle') – page fully settled, no pending requests
  • page.waitForFunction(fn) – wait until a JavaScript condition returns true

WHY THIS MODULE

Flaky tests — tests that sometimes pass and sometimes fail — are the biggest productivity killer in automation. The root cause is almost always a timing problem: the script moves faster than the page. Understanding the difference between a blind waitForTimeout (slow, unreliable) and a smart waitFor or waitForLoadState (fast, reliable) is what separates test suites that just work from ones that constantly need fixing.

Page-Level Assertions

  • expect(page).toHaveTitle('...') – assert current page title
  • expect(page).toHaveURL('...') – assert current URL
  • expect(page).toHaveScreenshot() – visual regression for the full page

Element-Level Assertions

  • toHaveAttribute(name, value) – verify any HTML attribute
  • toBeChecked() / toBeEditable() / toBeAttached() / toBeEmpty()
  • toHaveText('...') – visible text content of an element
  • toHaveCSS('color', 'rgb(0,0,0)') – verify computed CSS style
  • toBeVisible() / toBeHidden() / toBeEnabled() / toBeDisabled()
  • toHaveValue('...') – current value of an input
  • toHaveClass('...') / toHaveId('...')
  • toHaveScreenshot() – visual regression for a single element

Value-Level Assertions & Configuration

  • toBe() / toEqual() / toContain() – strict, deep, and substring checks
  • Default expect timeout: 5000ms – override per assertion: { timeout: 7000 }
  • Global: expect: { timeout: 6000 } in config applies to all assertions
  • toBeLessThan(n) / toBeGreaterThan(n) / toBeLessThanOrEqual(n)
  • Hard assert (default) – stops test immediately on failure
  • Soft assert:
    await expect.soft(el).toHaveValue('...') – continues, collects all failures
  • Negate any assertion:
    await expect(page).not.toHaveTitle('Wrong Title')

WHY THIS MODULE

Without assertions, a test cannot pass or fail — it can only run. Playwright’s expect API is powerful because it automatically retries until the condition becomes true or times out, reducing flaky failures. Knowing when to use soft assertions (collect multiple failures) versus hard assertions (fail fast) is something interviewers often check.

What You Will Learn

  • Import JSON test data:
    import users from './users.json'
    assert { type: 'json' }
  • Read Excel data:
    npm install xlsx
    XLSX.readFile()sheet_to_json()
  • Remote server:
    npx playwright run-server --port 56789 – on the remote machine
  • SauceLabs – cloud platform; configure via saucectl + .sauce/config.yml
  • Limit workers:
    --workers=1 or workers: 2 in config

  • Loop through JSON array with for...of – run one test per data row
  • Compatibility testing – same script runs on Chromium, Firefox, and WebKit
  • Connect from local:
    await chromium.connect('ws://localhost:56789/')
  • Parallel execution:
    npx playwright test --headed – default workers = half your CPUs
  • Run tests in same file in parallel:
    fullyParallel: true in config

WHY THIS MODULE

Data-driven testing transforms a single test into a full test suite. Instead of writing 50 login tests for 50 users, you write one test and drive it from an Excel or JSON file. Parallel execution then runs all tests simultaneously, dramatically reducing execution time and giving faster feedback to developers. These two skills together make automation genuinely useful in real-world teams.


Page Object Model (POM)

  • Encapsulation – declare #private fields, expose via getter/setter
  • export class from each page file; import in spec files
  • Test files use only human-readable method calls – no raw locators
  • JSDoc:

     
    /** @param {import(‘@playwright/test’).Page} page */
     

    – enables VS Code autocomplete

  • One class per page: LoginPage, HomePage, ItemsPage, ItemEditPage
  • Update one POM class when UI changes – all tests fixed instantly

Hooks, Custom Fixtures & Login-Once Strategy

  • test.beforeEach / test.afterEach – auto-run before/after each test in a file
  • test.beforeAll / test.afterAll – run once per file
  • Hooks accept { page, browser, context, browserName, baseURL } fixtures
  • test.skip / test.only / test.describe.skip
  • test.describe('group', () => {}) – group tests with shared setup
  • Custom fixture in base_test.js – reusable beforeEach / afterEach across all files
  • global.setup.js – login once, save state to storageState.json
  • Config: storageState: 'storageState.json' – every test inherits logged-in session
  • global.teardown.js – delete storageState.json after all tests complete

Allure Reports, Tags, GitHub & Jenkins

  • Install:
    npm install --save-dev allure-playwright allure-commandline
  • Generate report:
    npx allure generate allure-results --clean -o allure-report
  • Open report:
    npx allure open allure-report
  • Run by tag:
    npx playwright test --grep @smoke
  • GitHub:
    git init → VS Code Source Control → publish to private repo
  • Build steps:
    call npm installcall npx playwright installcall npx playwright test
  • Automatic trigger: build after code changes – runs when dev deploys
  • Config:
    { "allure-playwright": { "outputFolder": "allure-results" } }
  • Tags:
    test('login @smoke', async (page) => {}) – word starting with @
  • OR tags:
    --grep "@smoke|@sanity"
  • Jenkins Free Style project – SCM: GitHub URL + credentials + branch /main
  • Post-build: Allure plugin; Schedule cron: 0 20 * * * → 8 PM daily

WHY THIS MODULE

This is where everything comes together. The B149_AFW framework is a production-ready automation suite — the same pattern used in professional QA teams at product companies. By the end, you will have a real GitHub repository with POM classes, data-driven tests, Allure reports, and Jenkins integration. This portfolio project is what turns interviews from “tell me about automation” into “let me show you my framework.”

Live Projects You Will Build

Flight Booking API

Microservices based airline reservation backend.

E-Commerce Platform

Full-featured Amazon clone with Cart & Payment Gateway.

Smart Banking System

Secure transaction portal with Spring Security & JWT.

Hospital Management

Patient records & doctor booking system.