🏗️ Framework Architecture (SOLID + POM)

Framework Architecture (SOLID + POM): Every piece you have written up to this tab (findElement calls, WebDriverWait blocks, @Test methods) works on its own but is LOOSELY connect

Every piece you have written up to this tab (findElement calls, WebDriverWait blocks, @Test methods) works on its own but is LOOSELY connected — like an industrial park that grew without a zoning plan: every workshop installs its own generator, runs its own water line, nobody follows a shared standard. The first 10 tests cause no trouble; by test 200, the answer to "how many seconds is this wait?" is hidden in 200 separate places. Framework architecture is exactly what fixes this: ONE DriverManager owns the driver lifecycle (the main power grid), ONE BasePage holds all wait/click logic (the shared building code), and each PageObject knows ONLY its own elements (a neighborhood boundary). But if every test already uses WebDriverWait, why open a separate architecture tab — don't the pieces already exist? Because EXISTING and being CORRECTLY RELATED are not the same thing: if every @Test copies its own `new WebDriverWait(driver, Duration.ofSeconds(10))` line, the decision to "bump our wait to 15 seconds" means editing 200 files by hand. Java comparison: in a poorly designed project, the difference between every class creating its own `SimpleDateFormat` and one central utility class managing it is exactly this — the SOLID principles discipline that difference. QA context: the REAL cause of a flaky suite is often not a wrong locator but the absence of architecture; inconsistent wait durations, copy-pasted driver setup, and scattered locators together produce the "passes on my machine, explodes in CI" nightmare.

Build Your Selenium Framework Step by Step

The 4 pieces below are the BIG PICTURE of the architecture you are about to build piece by piece in this tab. They all start locked — the first time you correctly finish that step's "Try It Yourself" practice, that piece flips from locked to BUILT. As you scroll down, you will complete the puzzle piece by piece.

🧭 Step 1 — The Big Picture: Framework Mindmap

The same architecture is shown here from five angles: first the main flow (who calls whom while a test runs), then the setup flow (how config reaches the driver), then parallel execution (why ThreadLocal exists), then the data-sharing scope (@DataProvider / ITestContext / config), and finally a "does / does not" list for every class. Press ▶ Animate on the first two boxes to watch the flow advance step by step.

3️⃣ Parallel Execution — Why ThreadLocal?

When you run tests concurrently with TestNG `parallel="methods"`, a single static WebDriver field WOULD let three threads write to the same browser and tests would corrupt each other's page. Thanks to ThreadLocal, the same DriverManager class serves every thread, but each thread holds its own WebDriver reference — when one thread finishes, the others' sessions are NOT affected.

4️⃣ Data-Sharing Scope — Where Does Test Data Come From?

5️⃣ Who Does What? — Class Responsibilities

🎬 The Journey of a @Test Call (and the Thread-2 Contrast)

Thread-2 (parallel test)

The `loginTest` method starts running. This method ONLY narrates the scenario — it contains no locators or wait code, it hands the work straight to LoginPage.

Step 1 — LoginPage (POM) takes over: it knows its own `@FindBy` locators but NEVER touches click/wait logic, leaving that to the BasePage it extends.

Step 2 — Before touching the element, BasePage asks WaitFactory for the shared wait rule. This is the SRP boundary: BasePage does not know HOW to wait, only WHEN it must wait.