Skip to content

Commit 8862ba3

Browse files
committed
add e2e tests
1 parent 1771d46 commit 8862ba3

7 files changed

Lines changed: 676 additions & 1 deletion

File tree

.github/workflows/e2e-tests.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
name: E2E Tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
e2e:
11+
runs-on: ubuntu-latest
12+
timeout-minutes: 30
13+
14+
steps:
15+
- name: Checkout Janeway
16+
uses: actions/checkout@v4
17+
with:
18+
repository: BirkbeckCTP/janeway
19+
ref: master
20+
21+
- name: Checkout geometadata plugin
22+
uses: actions/checkout@v4
23+
with:
24+
path: src/plugins/geometadata/
25+
26+
- name: Set up Python 3.11
27+
uses: actions/setup-python@v5
28+
with:
29+
python-version: "3.11"
30+
cache: "pip"
31+
cache-dependency-path: |
32+
requirements.txt
33+
dev-requirements.txt
34+
src/plugins/geometadata/requirements.txt
35+
src/plugins/geometadata/requirements-e2e.txt
36+
37+
- name: Install dependencies
38+
run: |
39+
python -m pip install --upgrade pip
40+
pip install -r requirements.txt
41+
pip install -r dev-requirements.txt
42+
pip install -r src/plugins/geometadata/requirements.txt
43+
pip install -r src/plugins/geometadata/requirements-e2e.txt
44+
45+
- name: Cache Playwright browsers
46+
uses: actions/cache@v4
47+
id: playwright-cache
48+
with:
49+
path: ~/.cache/ms-playwright
50+
key: playwright-${{ runner.os }}-${{ hashFiles('src/plugins/geometadata/requirements-e2e.txt') }}
51+
52+
- name: Install Playwright browsers
53+
if: steps.playwright-cache.outputs.cache-hit != 'true'
54+
run: playwright install --with-deps chromium
55+
56+
- name: Install Playwright browser deps (if cached)
57+
if: steps.playwright-cache.outputs.cache-hit == 'true'
58+
run: playwright install-deps chromium
59+
60+
- name: Set environment variables
61+
run: |
62+
echo "DB_VENDOR=sqlite" >> "$GITHUB_ENV"
63+
echo "JANEWAY_SETTINGS_MODULE=core.janeway_global_settings" >> "$GITHUB_ENV"
64+
echo "DJANGO_ALLOW_ASYNC_UNSAFE=1" >> "$GITHUB_ENV"
65+
66+
- name: Run E2E tests
67+
working-directory: src
68+
run: pytest plugins/geometadata/tests/e2e/ -v
69+
70+
- name: Upload test artifacts
71+
uses: actions/upload-artifact@v4
72+
if: failure()
73+
with:
74+
name: playwright-traces
75+
path: src/plugins/geometadata/tests/e2e/test-results/
76+
retention-days: 7

.github/workflows/tests.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Tests
1+
name: Unit Tests
22

33
on:
44
push:
@@ -26,6 +26,11 @@ jobs:
2626
uses: actions/setup-python@v5
2727
with:
2828
python-version: "3.11"
29+
cache: "pip"
30+
cache-dependency-path: |
31+
requirements.txt
32+
dev-requirements.txt
33+
src/plugins/geometadata/requirements.txt
2934
3035
- name: Install dependencies
3136
run: |

requirements-e2e.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# E2E testing dependencies
2+
pytest>=8.0
3+
pytest-django>=4.5
4+
pytest-playwright>=0.5
5+
playwright>=1.40

tests/e2e/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""E2E tests for geometadata plugin using Playwright."""

tests/e2e/conftest.py

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
"""
2+
Pytest configuration for geometadata E2E tests.
3+
4+
Provides fixtures for Django live server and test data setup.
5+
Uses pytest-playwright for browser automation.
6+
"""
7+
8+
import os
9+
10+
import pytest
11+
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
12+
from playwright.sync_api import Page
13+
14+
from plugins.geometadata import plugin_settings
15+
from plugins.geometadata.models import ArticleGeometadata
16+
from utils.testing import helpers
17+
18+
19+
# Allow async unsafe operations for Django ORM in Playwright tests
20+
os.environ.setdefault("DJANGO_ALLOW_ASYNC_UNSAFE", "true")
21+
22+
23+
class GeometadataLiveServerTestCase(StaticLiveServerTestCase):
24+
"""
25+
Live server test case with geometadata fixtures.
26+
27+
Provides a running Django server and pre-populated test data
28+
for E2E testing with Playwright.
29+
"""
30+
31+
host = "localhost"
32+
33+
@classmethod
34+
def setUpClass(cls):
35+
super().setUpClass()
36+
# Install plugin settings
37+
plugin_settings.install()
38+
39+
# Create core fixtures
40+
cls.press = helpers.create_press()
41+
cls.journal, _ = helpers.create_journals()
42+
43+
# Create editor user
44+
cls.editor = helpers.create_user(
45+
"editor@test.com",
46+
["editor"],
47+
cls.journal,
48+
is_staff=True,
49+
is_active=True,
50+
)
51+
cls.editor.set_password("testpass123")
52+
cls.editor.save()
53+
54+
# Create published article with geometadata
55+
cls.article = helpers.create_article(cls.journal, with_author=True)
56+
cls.article.stage = "Published"
57+
cls.article.date_published = "2024-01-15"
58+
cls.article.save()
59+
60+
cls.geometadata = ArticleGeometadata.objects.create(
61+
article=cls.article,
62+
geometry_wkt="POINT(13.4 52.5)",
63+
place_name="Berlin",
64+
admin_units="Berlin, Germany",
65+
temporal_periods=[["2020-01-01", "2021-12-31"]],
66+
)
67+
68+
# Create issue with the article
69+
cls.issue = helpers.create_issue(
70+
cls.journal, vol=1, number=1, articles=[cls.article]
71+
)
72+
73+
@classmethod
74+
def tearDownClass(cls):
75+
super().tearDownClass()
76+
77+
78+
@pytest.fixture(scope="module")
79+
def live_server():
80+
"""
81+
Fixture providing a live Django server for E2E tests.
82+
83+
Uses Django's StaticLiveServerTestCase to serve static files.
84+
"""
85+
server = GeometadataLiveServerTestCase("run")
86+
server.setUpClass()
87+
try:
88+
yield server
89+
finally:
90+
server.tearDownClass()
91+
92+
93+
@pytest.fixture
94+
def base_url(live_server):
95+
"""Return the base URL of the live server."""
96+
return live_server.live_server_url
97+
98+
99+
@pytest.fixture
100+
def journal(live_server):
101+
"""Return the test journal."""
102+
return live_server.journal
103+
104+
105+
@pytest.fixture
106+
def article(live_server):
107+
"""Return the test article with geometadata."""
108+
return live_server.article
109+
110+
111+
@pytest.fixture
112+
def geometadata(live_server):
113+
"""Return the test geometadata."""
114+
return live_server.geometadata
115+
116+
117+
@pytest.fixture
118+
def issue(live_server):
119+
"""Return the test issue."""
120+
return live_server.issue
121+
122+
123+
@pytest.fixture
124+
def editor(live_server):
125+
"""Return the editor user."""
126+
return live_server.editor
127+
128+
129+
@pytest.fixture
130+
def authenticated_page(page: Page, base_url: str, editor, journal) -> Page:
131+
"""
132+
Return a page with an authenticated editor session.
133+
134+
Logs in via the Django login page.
135+
"""
136+
# Navigate to login page
137+
login_url = f"{base_url}/login/"
138+
page.goto(login_url)
139+
140+
# Fill in credentials
141+
page.fill('input[name="user_name"]', editor.email)
142+
page.fill('input[name="user_pass"]', "testpass123")
143+
page.click('button[type="submit"], input[type="submit"]')
144+
145+
# Wait for redirect
146+
page.wait_for_load_state("networkidle")
147+
148+
return page
149+
150+
151+
@pytest.fixture
152+
def map_selectors():
153+
"""
154+
Return CSS selectors for map elements.
155+
156+
Centralizes selector definitions for maintainability.
157+
"""
158+
return {
159+
"map_container": "#geometadata-map, .geometadata-map, [data-geometadata-map]",
160+
"leaflet_map": ".leaflet-container",
161+
"leaflet_marker": ".leaflet-marker-icon",
162+
"leaflet_popup": ".leaflet-popup",
163+
"leaflet_tile": ".leaflet-tile",
164+
"loading_indicator": ".geometadata-loading",
165+
"error_message": ".geometadata-error",
166+
"download_button": 'a[href*="geojson"], button[data-download="geojson"]',
167+
}

tests/e2e/pytest.ini

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[pytest]
2+
DJANGO_SETTINGS_MODULE = core.janeway_global_settings
3+
python_files = test_*.py
4+
python_classes = Test*
5+
python_functions = test_*
6+
addopts = --strict-markers -v
7+
markers =
8+
slow: marks tests as slow (deselect with '-m "not slow"')
9+
authenticated: marks tests that require authentication
10+
testpaths = .
11+
filterwarnings =
12+
ignore::DeprecationWarning
13+
ignore::PendingDeprecationWarning

0 commit comments

Comments
 (0)