Episode ini membahas pembuatan test utilities dan wrapper yang bisa dipakai ulang, custom logs, screenshot, dan reporting utilities, integrasi dengan framework test seperti pytest, serta berbagi utilitas antar test suite agar project test tetap ringkas.

Semakin besar suite, semakin sering kalian menemukan pola yang berulang: membuat driver, menunggu elemen, mengambil screenshot, menulis log. Episode 18 membahas cara merapikan pola itu menjadi custom utilities dan tooling — kode yang ditulis sekali dan dipakai di seluruh suite.
Tujuan utama episode ini bukan sekadar mengurangi pengetikan, tapi membuat suite lebih mudah dipelihara dan lebih informatif. Dengan wrapper yang konsisten, kebijakan berubah di satu tempat; dengan logging dan reporting yang terpusat, setiap kegagalan membawa bukti yang lengkap.
Fokuskan pembuatan driver di satu wrapper yang menangani opsi, headless, dan logging sesi:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def buat_chrome(headless=False, ukuran=None):
opsi = Options()
if headless:
opsi.add_argument("--headless")
if ukuran:
opsi.add_argument(f"--window-size={ukuran[0]},{ukuran[1]}")
return webdriver.Chrome(options=opsi)buat_chrome(headless=False, ukuran=None) menyeragamkan cara seluruh suite membuat Chrome. Perubahan opsi — misalnya menambah argumen anti-crash — cukup dilakukan sekali.
Metode yang dipakai semua halaman bisa ditarik ke class induk:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class BasePage:
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 10)
def klik_saat_klikable(self, locator):
self.wait.until(EC.element_to_be_clickable(locator)).click()
def baca_teks(self, locator):
return self.driver.find_element(*locator).textklik_saat_klikable(locator) dan baca_teks(locator) menjadi method yang diwarisi semua page object dari episode 6. Konsistensi ini menjamin setiap halaman memakai kebijakan wait yang sama.
Log yang tersebar di banyak file sulit dilacak. Terpusatkan lewat module logging:
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)
log = logging.getLogger("selenium-tests")
def cek_halaman(driver, url):
log.info("Membuka %s", url)
driver.get(url)
log.info("Judul: %s", driver.title)logging.getLogger("selenium-tests") memberi satu logger yang dipakai seluruh suite. Dengan log.info(...) di titik-titik penting, urutan langkah test bisa direkonstruksi dari log saat kegagalan terjadi.
Screenshot dari episode 7 bisa dibungkus menjadi utilitas:
from pathlib import Path
def simpan_bukti(driver, nama, folder="artifacts"):
Path(folder).mkdir(exist_ok=True)
path_png = Path(folder) / f"{nama}.png"
driver.save_screenshot(str(path_png))
return path_pngsimpan_bukti(driver, nama) menyeragamkan lokasi dan penamaan bukti. Dipakai bersama hook kegagalan pytest, ini memastikan setiap run menghasilkan artifacts yang konsisten.
pytest mengintegrasikan utilitas lewat fixture di conftest.py — di sini wrapper driver dan logger disatukan:
import pytest
import logging
from utils.driver_factory import buat_chrome
@pytest.fixture
def driver():
log = logging.getLogger("selenium-tests")
log.info("Membuat sesi Chrome")
d = buat_chrome(headless=True)
yield d
d.quit()
log.info("Sesi ditutup")Fixture driver ini menyediakan sesi bersih ke setiap test, lengkap dengan catatan log pembuatan dan penutupan. Seluruh suite memakai fixture yang sama — kualitas setup dan teardown terjamin di satu tempat.
Tambahkan hook untuk melengkapi laporan dengan bukti otomatis:
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
if report.when == "call" and report.failed:
log = logging.getLogger("selenium-tests")
log.error("Test gagal: %s", item.name)
log.error("Detail: %s", report.longrepr)Hook ini menulis alasan kegagalan ke log dengan level error. Kombinasi fixture driver, logger, dan hook ini menghasilkan suite yang setiap kegagalannya disertai konteks.
Utilitas yang baik adalah yang bisa dipakai di project lain. Satu-satunya cara mencapai itu adalah menulisnya tanpa ketergantungan pada halaman atau test tertentu:
driver_factory.py — hanya tentang membuat driver.waits.py — hanya tentang menunggu kondisi.reporting.py — hanya tentang menyimpan bukti.utils/
├── driver_factory.py -> pembuatan driver
├── waits.py -> kondisi tunggu
├── reporting.py -> screenshot dan log
└── __init__.pyFolder utils di atas tidak menyentuh logika bisnis halaman mana pun. Package seperti ini bisa di-publish atau di-copy ke project lain tanpa perubahan besar.
Tip
Saat membuat utilitas, tulis dulu dokumentasi singkat di docstring dan beri nama yang jelas. Utilitas tanpa dokumentasi akan dengan cepat berubah menjadi "kode misterius" yang tidak berani diubah siapa pun.
Episode 18 menutup kebutuhan tooling dasar suite Selenium: wrapper driver dan BasePage yang konsisten, logging dan screenshot terpusat, fixture dan hook pytest yang menyatukan semuanya, serta struktur utils yang portabel antar project.
Inti yang harus dibawa pulang:
Di episode 19 selanjutnya kita akan membahas operational readiness dan runbooks — runbook untuk broken tests, maintenance window, dan environment drift, mengelola test suite dan men-triage kegagalan, langkah recovery untuk masalah kompatibilitas browser, serta kepemilikan dan pemeliharaan test oleh tim.