Skip to content

Commit 802c8da

Browse files
authored
Merge pull request #7240 from freedomofpress/l10n-ci-screenshots
ci(translation): save screenshots as workflow artifacts
2 parents 007fb0c + 6c9917c commit 802c8da

19 files changed

+123
-108
lines changed

.github/workflows/translation.yml

+5
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,8 @@ jobs:
5656
- name: Run translation tests
5757
run: |
5858
LOCALES="${{ matrix.locale }}" make translation-test
59+
- name: Save screenshots
60+
uses: actions/upload-artifact@v4
61+
with:
62+
name: screenshots-${{ matrix.locale }}
63+
path: securedrop/tests/functional/pageslayout/screenshots/

Makefile

+3-2
Original file line numberDiff line numberDiff line change
@@ -427,9 +427,10 @@ $(DESKTOP_POT): ${DESKTOP_BASE}/*.in
427427
--output-file $@
428428
@rm ${DESKTOP_LOCALE_DIR}/*.po
429429

430-
# Render desktop list from "i18n.json".
430+
# Render the list of desktop locales from those in entries "i18n.json" that
431+
# include a "desktop" key.
431432
$(DESKTOP_I18N_CONF):
432-
@jq --raw-output '.supported_locales[].desktop' ${I18N_CONF} > $@
433+
@jq --raw-output '.supported_locales[].desktop | values' ${I18N_CONF} > $@
433434

434435
## Supported locales
435436

securedrop/bin/dev-config

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ with open('securedrop/config.py', 'w') as f:
2727
text += '\n'
2828
supported_locales = subprocess.check_output(['make', '--quiet', 'supported-locales']).decode().strip()
2929
text += f'SUPPORTED_LOCALES = {supported_locales}\n'
30-
text += 'SUPPORTED_LOCALES.append("en_US")\n'
3130
f.write(text)
3231

3332
with open('securedrop/rq_config.py', 'w') as f:

securedrop/i18n.json

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
"name": "Greek",
2121
"desktop": "el"
2222
},
23+
"en_US": {
24+
"name": "English"
25+
},
2326
"es_ES": {
2427
"name": "Spanish",
2528
"desktop": "es_ES"

securedrop/i18n.rst

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Czech (``cs``)
55
* German (``de_DE``)
66
* Greek (``el``)
7+
* English (``en_US``)
78
* Spanish (``es_ES``)
89
* French (``fr_FR``)
910
* Hindi (``hi``)

securedrop/tests/functional/app_navigators/journalist_app_nav.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,18 @@ def __init__(
3333
self._journalist_app_base_url = journalist_app_base_url
3434
self.nav_helper = NavigationHelper(web_driver)
3535
self.driver = web_driver
36+
37+
# Some string-based tests check this to avoid failing on translated strings.
3638
self.accept_languages = accept_languages
3739

40+
def got_expected_language(self, locale: str) -> None:
41+
expected = locale.replace("_", "-")
42+
43+
html = self.nav_helper.wait_for(lambda: self.driver.find_element(By.TAG_NAME, "html"))
44+
actual = html.get_attribute("lang")
45+
46+
assert actual == expected
47+
3848
def is_on_journalist_homepage(self) -> WebElement:
3949
return self.nav_helper.wait_for(
4050
lambda: self.driver.find_element(By.CSS_SELECTOR, "div.journalist-view-all")
@@ -341,6 +351,7 @@ def admin_visits_user_edit_page(self, username_of_journalist_to_edit: str) -> No
341351
# Ensure the admin is allowed to edit the journalist
342352
def can_edit_user():
343353
h = self.driver.find_elements(By.TAG_NAME, "h1")[0]
344-
assert f'Edit user "{username_of_journalist_to_edit}"' == h.text
354+
if not self.accept_languages:
355+
assert f'Edit user "{username_of_journalist_to_edit}"' == h.text
345356

346357
self.nav_helper.wait_for(can_edit_user)

securedrop/tests/functional/app_navigators/source_app_nav.py

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ def __init__(
2626
self._source_app_base_url = source_app_base_url
2727
self.nav_helper = NavigationHelper(web_driver)
2828
self.driver = web_driver
29+
30+
# Some string-based tests check this to avoid failing on translated strings.
2931
self.accept_languages = accept_languages
3032

3133
@classmethod

securedrop/tests/functional/conftest.py

+15-6
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,18 @@
1818
from tests.factories import SecureDropConfigFactory
1919
from tests.functional.db_session import get_database_session
2020
from tests.functional.web_drivers import WebDriverTypeEnum, get_web_driver
21-
22-
23-
# Function-scoped so that tests can be run in parallel if needed
24-
@pytest.fixture
25-
def firefox_web_driver() -> WebDriver: # type: ignore
26-
with get_web_driver(web_driver_type=WebDriverTypeEnum.FIREFOX) as web_driver:
21+
from tests.utils.i18n import get_test_locales
22+
23+
24+
# Function-scoped so that tests can be run in parallel if needed. The fixture
25+
# needs to know the locale at setup time, so we do that parameterization here
26+
# rather than at the test level.
27+
@pytest.fixture(params=get_test_locales())
28+
def firefox_web_driver(request) -> WebDriver: # type: ignore
29+
locale = request.param.replace("_", "-")
30+
with get_web_driver(
31+
web_driver_type=WebDriverTypeEnum.FIREFOX, accept_languages=locale
32+
) as web_driver:
2733
yield web_driver
2834

2935

@@ -209,6 +215,7 @@ def sd_servers(
209215
GPG_KEY_DIR=gpg_key_dir,
210216
JOURNALIST_KEY=journalist_key_fingerprint,
211217
RQ_WORKER_NAME=worker_name,
218+
SUPPORTED_LOCALES=get_test_locales(),
212219
)
213220

214221
# Spawn the apps in separate processes
@@ -232,6 +239,7 @@ def sd_servers_with_clean_state(
232239
GPG_KEY_DIR=gpg_key_dir,
233240
JOURNALIST_KEY=journalist_key_fingerprint,
234241
RQ_WORKER_NAME=worker_name,
242+
SUPPORTED_LOCALES=get_test_locales(),
235243
)
236244

237245
# Spawn the apps in separate processes
@@ -255,6 +263,7 @@ def sd_servers_with_submitted_file(
255263
GPG_KEY_DIR=gpg_key_dir,
256264
JOURNALIST_KEY=journalist_key_fingerprint,
257265
RQ_WORKER_NAME=worker_name,
266+
SUPPORTED_LOCALES=get_test_locales(),
258267
)
259268

260269
# Spawn the apps in separate processes with a callback to create a submission

securedrop/tests/functional/pageslayout/test_journalist.py

+17-17
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,22 @@
1717
#
1818
import pytest
1919
from tests.functional.app_navigators.journalist_app_nav import JournalistAppNavigator
20-
from tests.functional.pageslayout.utils import list_locales, save_static_data
20+
from tests.functional.pageslayout.utils import save_static_data
2121

2222

23-
@pytest.mark.parametrize("locale", list_locales())
2423
@pytest.mark.pagelayout
2524
class TestJournalistLayout:
26-
def test_login_index_and_edit(self, locale, sd_servers, firefox_web_driver):
25+
def test_login_index_and_edit(self, sd_servers, firefox_web_driver, request):
26+
locale = firefox_web_driver.locale
2727
# Given an SD server
2828
# And a journalist accessing the journalist interface
29-
locale_with_commas = locale.replace("_", "-")
3029
journ_app_nav = JournalistAppNavigator(
3130
journalist_app_base_url=sd_servers.journalist_app_base_url,
3231
web_driver=firefox_web_driver,
33-
accept_languages=locale_with_commas,
32+
accept_languages=locale,
3433
)
3534
journ_app_nav.driver.get(f"{sd_servers.journalist_app_base_url}/login")
35+
journ_app_nav.got_expected_language(locale)
3636
save_static_data(journ_app_nav.driver, locale, "journalist-login")
3737

3838
# And they log into the app and are an admin
@@ -54,14 +54,14 @@ def test_login_index_and_edit(self, locale, sd_servers, firefox_web_driver):
5454
journ_app_nav.journalist_visits_edit_account()
5555
save_static_data(journ_app_nav.driver, locale, "journalist-edit_account_user")
5656

57-
def test_index_entered_text(self, locale, sd_servers, firefox_web_driver):
57+
def test_index_entered_text(self, sd_servers, firefox_web_driver):
5858
# Given an SD server
5959
# And a journalist accessing the journalist interface
60-
locale_with_commas = locale.replace("_", "-")
60+
locale = firefox_web_driver.locale
6161
journ_app_nav = JournalistAppNavigator(
6262
journalist_app_base_url=sd_servers.journalist_app_base_url,
6363
web_driver=firefox_web_driver,
64-
accept_languages=locale_with_commas,
64+
accept_languages=locale,
6565
)
6666

6767
# Take a screenshot of the login page with the form completed
@@ -74,15 +74,15 @@ def test_index_entered_text(self, locale, sd_servers, firefox_web_driver):
7474
save_static_data(journ_app_nav.driver, locale, "journalist-index_with_text")
7575

7676
def test_index_with_submission_and_select_documents(
77-
self, locale, sd_servers_with_submitted_file, firefox_web_driver
77+
self, sd_servers_with_submitted_file, firefox_web_driver
7878
):
7979
# Given an SD server with an already-submitted file
8080
# And a journalist logging into the journalist interface
81-
locale_with_commas = locale.replace("_", "-")
81+
locale = firefox_web_driver.locale
8282
journ_app_nav = JournalistAppNavigator(
8383
journalist_app_base_url=sd_servers_with_submitted_file.journalist_app_base_url,
8484
web_driver=firefox_web_driver,
85-
accept_languages=locale_with_commas,
85+
accept_languages=locale,
8686
)
8787

8888
# Take a screenshot of the index page when there is a source and submission
@@ -115,27 +115,27 @@ def test_index_with_submission_and_select_documents(
115115
)
116116
save_static_data(journ_app_nav.driver, locale, "journalist-composes_reply")
117117

118-
def test_fail_to_visit_admin(self, locale, sd_servers, firefox_web_driver):
118+
def test_fail_to_visit_admin(self, sd_servers, firefox_web_driver):
119119
# Given an SD server
120120
# And someone accessing the journalist interface
121-
locale_with_commas = locale.replace("_", "-")
121+
locale = firefox_web_driver.locale
122122
journ_app_nav = JournalistAppNavigator(
123123
journalist_app_base_url=sd_servers.journalist_app_base_url,
124124
web_driver=firefox_web_driver,
125-
accept_languages=locale_with_commas,
125+
accept_languages=locale,
126126
)
127127
# Take a screenshot of them trying to force-browse to the admin interface
128128
journ_app_nav.driver.get(f"{sd_servers.journalist_app_base_url}/admin")
129129
save_static_data(journ_app_nav.driver, locale, "journalist-code-fail_to_visit_admin")
130130

131-
def test_fail_login(self, locale, sd_servers, firefox_web_driver):
131+
def test_fail_login(self, sd_servers, firefox_web_driver):
132132
# Given an SD server
133133
# And someone accessing the journalist interface
134-
locale_with_commas = locale.replace("_", "-")
134+
locale = firefox_web_driver.locale
135135
journ_app_nav = JournalistAppNavigator(
136136
journalist_app_base_url=sd_servers.journalist_app_base_url,
137137
web_driver=firefox_web_driver,
138-
accept_languages=locale_with_commas,
138+
accept_languages=locale,
139139
)
140140

141141
# Take a screenshot of trying to log in using invalid credentials

securedrop/tests/functional/pageslayout/test_journalist_account.py

+8-11
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,21 @@
2121
from selenium.webdriver import ActionChains
2222
from selenium.webdriver.common.by import By
2323
from tests.functional.app_navigators.journalist_app_nav import JournalistAppNavigator
24-
from tests.functional.pageslayout.utils import list_locales, save_static_data
24+
from tests.functional.pageslayout.utils import save_static_data
2525

2626

27-
@pytest.mark.parametrize("locale", list_locales())
2827
@pytest.mark.pagelayout
2928
class TestJournalistLayoutAccount:
3029
def test_account_edit_and_set_hotp_secret(
31-
self, locale, sd_servers_with_clean_state, firefox_web_driver
30+
self, sd_servers_with_clean_state, firefox_web_driver
3231
):
3332
# Given an SD server
3433
# And a journalist logging into the journalist interface
35-
locale_with_commas = locale.replace("_", "-")
34+
locale = firefox_web_driver.locale
3635
journ_app_nav = JournalistAppNavigator(
3736
journalist_app_base_url=sd_servers_with_clean_state.journalist_app_base_url,
3837
web_driver=firefox_web_driver,
39-
accept_languages=locale_with_commas,
38+
accept_languages=locale,
4039
)
4140
journ_app_nav.journalist_logs_in(
4241
username=sd_servers_with_clean_state.journalist_username,
@@ -87,7 +86,7 @@ def explanatory_tooltip_is_correct() -> None:
8786
explanatory_tooltip_opacity = explanatory_tooltip.value_of_css_property("opacity")
8887
assert explanatory_tooltip_opacity == "1"
8988

90-
if assert_tooltip_text_is:
89+
if assert_tooltip_text_is and not journ_app_nav.accept_languages:
9190
assert explanatory_tooltip.text == assert_tooltip_text_is
9291

9392
journ_app_nav.nav_helper.wait_for(explanatory_tooltip_is_correct)
@@ -97,16 +96,14 @@ def explanatory_tooltip_is_correct() -> None:
9796
alert = journ_app_nav.driver.switch_to.alert
9897
alert.accept()
9998

100-
def test_account_new_two_factor_totp(
101-
self, locale, sd_servers_with_clean_state, firefox_web_driver
102-
):
99+
def test_account_new_two_factor_totp(self, sd_servers_with_clean_state, firefox_web_driver):
103100
# Given an SD server
104101
# And a journalist logging into the journalist interface
105-
locale_with_commas = locale.replace("_", "-")
102+
locale = firefox_web_driver.locale
106103
journ_app_nav = JournalistAppNavigator(
107104
journalist_app_base_url=sd_servers_with_clean_state.journalist_app_base_url,
108105
web_driver=firefox_web_driver,
109-
accept_languages=locale_with_commas,
106+
accept_languages=locale,
110107
)
111108
journ_app_nav.journalist_logs_in(
112109
username=sd_servers_with_clean_state.journalist_username,

securedrop/tests/functional/pageslayout/test_journalist_admin.py

+17-17
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,22 @@
2525
from selenium.webdriver import ActionChains
2626
from selenium.webdriver.common.by import By
2727
from tests.functional.app_navigators.journalist_app_nav import JournalistAppNavigator
28-
from tests.functional.pageslayout.utils import list_locales, save_static_data
28+
from tests.functional.pageslayout.utils import save_static_data
2929

3030

31-
@pytest.mark.parametrize("locale", list_locales())
3231
@pytest.mark.pagelayout
3332
class TestAdminLayoutAddAndEditUser:
3433
def test_admin_adds_user_hotp_and_edits_hotp(
35-
self, locale, sd_servers_with_clean_state, firefox_web_driver
34+
self, sd_servers_with_clean_state, firefox_web_driver
3635
):
3736
# Given an SD server
3837
# And a journalist logging into the journalist interface as an admin
3938
assert sd_servers_with_clean_state.journalist_is_admin
40-
locale_with_commas = locale.replace("_", "-")
39+
locale = firefox_web_driver.locale
4140
journ_app_nav = JournalistAppNavigator(
4241
journalist_app_base_url=sd_servers_with_clean_state.journalist_app_base_url,
4342
web_driver=firefox_web_driver,
44-
accept_languages=locale_with_commas,
43+
accept_languages=locale,
4544
)
4645
journ_app_nav.journalist_logs_in(
4746
username=sd_servers_with_clean_state.journalist_username,
@@ -118,16 +117,16 @@ def _admin_visits_reset_2fa_hotp_step() -> None:
118117
)
119118

120119
def test_admin_adds_user_totp_and_edits_totp(
121-
self, locale, sd_servers_with_clean_state, firefox_web_driver
120+
self, sd_servers_with_clean_state, firefox_web_driver
122121
):
123122
# Given an SD server
124123
# And a journalist logging into the journalist interface as an admin
125124
assert sd_servers_with_clean_state.journalist_is_admin
126-
locale_with_commas = locale.replace("_", "-")
125+
locale = firefox_web_driver.locale
127126
journ_app_nav = JournalistAppNavigator(
128127
journalist_app_base_url=sd_servers_with_clean_state.journalist_app_base_url,
129128
web_driver=firefox_web_driver,
130-
accept_languages=locale_with_commas,
129+
accept_languages=locale,
131130
)
132131
journ_app_nav.journalist_logs_in(
133132
username=sd_servers_with_clean_state.journalist_username,
@@ -223,18 +222,17 @@ def _retry_2fa_pop_ups(
223222
logging.info("Selenium has failed to click; retrying.")
224223

225224

226-
@pytest.mark.parametrize("locale", list_locales())
227225
@pytest.mark.pagelayout
228226
class TestAdminLayoutEditConfig:
229-
def test_admin_changes_logo(self, locale, sd_servers_with_clean_state, firefox_web_driver):
227+
def test_admin_changes_logo(self, sd_servers_with_clean_state, firefox_web_driver):
230228
# Given an SD server
231229
# And a journalist logging into the journalist interface as an admin
232230
assert sd_servers_with_clean_state.journalist_is_admin
233-
locale_with_commas = locale.replace("_", "-")
231+
locale = firefox_web_driver.locale
234232
journ_app_nav = JournalistAppNavigator(
235233
journalist_app_base_url=sd_servers_with_clean_state.journalist_app_base_url,
236234
web_driver=firefox_web_driver,
237-
accept_languages=locale_with_commas,
235+
accept_languages=locale,
238236
)
239237
journ_app_nav.journalist_logs_in(
240238
username=sd_servers_with_clean_state.journalist_username,
@@ -257,22 +255,23 @@ def test_admin_changes_logo(self, locale, sd_servers_with_clean_state, firefox_w
257255
# Then it succeeds
258256
def updated_image() -> None:
259257
flash_msg = journ_app_nav.driver.find_element(By.CSS_SELECTOR, ".flash")
260-
assert "Image updated." in flash_msg.text
258+
if not journ_app_nav.accept_languages:
259+
assert "Image updated." in flash_msg.text
261260

262261
journ_app_nav.nav_helper.wait_for(updated_image, timeout=20)
263262

264263
# Take a screenshot
265264
save_static_data(journ_app_nav.driver, locale, "journalist-admin_changes_logo_image")
266265

267-
def test_ossec_alert_button(self, locale, sd_servers, firefox_web_driver):
266+
def test_ossec_alert_button(self, sd_servers, firefox_web_driver):
268267
# Given an SD server
269268
# And a journalist logging into the journalist interface as an admin
270269
assert sd_servers.journalist_is_admin
271-
locale_with_commas = locale.replace("_", "-")
270+
locale = firefox_web_driver.locale
272271
journ_app_nav = JournalistAppNavigator(
273272
journalist_app_base_url=sd_servers.journalist_app_base_url,
274273
web_driver=firefox_web_driver,
275-
accept_languages=locale_with_commas,
274+
accept_languages=locale,
276275
)
277276
journ_app_nav.journalist_logs_in(
278277
username=sd_servers.journalist_username,
@@ -290,7 +289,8 @@ def test_ossec_alert_button(self, locale, sd_servers, firefox_web_driver):
290289
# Then it succeeds
291290
def test_alert_sent():
292291
flash_msg = journ_app_nav.driver.find_element(By.CSS_SELECTOR, ".flash")
293-
assert "Test alert sent. Please check your email." in flash_msg.text
292+
if not journ_app_nav.accept_languages:
293+
assert "Test alert sent. Please check your email." in flash_msg.text
294294

295295
journ_app_nav.nav_helper.wait_for(test_alert_sent)
296296

0 commit comments

Comments
 (0)