Skip to content

Commit b1c0813

Browse files
committed
test(frontend): add basic Selenium testing
So far, this just checks that the main pages (as listed in the navigation bar) do not 404, have a Django ProgrammingError page displayed, etc. The test uses the Chromium webdriver because it is more complex to set up one test to run with two different webdrivers in sequence. It also opts for emulating the common _desktop_ resolution of 1080p (future tests could check that the navbar expander, etc., work properly, but this is out of scope for test #1).
1 parent 6d0d8fd commit b1c0813

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

Dockerfile-dev

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ RUN <<EOF
1818
set -exo pipefail
1919
apt-get update
2020
apt-get -y upgrade
21-
apt-get install -y --no-install-recommends libmagic1 gettext graphviz graphviz-dev
21+
apt-get install -y --no-install-recommends libmagic1 gettext graphviz graphviz-dev chromium
2222
pip install --upgrade pip
2323
pip install -r requirements-dev.txt
2424
EOF

app/general/tests/test_frontend.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
2+
from selenium.common import TimeoutException
3+
from selenium.webdriver.chrome.webdriver import WebDriver, Options
4+
from selenium.webdriver.common.by import By
5+
from selenium.webdriver.support.wait import WebDriverWait
6+
7+
8+
# Wait timeout in seconds
9+
WAIT_TIMEOUT = 5
10+
11+
12+
class TestFrontend(StaticLiveServerTestCase):
13+
@classmethod
14+
def setUpClass(cls):
15+
opts = Options()
16+
opts.add_argument("--headless")
17+
opts.add_argument("--no-sandbox")
18+
opts.add_argument("--disable-dev-shm-usage")
19+
opts.add_argument("--window-size=1920,1080")
20+
cls.driver = WebDriver(opts)
21+
cls.driver.implicitly_wait(WAIT_TIMEOUT)
22+
super().setUpClass()
23+
24+
@classmethod
25+
def tearDownClass(cls):
26+
cls.driver.quit()
27+
super().tearDownClass()
28+
29+
def test_no_404s(self):
30+
# Sanity check in case we ever change the 404 title
31+
self.driver.get(f"{self.live_server_url}/blabla404")
32+
print(self.driver.title)
33+
assert self.driver.title.startswith(
34+
"Error"
35+
), f"Actual title was {self.driver.title}. Page: {self.driver.page_source}"
36+
37+
# Check main page does not 404
38+
self.driver.get(self.live_server_url)
39+
self.assert_current_page_not_error()
40+
41+
# Check all nav items
42+
for item in ["Search", "Institutions", "Projects", "Documents", "Languages", "Subjects"]:
43+
self.check_nav_item(item)
44+
45+
def check_nav_item(self, link_text):
46+
self.driver.find_element(By.PARTIAL_LINK_TEXT, link_text).click()
47+
48+
# We use 'in' to do a more permissive match (for instance 'Search' is usually '<search query> - Search'
49+
try:
50+
wait = WebDriverWait(self.driver, timeout=WAIT_TIMEOUT)
51+
wait.until(lambda d: link_text in self.driver.title)
52+
except TimeoutException:
53+
assert link_text in self.driver.title, (
54+
f"Expected title for page {link_text} to have {link_text};"
55+
f" was {self.driver.title}"
56+
)
57+
self.assert_current_page_not_error()
58+
59+
def assert_current_page_not_error(self):
60+
assert not self.driver.title.startswith("Error"), f"Actual title was {self.driver.title}"
61+
assert not self.driver.title.startswith(
62+
"ProgrammingError"
63+
), f"Actual title was {self.driver.title}"
64+
assert not self.driver.find_element(By.ID, "error-block").is_displayed()

requirements-test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ django-debug-toolbar
33
django-extensions
44
faker
55
ruff
6+
selenium==4.25.0

0 commit comments

Comments
 (0)