Stop Using Raw WebDriver in Robot Framework

A lot of Robot Framework projects still look like plain Selenium scripts with .robot file extensions.

Someone imports webdriver, creates driver = webdriver.Chrome(), then calls find_element and send_keys in Python helpers. Robot Framework runs the suite, but readable keywords, shared libraries, and consistent waits never show up in the tests.

If you already use Robot Framework with SeleniumLibrary, you do not need the raw WebDriver API. SeleniumLibrary gives you high-level keywords. The Page Object Model gives you structure. Together they keep tests short and UI changes localized.

We published a small MIT template that shows the layout: rf-seleniumlibrary-pageobject-template. It targets Sauce Demo — clone it, run four tests, fork the folder structure.

What breaks when you mix in raw WebDriver

driver = webdriver.Chrome()
driver.find_element(By.ID, "user-name").send_keys("standard_user")
driver.find_element(By.ID, "password").send_keys("secret_sauce")
driver.find_element(By.ID, "login-button").click()

Fine for a script. Painful in a growing suite.

Locators spread across helpers and test files. Waits become time.sleep(2) in one place and missing in another. You end up maintaining SeleniumLibrary and a parallel WebDriver stack. CI fails on a Tuesday night and you are not sure which path opened the browser.

Before and after

Before After
driver.find_element(...).send_keys(...) Login With Valid Credentials ${VALID_USER} ${VALID_PASSWORD}
Locators in every file LoginLocators.USERNAME in one module
Ad-hoc sleeps wait_until_element_is_visible in BasePage.click()
Two browser stacks One SeleniumLibrary instance per suite

Four layers

Layer Job Example
Locators Selectors per screen login_locators.py
BasePage Shared waits and actions click(), enter_text()
Page library Screen keywords LoginPage.login()
Robot test Scenario only Inventory Should Be Visible

Folder layout in the repo:

resources/locators/   → selectors
pages/                → Python page libraries
tests/                → thin .robot files

Locators stay in one place

class LoginLocators:
    USERNAME = "id:user-name"
    PASSWORD = "id:password"
    SUBMIT = "id:login-button"

Prefer stable attributes like data-test when the app exposes them.

BasePage owns the waits

def click(self, locator):
    self.seleniumlib.wait_until_element_is_visible(locator)
    self.seleniumlib.click_element(locator)

@property
def seleniumlib(self):
    return BuiltIn().get_library_instance("SeleniumLibrary")

Import SeleniumLibrary once in common.resource. Page objects look up that same instance — no driver argument passed between keywords. If you create driver = webdriver.Chrome() outside SeleniumLibrary, your page keywords will not see that browser.

A thin test

*** Test Cases ***
Valid Login
    Login With Valid Credentials    ${VALID_USER}    ${VALID_PASSWORD}
    Inventory Should Be Visible

No locators. No driver setup. Browser open/close in Test Setup / Test Teardown.

Quick start

git clone https://github.com/gitoza-io/rf-seleniumlibrary-pageobject-template.git
cd rf-seleniumlibrary-pageobject-template
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
robot --pythonpath . --outputdir results tests/

Use --pythonpath . from the repo root so pages.* imports resolve. Four passing tests = layout is wired.

Migrating without a rewrite

  1. Move locators to resources/locators/
  2. Add BasePage with click / enter_text
  3. Wrap login as the first page library
  4. Import SeleniumLibrary once in common.resource
  5. Rewrite one .robot file, delete webdriver imports from its helpers

Repeat screen by screen. Leave the rest alone until you touch that feature.

Playwright and Cypress are valid for greenfield work. Plenty of teams still run RF and SeleniumLibrary in production — for them, dropping find_element for Page Objects is a low-risk upgrade that pays off on the next UI refactor.

Template repo: github.com/gitoza-io/rf-seleniumlibrary-pageobject-template

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post

How to stop Meta’s AI image generator from using your Instagram photos

Next Post

From Nano-Scale to Large-Scale: Optimizing Electronics Yield with 3D Optical Metrology

Related Posts