This episode dissects Selenium's main components: WebDriver, browser driver, and Selenium Grid, how Selenium controls the browser through the W3C protocol, the setup-exercise-assert-teardown test lifecycle, and a clean automated test project structure.

After understanding why Selenium exists, episode 2 brings you inside its engine: core concepts and Selenium architecture. This is the most important episode to understand before writing lots of code, because almost every test script in this series is built on understanding how Selenium's components connect to each other.
We'll cover the main components (WebDriver, browser driver, Selenium Grid), how Selenium controls the browser through the W3C protocol, the test lifecycle that frames every test, and a healthy automated test project structure. If you understand this episode well, episodes 3 to 20 will feel like variations on one big theme.
The Selenium ecosystem stands on three major components:
find_element, click, and send_keys.In addition, there's Selenium IDE — a browser extension for quick record and playback — which we'll discuss in episode 21.
When you run driver.find_element(...), what happens behind the scenes?
test code -> WebDriver client -> HTTP/JSON (W3C) -> browser driver -> browserEvery command is sent from the WebDriver client to the browser driver as an HTTP request, then the driver translates it into a native action in the browser. The result returns through the same path. Understanding this path matters: every hop adds latency, and this is the root of many timing problems we'll discuss in episode 5.
Since Selenium 3 and 4, communication follows the W3C WebDriver standard — an official specification approved by the World Wide Web Consortium. Modern browsers (Chrome, Firefox, Edge, Safari) implement this protocol natively, so no intermediary server is needed like in the Selenium RC era.
The W3C protocol defines standard HTTP endpoints. Example commands sent to the browser driver:
POST /session -> create a new browser session
POST /session/:id/url -> navigate to a URL
POST /session/:id/element -> find an elementThrough POST /session a browser session is created, then that session is used for all subsequent commands. This session is what the driver object holds in your code.
The driver object represents a single browser session. All interactions — navigation, element lookup, JavaScript execution — go through this object. When you call driver.quit(), the session is deleted and the browser closes. Session leaks (not quitting) are a primary cause of browser processes piling up in CI — we'll see the solution in the test lifecycle section.
Every good E2E test follows four phases. This is the universal framework in all testing frameworks:
In pytest, this lifecycle is realized with fixtures:
import pytest
from selenium import webdriver
@pytest.fixture
def driver():
d = webdriver.Chrome()
yield d
d.quit()
def test_buka_halaman(driver):
driver.get("https://example.com")
assert "Example" in driver.titleIn the example above, the driver fixture runs the setup (opening Chrome), yield d hands the driver to the test, and d.quit() becomes the teardown that always runs. This driver fixture pattern will accompany us in almost every upcoming episode.
Info
Teardown is not optional. Even if a test fails midway, the browser must still be closed — otherwise zombie processes pile up and CI runs out of resources. The pytest fixture guarantees teardown runs.
A healthy test project has clear separation. The structure we use throughout the series:
belajar-selenium/
├── conftest.py -> shared fixtures
├── pages/ -> Page Objects (episode 6)
├── tests/ -> pytest test files
├── utils/ -> helpers and wrappers (episode 18)
├── data/ -> test data (episode 9)
└── requirements.txt -> dependenciesEach folder has a responsibility: pages holds page representations, tests holds test cases, utils holds reusable code, and data holds test inputs. Separating folders from the start is far cheaper than restructuring a large project later.
Episode 2 gave you a map of Selenium's architecture: the three main components (WebDriver, browser driver, Grid), the HTTP/JSON communication flow based on the W3C standard, the setup-exercise-assert-teardown test lifecycle realized as a pytest fixture, and a clean test project structure.
Key takeaways:
driver object; always close it via teardown.In episode 3 next, we'll start writing real code: WebDriver installation and setup — adding the Selenium dependency, understanding Selenium Manager and browser drivers, launching the first automated browser, and matching driver versions with browser versions. Prepare your environment from episode 0.