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 CommonUtilsand callsPageFactory.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 fromsrc/main/resources/testdata/<module>/*.json.readJsonElementInOrderreturns an orderedLinkedHashMapfor UI tests;readJsonElementForAPIreturns aJsonObjectfor API tests. Config comes fromconfig.properties. - Listeners โ
ExtentReporterNG implements IReporter(reporting) andRetry implements IAnnotationTransformer(auto-attaches a 1-retryRetryAnalyzerto every test without annotating each one), both wired in the suite XMLs. - API layer โ
apis/OrdersAPIwraps REST AssuredRequestSpecification/Response;OrdersAPIHelperbuilds payloads (string-templating{orderId}/{status}into JSON) and delegates. Tests assert viaresponse.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.propertiesholds URLs, mobile numbers, OTP/password, admin login,apiKey, andmode(normal/headless), passed via TestNG@Parameters(runParallel,enviroment[sic],browser,hubURL). Credentials committed in plaintext โ a known gap. - Screenshots on failure: in
CustomException, only fororg.openqa.seleniumexception types, copied via commons-ioFileUtils.
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 aCommonUtilsbase 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
@FindByto declare elements andinitElementsto 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 inReadTestData. For UI tests I return an orderedLinkedHashMapso field order is preserved; for API tests I return aJsonObject. Config (URLs, credentials, mode) comes fromconfig.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'swaitForAngularRequestsToFinish()before and after actions to wait for Angular to be stable, plus explicitWebDriverWaitwithExpectedConditionsfor visibility/clickability, and adocument.readyStatepoll 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 someThread.sleephard waits I'd replace with explicit waits.
Q7. How do you handle test retries and flaky tests?
A
RetryAnalyzer implements IRetryAnalyzerretries a failed test once, andRetry implements IAnnotationTransformerauto-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.
OrdersAPIwraps REST Assured โgiven().header(...).body(...).request(Method.POST, path)โ andOrdersAPIHelperbuilds the JSON payloads by templating values like{orderId}and{status}. Tests extract values withresponse.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?
WebDriverUtilsis the driver factory and holds both a plainWebDriverand aThreadLocal<RemoteWebDriver>;getDriver()returns the thread-local if set. Suites runparallel="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/hubURLpath that's declared but incomplete.
Q11. How does reporting and failure diagnosis work?
Custom
ExtentReporterNG(anIReporter) generates timestamped HTML with TestNG groups as categories, alongside TestNG's default reports. On failure, myCustomExceptionlayer 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
@Parametersin the suite XML (browser,enviroment,runParallel,hubURL) plusconfig.propertiesfor 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.batalready doesmvn clean compile && mvn test -Db2b.testng.xml=Smoke_Testng.xml, so it's a Jenkins/GitHub Actions job away: checkout โmvn testwith 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
BaseTestso@BeforeClass/@AfterClasssetup is duplicated across classes; no logging framework (it usesSystem.out.printlnโ I'd add Log4j2/SLF4J); plaintext credentials inconfig.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; anenviromenttypo 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.xmlplus 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/@AfterClasssetup 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>/hubURLdeclared but not fully wired. - Selenium 4.0.0-alpha-5 โ a pre-release; bump to a stable 4.x.
enviromenttypo 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.