Skip to content

siraajul/testkart

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

25 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ›’ TestKart

BDD + Page Object Model Automation Framework

A production-grade SDET automation framework built with a pure JavaScript stack to automate real-world e-commerce scenarios on Flipkart.com

Node.js Playwright Cucumber License

๐Ÿ“– Read the Full Case Study โ†’


๐Ÿ“‹ Table of Contents


๐ŸŽฏ Challenge Overview

This framework was built as a 3-hour SDET interview challenge โ€” ported from the original Java/Selenium stack to a modern JavaScript ecosystem:

Requirement Status
Build BDD / POM automation framework from scratch โœ…
Navigate to Flipkart homepage โœ…
Handle unexpected promotional pop-ups โœ…
Search for "Shoes for Men" โœ…
Implement pagination (Page 1 & 2) โœ…
Extract MRP & Discount Percentage โœ…
Ensure proper browser teardown โœ…

๐Ÿ”ง Tech Stack

The original challenge specified Java/Selenium โ€” this framework reimplements it using a modern JS stack:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Original Stack    โ†’    JS Stack               โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚           Java              โ†’    Node.js                โ”‚
โ”‚           Selenium          โ†’    Playwright              โ”‚
โ”‚           TestNG            โ†’    Cucumber.js (BDD)       โ”‚
โ”‚           Maven             โ†’    npm                     โ”‚
โ”‚           Eclipse           โ†’    VS Code                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
Technology Role Why This Choice
Node.js Runtime Fast, async-native, huge ecosystem
Playwright Browser Automation Auto-wait, superior popup handling, built-in assertions
Cucumber.js BDD Framework Gherkin syntax, readable by non-technical stakeholders
dotenv Configuration Environment-based config (headed/headless, timeouts)
Page Object Model Design Pattern Maintainable, reusable, scalable test architecture

๐Ÿ— Architecture

High-Level Data Flow

graph TD
    A["๐Ÿฅ’ Feature File<br/><i>Gherkin BDD Scenario</i>"] --> B["๐Ÿ“ Step Definitions<br/><i>Maps steps to actions</i>"]
    B --> C["๐Ÿ“„ Page Objects<br/><i>POM Layer</i>"]
    C --> D["๐ŸŽญ Playwright<br/><i>Browser Engine</i>"]
    D --> E["๐ŸŒ Flipkart.com<br/><i>Target Application</i>"]

    F["โš™๏ธ cucumber.js<br/><i>Runner Config</i>"] -.-> B
    G["๐Ÿ”„ hooks.js<br/><i>Lifecycle Hooks</i>"] -.-> D
    H["๐Ÿ” .env<br/><i>Environment Config</i>"] -.-> G
    I["๐Ÿ“Š logger.js<br/><i>Output Formatter</i>"] -.-> B
Loading

Layer Responsibility

graph LR
    subgraph "BDD Layer"
        A[Feature Files]
        B[Step Definitions]
    end
    subgraph "POM Layer"
        C[BasePage]
        D[HomePage]
        E[SearchResultsPage]
    end
    subgraph "Infrastructure"
        F[World Context]
        G[Hooks]
        H[Logger]
    end
    subgraph "External"
        I[Playwright]
        J[Flipkart.com]
    end

    A --> B
    B --> D
    B --> E
    D --> C
    E --> C
    C --> I
    I --> J
    F --> D
    F --> E
    G --> I
    B --> H
Loading

๐Ÿ“ Project Structure

testkart/
โ”‚
โ”œโ”€โ”€ ๐Ÿ“„ package.json                    # Dependencies & npm scripts
โ”œโ”€โ”€ ๐Ÿ“„ cucumber.js                     # Cucumber runner configuration
โ”œโ”€โ”€ ๐Ÿ“„ .env                            # Environment variables (URL, timeouts, browser)
โ”œโ”€โ”€ ๐Ÿ“„ .gitignore                      # Git exclusions
โ”œโ”€โ”€ ๐Ÿ“„ README.md                       # This file
โ”‚
โ”œโ”€โ”€ ๐Ÿฅ’ features/                       # โ”€โ”€ BDD LAYER โ”€โ”€
โ”‚   โ””โ”€โ”€ flipkart-shoes.feature         # Gherkin scenario (human-readable)
โ”‚
โ”œโ”€โ”€ ๐Ÿ“ step-definitions/               # โ”€โ”€ GLUE CODE โ”€โ”€
โ”‚   โ””โ”€โ”€ flipkart-shoes.steps.js        # Maps Gherkin โ†’ Page Object calls
โ”‚
โ”œโ”€โ”€ ๐Ÿ“„ pages/                          # โ”€โ”€ PAGE OBJECT MODEL โ”€โ”€
โ”‚   โ”œโ”€โ”€ BasePage.js                    # Abstract base (navigate, wait, click, screenshot)
โ”‚   โ”œโ”€โ”€ HomePage.js                    # Flipkart home (popup handling, search)
โ”‚   โ””โ”€โ”€ SearchResultsPage.js           # Search results (pagination, data extraction)
โ”‚
โ”œโ”€โ”€ โš™๏ธ support/                         # โ”€โ”€ FRAMEWORK INFRASTRUCTURE โ”€โ”€
โ”‚   โ”œโ”€โ”€ world.js                       # Custom Cucumber World (browser + data store)
โ”‚   โ””โ”€โ”€ hooks.js                       # Before/After hooks (launch, teardown, screenshots)
โ”‚
โ”œโ”€โ”€ ๐Ÿ›  utils/                           # โ”€โ”€ UTILITIES โ”€โ”€
โ”‚   โ””โ”€โ”€ logger.js                      # Formatted console tables & statistics
โ”‚
โ”œโ”€โ”€ ๐Ÿ“Š reports/                        # Generated HTML/JSON test reports
โ””โ”€โ”€ ๐Ÿ“ธ screenshots/                    # Failure screenshots (auto-captured)

File Dependency Graph

graph TD
    hooks["hooks.js"] --> world["world.js"]
    hooks --> dotenv[".env"]
    world --> HomePage["HomePage.js"]
    world --> SearchResultsPage["SearchResultsPage.js"]
    HomePage --> BasePage["BasePage.js"]
    SearchResultsPage --> BasePage
    steps["flipkart-shoes.steps.js"] --> world
    steps --> logger["logger.js"]
    feature["flipkart-shoes.feature"] --> steps
    cucumber["cucumber.js"] --> feature
    cucumber --> steps
    cucumber --> hooks

    style feature fill:#23D96C,color:#fff
    style BasePage fill:#2563EB,color:#fff
    style HomePage fill:#3B82F6,color:#fff
    style SearchResultsPage fill:#3B82F6,color:#fff
    style hooks fill:#F59E0B,color:#fff
    style world fill:#F59E0B,color:#fff
Loading

๐Ÿš€ Quick Start

Prerequisites

  • Node.js v18+ installed
  • npm v9+ installed

Installation & Run

# 1๏ธโƒฃ  Clone and enter the project
cd testkart

# 2๏ธโƒฃ  Install dependencies
npm install

# 3๏ธโƒฃ  Install Playwright's Chromium browser
npm run install:browsers

# 4๏ธโƒฃ  Run the test suite (headed mode โ€” watch the browser)
npm test

# 5๏ธโƒฃ  Or run in headless mode (for CI/CD)
npm run test:headless

โšก How It Works

End-to-End Test Flow

sequenceDiagram
    participant C as ๐Ÿฅ’ Cucumber Runner
    participant H as ๐Ÿ”„ Hooks
    participant S as ๐Ÿ“ Step Definitions
    participant P as ๐Ÿ“„ Page Objects
    participant B as ๐ŸŽญ Playwright Browser
    participant F as ๐ŸŒ Flipkart.com

    C->>H: Before Hook
    H->>B: Launch Chromium
    B-->>H: Browser Ready

    C->>S: Given: Navigate to homepage
    S->>P: HomePage.open()
    P->>B: page.goto(flipkart.com)
    B->>F: HTTP Request
    F-->>B: HTML Response
    B-->>P: Page Loaded

    C->>S: And: Handle pop-ups
    S->>P: HomePage.dismissPopup()
    P->>B: Escape / Close Button
    B-->>P: Popup Dismissed

    C->>S: When: Search "Shoes for Men"
    S->>P: HomePage.searchProduct()
    P->>B: Fill & Submit
    B->>F: Search Request
    F-->>B: Results Page

    C->>S: Then: Extract data (Page 1)
    S->>P: SearchResultsPage.extractProductData(1)
    P->>B: page.evaluate() โ€” DOM scan
    B-->>P: Product Array [40 items]

    C->>S: When: Navigate to Page 2
    S->>P: SearchResultsPage.goToPage(2)
    P->>B: Click pagination / URL param
    B->>F: Page 2 Request
    F-->>B: Page 2 Results

    C->>S: Then: Extract data (Page 2)
    S->>P: SearchResultsPage.extractProductData(2)
    P->>B: page.evaluate() โ€” DOM scan
    B-->>P: Product Array [40 items]

    C->>S: Then: Display consolidated results
    S->>S: Logger.displayConsolidatedResults()
    Note over S: ๐Ÿ“Š 80+ products displayed

    C->>H: After Hook
    H->>B: page.close() โ†’ context.close() โ†’ browser.close()
    B-->>H: โœ… Teardown Complete
Loading

๐Ÿ“„ Page Object Model Design

The POM pattern encapsulates all page interactions into reusable, maintainable classes:

Class Hierarchy

classDiagram
    class BasePage {
        +Page page
        +int defaultTimeout
        +navigate(url)
        +getTitle()
        +getCurrentUrl()
        +waitForPageLoad()
        +waitForElement(selector)
        +isElementVisible(selector)
        +click(selector)
        +type(selector, text)
        +getText(selector)
        +takeScreenshot(name)
    }

    class HomePage {
        +String searchInput
        +String popupCloseButton
        +open()
        +dismissPopup()
        +searchProduct(term)
    }

    class SearchResultsPage {
        +String productCard
        +String sellingPrice
        +String originalMRP
        +hasSearchResults()
        +extractProductData(pageNum)
        +goToPage(targetPage)
        +getCurrentPageNumber()
        +scrollToLoadAllProducts()
    }

    BasePage <|-- HomePage : extends
    BasePage <|-- SearchResultsPage : extends
Loading

What Each Page Handles

Page Object Responsibilities Key Methods
BasePage Navigation, waits, clicks, screenshots navigate(), waitForPageLoad(), isElementVisible()
HomePage Flipkart homepage interactions open(), dismissPopup(), searchProduct()
SearchResultsPage Product data & pagination extractProductData(), goToPage(), scrollToLoadAllProducts()

๐Ÿฅ’ BDD Scenario

The test scenario is written in Gherkin โ€” a human-readable format that serves as both documentation and executable specification:

@flipkart @shoes @e2e
Feature: Flipkart Men's Shoes โ€” Search & Data Extraction

  Scenario: Extract MRP and Discount Percentage from Page 1 and Page 2
    Given I navigate to the Flipkart homepage
    And I handle any promotional pop-ups
    When I search for "Shoes for Men"
    Then I should see search results for shoes

    When I scroll to load all products on the current page
    Then I extract MRP and Discount Percentage from page 1
    And I display the results for page 1

    When I navigate to page 2
    Then I should be on page 2

    When I scroll to load all products on the current page
    Then I extract MRP and Discount Percentage from page 2
    And I display the results for page 2

    Then I display the consolidated results from all pages

Step Mapping Flow

Feature File (WHAT)  โ†’  Step Definitions (HOW)  โ†’  Page Objects (WHERE)
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

"I navigate to homepage"  โ†’  Given step  โ†’  HomePage.open()
"I handle pop-ups"        โ†’  Given step  โ†’  HomePage.dismissPopup()
"I search for X"          โ†’  When step   โ†’  HomePage.searchProduct(X)
"I extract data from N"   โ†’  Then step   โ†’  SearchResultsPage.extractProductData(N)
"I navigate to page N"    โ†’  When step   โ†’  SearchResultsPage.goToPage(N)
"display consolidated"    โ†’  Then step   โ†’  Logger.displayConsolidatedResults()

๐Ÿ” Data Extraction Strategy

The Problem

Flipkart uses obfuscated CSS class names (e.g., _2WkVRV, Nx9bqj) that change frequently with every deployment. Traditional selector-based scraping breaks constantly.

The Solution: Content-Pattern Detection

Instead of relying on class names, our extraction uses content patterns and CSS computed styles:

flowchart TD
    A["๐Ÿ” Scan ALL div/span elements"] --> B{"Contains<br/>'XX% off'?"}
    B -->|Yes| C["๐Ÿ“Œ Found Discount Element"]
    B -->|No| D["Skip"]

    C --> E["โฌ†๏ธ Walk UP DOM tree<br/>to find product card container"]
    E --> F{"Has image +<br/>โ‚น price +<br/>height 100-800px?"}
    F -->|Yes| G["โœ… Found Product Card"]
    F -->|No| H["โฌ†๏ธ Go up one more level"]
    H --> F

    G --> I["Extract from card:"]
    I --> J["๐Ÿ’ฐ Selling Price<br/><i>โ‚นXXX without strikethrough</i>"]
    I --> K["๐Ÿท๏ธ MRP<br/><i>โ‚นXXX with line-through CSS</i>"]
    I --> L["๐Ÿ“‰ Discount<br/><i>XX% off text</i>"]
    I --> M["๐Ÿ“ Title<br/><i>Link text > 10 chars</i>"]

    style C fill:#23D96C,color:#fff
    style G fill:#2563EB,color:#fff
    style J fill:#F59E0B,color:#000
    style K fill:#EF4444,color:#fff
    style L fill:#8B5CF6,color:#fff
Loading

Detection Rules

Data Point Detection Method
Discount Regex: /^\d+%\s*off$/i on leaf elements
Selling Price Regex: /^โ‚น[\d,]+$/ + NO text-decoration: line-through
MRP Regex: /^โ‚น[\d,]+$/ + HAS text-decoration: line-through
Product Title <a> tag text > 10 chars, not starting with โ‚น or %
Product Card Ancestor with <img> + price elements + height 100-800px

โš™๏ธ Environment Configuration

All runtime settings are controlled via the .env file:

# Flipkart Base URL
BASE_URL=https://www.flipkart.com/

# Search Configuration
SEARCH_TERM=Shoes for Men

# Browser Configuration
HEADLESS=false          # true = CI mode, false = watch the browser
SLOW_MO=100             # Delay between actions (ms) for visibility
VIEWPORT_WIDTH=1440     # Browser window width
VIEWPORT_HEIGHT=900     # Browser window height

# Pagination
MAX_PAGES=2             # Number of pages to scrape

# Timeouts (ms)
DEFAULT_TIMEOUT=30000   # Wait timeout for elements
NAVIGATION_TIMEOUT=45000 # Page navigation timeout

Where Each Variable Is Used

graph LR
    ENV[".env File"] --> hooks["hooks.js<br/><i>dotenv.config()</i>"]

    hooks --> world["world.js"]
    hooks --> base["BasePage.js"]
    hooks --> home["HomePage.js"]

    world --> |HEADLESS| B1["Browser Mode"]
    world --> |SLOW_MO| B2["Action Speed"]
    world --> |VIEWPORT_*| B3["Window Size"]
    world --> |*_TIMEOUT| B4["Page Timeouts"]

    base --> |DEFAULT_TIMEOUT| B5["Element Waits"]
    base --> |NAVIGATION_TIMEOUT| B6["goto() Timeout"]

    home --> |BASE_URL| B7["Flipkart URL"]

    style ENV fill:#F59E0B,color:#000
    style B1 fill:#3B82F6,color:#fff
    style B2 fill:#3B82F6,color:#fff
    style B3 fill:#3B82F6,color:#fff
Loading

๐Ÿ”„ Test Lifecycle

Browser Lifecycle Management

stateDiagram-v2
    [*] --> BeforeHook: Scenario Start

    BeforeHook --> BrowserLaunch: launchBrowser()
    BrowserLaunch --> ContextCreate: newContext(viewport, userAgent)
    ContextCreate --> PageCreate: newPage()
    PageCreate --> TestExecution: Page Objects Ready

    TestExecution --> ScenarioPass: All Steps โœ…
    TestExecution --> ScenarioFail: Step Failure โŒ

    ScenarioFail --> ScreenshotCapture: page.screenshot()
    ScreenshotCapture --> AfterHook

    ScenarioPass --> AfterHook

    AfterHook --> PageClose: page.close()
    PageClose --> ContextClose: context.close()
    ContextClose --> BrowserClose: browser.close()
    BrowserClose --> [*]: Teardown Complete โœ…
Loading

Popup Handling Strategy

The framework uses a multi-strategy fallback approach for popup dismissal:

Strategy 1: CSS class-based close button     โ†’ Try first
    โ†“ (failed)
Strategy 2: XPath-based close button         โ†’ Fallback
    โ†“ (failed)
Strategy 3: Generic text-based close button  โ†’ Broader match
    โ†“ (failed)
Strategy 4: Escape key press                 โ†’ Universal fallback
    โ†“ (failed)
Result: Log "No popup detected" and continue โ†’ Graceful handling

Pagination Strategy

Strategy 1: Click page number link directly   โ†’ Most precise
    โ†“ (failed)
Strategy 2: Click "Next" button               โ†’ Common pattern
    โ†“ (failed)
Strategy 3: URL parameter manipulation        โ†’ Most reliable fallback
             (?page=2 appended to URL)

๐Ÿ“Š Sample Output

Console Output

  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  ๐Ÿš€ TestKart โ€” Launching Browser
  โ”€โ”€ Mode: Headed
  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  ๐ŸŒ Navigating to: https://www.flipkart.com/
  โœ… Page loaded: Online Shopping Site for Mobiles...
  ๐Ÿ” Checking for promotional pop-ups...
  โœ… Pop-up dismissed using: Escape key
  ๐Ÿ”Ž Searching for: "Shoes for Men"
  โœ… Search results loaded for: "Shoes for Men"
  โœ… Search results are displayed

  ๐Ÿ“ฆ Extracting product data from Page 1...
  โœ… Extracted 45 products from Page 1

  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚  ๐Ÿ“„ PAGE 1 RESULTS โ€” 45 Products Found                     โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  โ”Œโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚   โ”‚ #  โ”‚ Product                     โ”‚ Price    โ”‚ MRP     โ”‚ Discount  โ”‚
  โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
  โ”‚ 0 โ”‚ 1  โ”‚ Exclusive Trendy Sports...  โ”‚ โ‚น256     โ”‚ โ‚น1,299  โ”‚ 80% off   โ”‚
  โ”‚ 1 โ”‚ 2  โ”‚ Trendy & Stylish Runnin... โ”‚ โ‚น240     โ”‚ โ‚น999    โ”‚ 75% off   โ”‚
  โ”‚ 2 โ”‚ 3  โ”‚ ES-21 Hockey Walking/...   โ”‚ โ‚น452     โ”‚ โ‚น1,999  โ”‚ 77% off   โ”‚
  โ”‚...โ”‚... โ”‚ ...                         โ”‚ ...      โ”‚ ...     โ”‚ ...       โ”‚
  โ””โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

  ๐Ÿ“„ Navigating to Page 2...
  โœ… Navigated to Page 2

  ๐Ÿ“ฆ Extracting product data from Page 2...
  โœ… Extracted 45 products from Page 2

  โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
  โ•‘  ๐Ÿ“Š CONSOLIDATED RESULTS โ€” ALL PAGES            โ•‘
  โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
  โ•‘  ๐Ÿ“„ Page 1: 45 products                         โ•‘
  โ•‘  ๐Ÿ“„ Page 2: 45 products                         โ•‘
  โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
  โ•‘  ๐Ÿ“ฆ Total Products Extracted: 90                 โ•‘
  โ•‘  ๐Ÿ’ฐ Products with MRP: 90                        โ•‘
  โ•‘  ๐Ÿท๏ธ  Products with Discount: 80                  โ•‘
  โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  ๐ŸŽฏ Total products extracted: 90
  โœ… Data extraction complete!

  ๐Ÿงน Tearing down browser...
  โœ… Browser teardown complete

  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
  ๐Ÿ TestKart โ€” Test Execution Complete
  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  ๐Ÿ“Š Reports: reports/cucumber-report.html
  ๐Ÿ“ธ Screenshots: screenshots/
  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

  1 scenario (1 passed)
  13 steps (13 passed)
  0m37.400s

๐Ÿ“ฆ NPM Scripts

Script Command Description
npm test npx cucumber-js Run all BDD scenarios (headed)
npm run test:headed HEADLESS=false npx cucumber-js Explicitly headed mode
npm run test:headless HEADLESS=true npx cucumber-js Headless mode (CI/CD)
npm run install:browsers npx playwright install chromium Download Chromium
npm run pretest mkdir -p reports screenshots Create output directories

๐Ÿ’ก Design Decisions

Why Playwright over Selenium?

Feature Selenium Playwright
Auto-wait for elements โŒ Manual waits โœ… Built-in
Popup handling โŒ Complex โœ… Native support
page.evaluate() for DOM โŒ Limited โœ… Full browser context
Network interception โŒ Requires proxy โœ… Built-in
Speed ๐Ÿข Slower ๐Ÿš€ Faster
Multi-browser support โœ… Yes โœ… Yes

Why Content-Based Extraction?

Flipkart uses obfuscated, randomly-generated CSS class names that change with every deployment (e.g., _2WkVRV, Nx9bqj, slAVV4). Our approach:

  • โŒ Class-based selectors โ†’ Break with every Flipkart deploy
  • โœ… Content patterns (โ‚น symbol, % off, strikethrough CSS) โ†’ Resilient to UI changes

Why Custom Cucumber World?

The World object serves as a shared context across all step definitions:

World = {
  browser,              // Playwright Browser instance
  context,              // Browser Context (viewport, cookies)
  page,                 // Active Page
  homePage,             // HomePage POM instance
  searchResultsPage,    // SearchResultsPage POM instance
  productsData: []      // Accumulated product data across pages
}

๐Ÿ”ฎ Extending the Framework

Adding a New Page Object

// pages/ProductDetailPage.js
const BasePage = require('./BasePage');

class ProductDetailPage extends BasePage {
  constructor(page) {
    super(page);
    // Define locators
  }
  // Define methods
}
module.exports = ProductDetailPage;

Adding a New Scenario

# features/flipkart-electronics.feature
@electronics
Scenario: Search and extract laptop prices
  Given I navigate to the Flipkart homepage
  When I search for "Laptops"
  Then I extract pricing data from page 1

Built with โค๏ธ for the SDET Community

TestKart โ€” Because real SDET interviews test what you can build, not what you can memorize.

About

๐Ÿ›’ BDD + POM automation framework (Playwright + Cucumber.js) โ€” inspired by a LinkedIn SDET challenge post. Automates Flipkart e-commerce: search, pagination & dynamic data extraction using content-pattern detection resilient to obfuscated CSS selectors. Pure JS stack over Java/Selenium ๐Ÿš€

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors