Skip to content

B2BProjectTest โ€” Interview Prep

One-liner: A Java + Selenium 4 + TestNG + REST Assured UI-and-API automation framework for a B2B e-commerce / PIM platform (Avysh), built on a three-layer Page Object Model with a helper/facade layer, JSON-driven test data, custom ExtentReports, a retry analyzer, and Angular-aware synchronization.


1. Elevator pitch

30-second version:

"B2BProjectTest is the regression and smoke automation framework for Avysh, a B2B e-commerce platform where brands publish products, sellers resell them, and buyers order through storefronts. It's Java with Selenium 4, TestNG, and REST Assured for the order APIs. The design is three-layered โ€” tests call helper classes, helpers orchestrate page objects, and page objects extend a common utilities base โ€” so tests read like business flows. It's data-driven from JSON, uses Angular-aware waits since the app is Angular, has a TestNG listener that auto-retries failed tests once, and generates custom ExtentReports with screenshots on failure."

2-minute version adds: the suites map to the platform's roles โ€” brandPIM (brand-side product management), sellerPIM (seller-side), orderAPI (REST Assured order API), integration (admin onboards a brand), and Smoke (orders flow). Selenium driver binaries are bundled per-OS, assertions use AssertJ SoftAssertions so a test reports all field mismatches at once, and a custom exception layer captures screenshots and formats HTML traces distinguishing "script issue" from "application issue."


2. The application under test

Avysh (https://qa.avishk.in, tenant storefronts like https://missbeautiful.avishk.in) โ€” a multi-tenant B2B commerce / PIM (Product Information Management) platform. Three actor roles drive the suites: - Brand users manage their own catalog โ†’ brandPIM.xml - Seller users manage brands/categories/products they resell โ†’ sellerPIM.xml - Order management via UI (My Orders) + external REST Order API โ†’ orderAPI.xml, Smoke_Testng.xml

The app also covers Regions/Zones, Manage Channels (Levels & Tiers), Manage Team (Departments, Designations, Members), brand onboarding, price rules, and storefront ordering. Login is mobile-number + OTP (admin = mobile + password) โ€” typical Indian B2B SaaS.


3. Tech stack & why (from pom.xml โ€” know the versions)

Library Version Role
Java 8 (1.8 source/target) Language
Maven surefire 3.0.0-M5 Build + test execution; suite chosen via -Db2b.testng.xml=<suite>
Selenium WebDriver 4.0.0-alpha-5 Browser automation (early Selenium 4 alpha)
TestNG 7.0.0 Test runner โ€” suites, groups, parallelism, listeners
REST Assured 4.4.0 API testing (Order API)
ExtentReports 2.41.1 (com.relevantcodes) HTML reporting (legacy v2 API)
WebDriverManager 4.2.2 Declared but not used โ€” drivers are bundled per-OS instead
AssertJ 3.10.0 Primary assertions (SoftAssertions)
ngwebdriver 1.1.4 Angular-aware synchronization (waitForAngularRequestsToFinish)
Gson 2.8.4 JSON test-data parsing

Notably absent: no Log4j/SLF4J (logging is System.out.println), no Apache POI (test data is JSON, not Excel), no Allure.

Why ngwebdriver? โ€” "The app is Angular, so the DOM updates asynchronously after XHR calls settle. Plain Selenium waits don't know about Angular's digest cycle. NgWebDriver.waitForAngularRequestsToFinish() waits for Angular to be stable before acting, which killed a whole class of timing flakiness."


4. Architecture / design patterns

src/test/java/com/avysh/qa/module/...        โ† TEST classes (TestNG @Test)
        โ”‚ calls
        โ–ผ
src/main/java/com/avysh/qa/helper/...         โ† HELPER / FACADE layer
        โ”‚ orchestrates business flows          (e.g. LoginHelper.loginToApplication())
        โ–ผ
src/main/java/com/avysh/qa/pages/...          โ† PAGE OBJECTS (44 classes)
        โ”‚ @FindBy + PageFactory.initElements    each extends CommonUtils
        โ–ผ
src/main/java/com/avysh/qa/util/CommonUtils   โ† BASE: click/sendKeys wrappers, waits,
                                                  Angular sync, alert handling, JS executor

Three-layer separation (the headline pattern): test โ†’ helper โ†’ page โ†’ CommonUtils. Tests talk to helpers (business flows), not directly to page objects, so a test reads like "login, add a product, verify it" rather than locator soup.

  • Page Object Model + PageFactory โ€” 44 page classes, each extends CommonUtils and calls PageFactory.initElements(driver, this) with @FindBy (mostly XPath/CSS) fields.
  • Helper/Facade layer โ€” 24 helper classes chain page-object steps into reusable business flows (LoginHelper, OrdersAPIHelper, StartUpHelper).
  • Data-driven via JSON (not DataProvider) โ€” ReadTestData (Gson) reads JSON from src/main/resources/testdata/<module>/*.json. readJsonElementInOrder returns an ordered LinkedHashMap for UI tests; readJsonElementForAPI returns a JsonObject for API tests. Config comes from config.properties.
  • Listeners โ€” ExtentReporterNG implements IReporter (reporting) and Retry implements IAnnotationTransformer (auto-attaches a 1-retry RetryAnalyzer to every test without annotating each one), both wired in the suite XMLs.
  • API layer โ€” apis/OrdersAPI wraps REST Assured RequestSpecification/Response; OrdersAPIHelper builds payloads (string-templating {orderId}/{status} into JSON) and delegates. Tests assert via response.jsonPath() + AssertJ.

5. Key components

Component Responsibility
util/WebDriverUtils Driver factory (Chrome/Firefox/IE/Edge/Safari; normal vs headless), OS-aware driver path, property loading, waitForPageToCompleteState (document.readyState polling)
util/CommonUtils Base of all pages: click/sendKeys wrappers, explicit WebDriverWait helpers (visible/clickable/invisible), NgWebDriver Angular sync, alert handling (incl. Webix UI alerts), dynamic XPath/CSS generation, JS-executor click/scroll
util/ReadTestData JSON test-data reader (Gson)
customException/CustomException + ExceptionFormatter Wraps exceptions, captures screenshots for Selenium exceptions, formats HTML traces (Script Issue vs Application Issue)
extentreport/ExtentReporterNG Generates timestamped AutomationResult<epoch>.html
retry/Retry + RetryAnalyzer Retries each failed test once (retryLimit = 1)
apis/OrdersAPI + helper/OrdersAPIHelper REST Assured Order API layer

6. Test suites & coverage

All suites share name="Avysh B2B Product Test_Suite", parallel="classes", Chrome, and the two listeners.

Suite Threads Group Coverage
brandPIM.xml 1 Smoke Brand-side PIM: add own/variant product, favorite/unfavorite, hide/unhide, categories, price rules (UI)
sellerPIM.xml 1 Smoke Seller-side equivalents: add own/variant product, seller brand, categories, favorite/unfavorite, hide/unhide (UI)
orderAPI.xml 2 Order-APIs OrdersAPITest โ€” pure REST Assured Order API (caveat: all @Tests currently commented out)
integration_testng.xml 4 Smoke OnBoardingBrandTest โ€” admin invites/onboards a brand, assigns a product, verifies cross-login
Smoke_Testng.xml 4 Smoke Default suite (used by runner.bat): order-status CRUD + place/accept/fulfill/reject orders via storefront + My Orders

UI vs API split: ~26 UI test classes vs 1 API class; ~27 active @Test methods, ~25 commented out. Be honest that a chunk is disabled.


7. Reporting, logging, config

  • Reporting: custom ExtentReports v2 (timestamped HTML in test-output/) + standard TestNG output (emailable-report.html, index.html). Categories set from TestNG groups.
  • Logging: no framework โ€” System.out.println + printStackTrace() (a known gap).
  • Config/credentials: src/main/resources/properties/config.properties holds URLs, mobile numbers, OTP/password, admin login, apiKey, and mode (normal/headless), passed via TestNG @Parameters (runParallel, enviroment [sic], browser, hubURL). Credentials committed in plaintext โ€” a known gap.
  • Screenshots on failure: in CustomException, only for org.openqa.selenium exception types, copied via commons-io FileUtils.

8. Interview Q&A

Q1. Describe your framework's architecture.

Three layers on top of a utilities base. Test classes call helper classes; helpers orchestrate page objects into business flows; page objects hold locators (@FindBy + PageFactory) and extend a CommonUtils base that wraps clicks, waits, Angular sync, and alerts. So a test reads as business steps, locators live in one place, and reusable flows live in helpers. Data is JSON-driven via Gson; reporting and retries are TestNG listeners.

Q2. What's the Page Object Model and why use it?

POM wraps each page's elements and actions in a class. Benefits: locators are centralized (a UI change updates one class, not every test), tests become readable business steps, and page logic is reusable. I use PageFactory's @FindBy to declare elements and initElements to lazy-initialize them.

Q3. Why a helper layer on top of page objects โ€” isn't POM enough?

POM gives you page-level actions, but a real test flow spans multiple pages โ€” login, navigate, fill a multi-step form, verify. Putting that orchestration in helper/facade classes keeps tests declarative and lets multiple tests reuse the same flow (e.g., LoginHelper.loginToApplication()). It's a facade over the page objects.

Q4. How is your framework data-driven?

Via JSON files under testdata/<module>/, read with Gson in ReadTestData. For UI tests I return an ordered LinkedHashMap so field order is preserved; for API tests I return a JsonObject. Config (URLs, credentials, mode) comes from config.properties. Honest note: I used JSON rather than TestNG @DataProvider + Excel/POI here โ€” I'd reach for DataProvider when I need TestNG to generate one test instance per data row with per-row reporting.

Q5. The app is Angular โ€” how do you handle synchronization?

Plain Selenium waits don't understand Angular's async digest cycle, so elements look present before data binds. I use ngwebdriver's waitForAngularRequestsToFinish() before and after actions to wait for Angular to be stable, plus explicit WebDriverWait with ExpectedConditions for visibility/clickability, and a document.readyState poll for full page loads. That combination removed most timing flakiness.

Q6. Explicit vs implicit vs fluent waits โ€” which do you use and why?

I use explicit waits (WebDriverWait + ExpectedConditions) because they wait for a specific condition on a specific element and fail fast with a clear reason. Implicit waits apply globally and can mask issues and interact badly with explicit waits. Fluent wait is an explicit wait with custom polling/ignored exceptions for special cases. Honest note: the codebase still has some Thread.sleep hard waits I'd replace with explicit waits.

Q7. How do you handle test retries and flaky tests?

A RetryAnalyzer implements IRetryAnalyzer retries a failed test once, and Retry implements IAnnotationTransformer auto-attaches it to every test at runtime, so I don't annotate each test manually. Retries are a safety net, not a fix โ€” I still investigate root causes (sync, locators) rather than masking real failures.

Q8. Explain your REST Assured API tests.

OrdersAPI wraps REST Assured โ€” given().header(...).body(...).request(Method.POST, path) โ€” and OrdersAPIHelper builds the JSON payloads by templating values like {orderId} and {status}. Tests extract values with response.jsonPath().getString(...) and assert with AssertJ soft assertions, including negative cases โ€” 403s, INSUFFICIENT_API_PARAMETERS, ORDER_NOT_FOUND, already-accepted/rejected. Honest note: those API tests are currently commented out in the suite; the coverage exists but is disabled.

Q9. Why AssertJ SoftAssertions instead of TestNG asserts?

A hard assert stops at the first failure, so you only see one broken field per run. SoftAssertions collect all failures and report them together at assertAll(), with .describedAs(...) messages โ€” so when verifying a product with 10 fields, I see every mismatch in one run instead of fixing-and-rerunning ten times. Much faster feedback for data-heavy validations.

Q10. How do you manage WebDriver instances and parallelism?

WebDriverUtils is the driver factory and holds both a plain WebDriver and a ThreadLocal<RemoteWebDriver>; getDriver() returns the thread-local if set. Suites run parallel="classes" with thread-counts 1โ€“4. Honest caveat: the true thread-local/Grid path isn't fully exercised โ€” each test class news up its own driver in normal mode, so parallelism is effectively per-class instances. For real parallel-at-scale I'd centralize a proper ThreadLocal driver pool and wire up the Grid/hubURL path that's declared but incomplete.

Q11. How does reporting and failure diagnosis work?

Custom ExtentReporterNG (an IReporter) generates timestamped HTML with TestNG groups as categories, alongside TestNG's default reports. On failure, my CustomException layer captures a screenshot (for Selenium exceptions) and formats an HTML trace that distinguishes a "Script Issue" from an "Application Issue" โ€” so a reviewer immediately knows whether the test or the app broke.

Q12. How do you pass environment/browser config?

Through TestNG @Parameters in the suite XML (browser, enviroment, runParallel, hubURL) plus config.properties for URLs/credentials/mode. So I can run the same suite against a different browser or environment by changing the XML/properties, no code change.

Q13. How would you integrate this into CI/CD?

runner.bat already does mvn clean compile && mvn test -Db2b.testng.xml=Smoke_Testng.xml, so it's a Jenkins/GitHub Actions job away: checkout โ†’ mvn test with the suite parameter โ†’ publish the TestNG/Extent HTML report and archive screenshots. I'd parameterize the suite and browser as build parameters and run headless on the agent.

Q14. What are the weaknesses of this framework and how would you improve it?

Honestly several: no shared BaseTest so @BeforeClass/@AfterClass setup is duplicated across classes; no logging framework (it uses System.out.println โ€” I'd add Log4j2/SLF4J); plaintext credentials in config.properties (move to env/secret store); WebDriverManager is declared but unused (bundled binaries instead); the Grid/parallel-remote path is incomplete; Selenium 4.0.0-alpha is a pre-release I'd bump to stable; an enviroment typo across suites; and a large fraction of tests are commented out. I'd frame these as a prioritized refactor backlog โ€” BaseTest + logging + secrets first.

Q15. How do you decide what to automate (smoke vs regression)?

Smoke = the critical happy paths that must work on every build (login, place an order, add a product) โ€” fast, run on every commit. Regression = broad coverage including edge/negative cases, run nightly or pre-release. My suites reflect this โ€” a tight Smoke_Testng.xml plus role-specific PIM regression suites.


9. STAR story (memorize)

Situation: The Avysh B2B platform โ€” multi-tenant, Angular front end, with brand/seller/order flows โ€” needed reliable UI and API regression coverage. Task: Build a maintainable Selenium + TestNG framework that wasn't flaky on an async Angular app and covered both UI and the order APIs. Action: I built a three-layer POM (test โ†’ helper โ†’ page โ†’ CommonUtils), added Angular-aware synchronization via ngwebdriver, made it JSON-data-driven, added a REST Assured layer for the order API with negative cases, an auto-retry listener, and a custom ExtentReports + screenshot-on-failure exception layer that labels script vs application issues. Result: Tests read as business flows, locator changes are isolated to one class, Angular flakiness dropped sharply, soft assertions surface all field mismatches per run, and failures come with a screenshot and a clear "script vs app" label for fast triage.


10. Honest caveats (be ready โ€” interviewers will dig here)

  • No BaseTest โ†’ duplicated @BeforeClass/@AfterClass setup in every test class.
  • No logging framework โ†’ System.out.println / printStackTrace.
  • Plaintext credentials committed in config.properties.
  • WebDriverManager declared but unused (bundled per-OS driver binaries instead).
  • Grid/parallel-remote path incomplete โ€” ThreadLocal<RemoteWebDriver>/hubURL declared but not fully wired.
  • Selenium 4.0.0-alpha-5 โ€” a pre-release; bump to a stable 4.x.
  • enviroment typo across most suite XMLs (one suite spells it correctly).
  • ~25 tests commented out (incl. all of OrdersAPITest) โ€” coverage exists but is disabled.

Pro tip: lead with the strengths (three-layer POM, Angular sync, soft assertions, custom reporting), then volunteer 2โ€“3 of these as "known tech-debt I'd refactor next." Owning the weaknesses reads as senior; pretending they don't exist reads as junior.