GUI tests
Table of contents
- Introduction to Selenium
- Where the tests live
- The driver helpers
- Running interface tests
- Local environment
- Docker environment (Selenium Grid)
- Vagrant environment
- Selenium IDE
- Summary
Introduction to Selenium
Selenium is a suite of web browser automation tools. It provides an easy-to-use interface for
driving browsers such as Chrome and Firefox, which is what the e2e level of the
testing pyramid uses to exercise the real interface.
VERY IMPORTANT!
The application must be running before you start any Selenium test. These tests drive a live browser against a live server; nothing is stubbed.
E2E tests run against the seeded development database, not the test database that the other levels use. They are written to be read-only for that reason: the development database is shared and is not reset between runs.
Where the tests live
One file per feature, at:
app/features/<feature>/tests/test_selenium.py
It is a file, not a directory. Features that ship one today are auth, dataset, explore,
featuremodel, profile, public, team and zenodo.
Each file declares the level once, at module scope:
import pytest
from tests.selenium_support import close_driver, get_host_for_selenium_testing, initialize_driver
pytestmark = pytest.mark.e2e
That pytestmark = pytest.mark.e2e is what keeps browser tests out of a default rosemary test
run and what makes --e2e able to select them.
The driver helpers
The imports come from tests/selenium_support.py, which since splent_framework 1.7.1 is a thin
wrapper over the framework’s own helpers. The framework drives the grid natively: when
SELENIUM_GRID_URL is set, initialize_driver attaches to that hub through webdriver.Remote, so
the browser runs in the selenium-chrome or selenium-firefox container; without it, a local
browser is launched through webdriver_manager. get_host_for_selenium_testing honours
SELENIUM_TARGET_URL, which matters because the URL is resolved by the browser, and inside a
grid node localhost is the node itself.
What the wrapper adds on top:
if os.getenv("WORKING_DIR", "") == "/workspace/":
os.environ.setdefault("SELENIUM_GRID_URL", "http://selenium_hub_container:4444")
os.environ.setdefault("SELENIUM_TARGET_URL", "http://nginx_web_server_container")
so the grid and the target default to this stack’s container names under Docker, plus a pinned 1920x1080 window. Browser defaults differ (chrome nodes open at about 945px, firefox at about 1280px), and below the responsive breakpoint the sidebar collapses off-canvas, so an unpinned viewport makes the same test pass on one browser and fail on the other.
Outside Docker neither variable is defaulted, so the framework launches a local browser against
http://localhost:5000 and the identical test file works in both environments.
Running interface tests
There are two ways in. They select the same tests, but they do not default to the same browser.
Through the normal test runner, selecting the e2e level:
rosemary test auth --e2e
Or through the dedicated command, which also lets you pick the browser:
rosemary selenium auth
Without a feature name, rosemary selenium collects every test_selenium.py it can find under
app/features/ and runs them all:
rosemary selenium
rosemary selenium defaults to firefox. Override it with --driver:
rosemary selenium auth --driver chrome
The flag accepts only firefox and chrome, and it is exported as SELENIUM_BROWSER, which is
what initialize_driver reads.
rosemary test --e2e has no such flag and never sets SELENIUM_BROWSER. The wrapper in
tests/selenium_support.py delegates browser selection to the framework, and the fallback lives in
splent_framework.selenium.common._resolve_browser:
name = (browser or os.getenv("SELENIUM_BROWSER") or DEFAULT_BROWSER).lower()
with DEFAULT_BROWSER = "chrome". So the two entry points differ: rosemary selenium gives you
firefox, rosemary test --e2e gives you chrome. Export SELENIUM_BROWSER=firefox yourself if you
want firefox from rosemary test.
Under the hood rosemary selenium runs pytest with the marker and the collected file paths:
pytest -v -m e2e /workspace/app/features/auth/tests/test_selenium.py
The paths carry the $WORKING_DIR prefix inside a container; outside Docker they start at
app/features/.
If you name a feature that has no test_selenium.py, the command tells you the exact path it
looked for and stops.
Local environment
Outside Docker (WORKING_DIR unset), Selenium launches a browser on your own desktop, and the
tests target http://localhost:5000.
No WebDriver to install
You do not install GeckoDriver or ChromeDriver by hand. The framework’s local mode resolves the driver binary through
webdriver_manager, which downloads a build matching your browser on first use and caches it for later runs.
The only thing that has to be present is the browser itself, Firefox or Chrome/Chromium, installed through whatever channel your platform uses; on Ubuntu, for example:
sudo apt install firefox
Then run:
rosemary selenium auth --driver firefox
A real browser window opens on your desktop and executes the test.
Docker environment (Selenium Grid)
Inside Docker (WORKING_DIR=/workspace/), Rosemary connects to the Selenium Grid defined in
docker/docker-compose.dev.yml. Three services make it up:
selenium-hub— the grid hub, containerselenium_hub_container, port 4444selenium-chrome— a Chrome node, containerselenium_chrome_containerselenium-firefox— a Firefox node, containerselenium_firefox_container
Launch the grid:
docker compose -f docker/docker-compose.dev.yml up -d selenium-hub selenium-chrome selenium-firefox
The web service already declares selenium-hub as a dependency, so bringing the whole
development stack up starts the hub for you as well.
Check that the grid is ready:
curl http://localhost:4444/status | jq .
Look for "ready": true in the response:
{
"value": {
"message": "Selenium Grid ready.",
"ready": true,
"nodes": [ ... ]
}
}
That is an excerpt. The full body also lists every registered node with its slots and stereotypes, so expect a much larger object.
Then run the tests from inside web_app_container:
rosemary selenium auth --driver chrome
The browser runs inside the Chrome or Firefox container and drives the app through nginx.
Viewing the browser in Docker (VNC)
VNC (Virtual Network Computing) is a remote-desktop protocol that lets you see and control a graphical session running on another machine or container over the network.
In our setup, each Selenium browser node runs its own virtual display inside Docker and exposes it over VNC, so you can watch the test in real time even though the browser window is not on your host desktop.
Connect via VNC
You can connect to the running browsers with any VNC viewer. Each node exposes its own port:
| Browser | VNC URL | Default password |
|---|---|---|
| Chrome | vnc://localhost:5900 |
none (VNC_NO_PASSWORD=1) |
| Firefox | vnc://localhost:5901 |
none |
Those ports and the passwordless setting come from docker/docker-compose.dev.yml and
.env.selenium.
Examples
macOS
- Open Finder then Go then Connect to Server.
- Enter the address
vnc://localhost:5900(orvnc://localhost:5901for Firefox). - Click Connect and you will see the browser window executing the test inside the container.
Linux
sudo apt install remmina
remmina
This opens the Remmina Remote Desktop Client. In the connection window:
- Click + to create a new connection.
- Set Protocol to
VNC - Virtual Network Computing. - Enter the server address:
localhost:5900for Chromelocalhost:5901for Firefox
- Leave the password field empty, since
VNC_NO_PASSWORD=1. - Click Connect.
You will then see a remote desktop window displaying the virtual browser inside the Docker container as Selenium runs the test.
Windows
- Download and install RealVNC Viewer.
- Open RealVNC Viewer and enter one of the following addresses:
localhost:5900for Chromelocalhost:5901for Firefox
- Click Connect.
- The remote desktop window opens, showing the live browser session running inside the Docker container as Selenium performs each step of the test.
Vagrant environment
Note on the Vagrant environment
rosemary seleniumis not yet available in Vagrant environments. WithWORKING_DIR=/vagrant/the command reports that Selenium tests cannot be run and exits. GUI testing is currently supported in local and Docker environments only.
Selenium IDE
Selenium IDE is a browser extension for Chrome and Firefox that lets you record, edit and debug web application tests without writing code. It is a quick way to draft an interface test that you then clean up by hand.
Installation
- Chrome: install the extension from the Chrome Web Store.
- Firefox: install the extension from Firefox Add-ons.
Once installed, the Selenium IDE icon appears in your browser toolbar.
Recording a test
- Open Selenium IDE from the toolbar.
- Create a new project and set the base URL:
http://localhost:5000when running locallyhttp://nginx_web_server_containerwhen running inside Docker
- Start recording your interactions with the application.
- Stop the recording when you are done.
- Save the test case.
Turning a recording into a test
Export the recording to Python pytest format, then move the code into the feature’s e2e file:
app/features/<feature>/tests/test_selenium.py
Adapt the generated code so it uses the project’s own helpers and carries the marker. The exported
skeleton uses setup_method/teardown_method; the tests in this repo build and close the driver
inside each test instead:
import pytest
from selenium.webdriver.common.by import By
from tests.selenium_support import close_driver, get_host_for_selenium_testing, initialize_driver
pytestmark = pytest.mark.e2e
def test_something():
driver = initialize_driver()
try:
driver.get(f"{get_host_for_selenium_testing()}/login")
driver.find_element(By.NAME, "email").send_keys("user1@example.com")
# ...
finally:
close_driver(driver)
Then run it the normal way:
rosemary test <feature> --e2e
Do not use
--noconftestOlder instructions ran exported recordings with
pytest --noconftest app/modules/auth/tests/test_selenium_ide/test_signup.py. That path no longer exists, and--noconftestnow breaks the run: the rootconftest.pyis what setsSPLENT_APPand provides the shared fixtures. Userosemary test <feature> --e2eorrosemary selenium <feature>.
Summary
| Environment | How to run | Browser | Notes |
|---|---|---|---|
| Local | rosemary selenium auth --driver firefox |
Chrome or Firefox on the host | Opens a real browser window, targets http://localhost:5000 |
| Docker (Grid) | rosemary selenium auth --driver chrome |
Chrome or Firefox in containers | Runs on the grid, targets the nginx container |
| Either | rosemary test auth --e2e |
Chrome, unless you export SELENIUM_BROWSER yourself |
The same tests, selected by marker |
| VNC view | vnc://localhost:5900 or vnc://localhost:5901 |
Remote viewer | Watch a run live |
| Selenium IDE | Export to Python, adapt, save as test_selenium.py |
Chrome or Firefox | Record and edit visually |