Skip to content

Commit 7e9d497

Browse files
committed
Add test and doc for changing Firefox browser language and locale
Fixes #2361 Signed-off-by: Viet Nguyen Duc <[email protected]>
1 parent 3318c3a commit 7e9d497

File tree

12 files changed

+140
-31
lines changed

12 files changed

+140
-31
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pip-selfcheck.json
4444

4545
# End of https://www.gitignore.io/api/virtualenv
4646
tests/tests/*
47+
tests/target/*
4748

4849
# Created by https://www.gitignore.io/api/python
4950

Makefile

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -584,8 +584,13 @@ test_edge_standalone:
584584
;; \
585585
esac
586586

587-
test_firefox:
588-
PLATFORMS=$(PLATFORMS) VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) BASE_RELEASE=$(BASE_RELEASE) BASE_VERSION=$(BASE_VERSION) BINDING_VERSION=$(BINDING_VERSION) SKIP_BUILD=true ./tests/bootstrap.sh NodeFirefox
587+
test_firefox_download_lang_packs:
588+
FIREFOX_VERSION=$$(docker run --rm $(NAME)/node-firefox:$(TAG_VERSION) firefox --version | awk '{print $$3}') ; \
589+
./NodeFirefox/get_lang_package.sh $$FIREFOX_VERSION ./tests/target/firefox_lang_packs
590+
591+
test_firefox: test_firefox_download_lang_packs
592+
PLATFORMS=$(PLATFORMS) VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) BASE_RELEASE=$(BASE_RELEASE) BASE_VERSION=$(BASE_VERSION) BINDING_VERSION=$(BINDING_VERSION) SKIP_BUILD=true \
593+
TEST_FIREFOX_INSTALL_LANG_PACKAGE=true ./tests/bootstrap.sh NodeFirefox
589594

590595
test_firefox_standalone:
591596
PLATFORMS=$(PLATFORMS) VERSION=$(TAG_VERSION) NAMESPACE=$(NAMESPACE) BASE_RELEASE=$(BASE_RELEASE) BASE_VERSION=$(BASE_VERSION) BINDING_VERSION=$(BINDING_VERSION) SKIP_BUILD=true ./tests/bootstrap.sh StandaloneFirefox
@@ -645,6 +650,10 @@ test_video: video hub chrome firefox edge chromium
645650
docker_compose_file=$(or $(DOCKER_COMPOSE_FILE), docker-compose-v3-test-video.yml) ; \
646651
list_of_tests_amd64=$(or $(LIST_OF_TESTS_AMD64), "NodeChrome NodeChromium NodeFirefox NodeEdge") ; \
647652
list_of_tests_arm64=$(or $(LIST_OF_TESTS_ARM64), "NodeChromium NodeFirefox") ; \
653+
TEST_FIREFOX_INSTALL_LANG_PACKAGE=$(or $(TEST_FIREFOX_INSTALL_LANG_PACKAGE), "true") ; \
654+
if [ "$${TEST_FIREFOX_INSTALL_LANG_PACKAGE}" = "true" ]; then \
655+
make test_firefox_download_lang_packs ; \
656+
fi ; \
648657
if [ "$(PLATFORMS)" = "linux/amd64" ]; then \
649658
list_nodes="$${list_of_tests_amd64}" ; \
650659
else \
@@ -659,6 +668,7 @@ test_video: video hub chrome firefox edge chromium
659668
echo BINDING_VERSION=$(BINDING_VERSION) >> .env ; \
660669
echo TEST_DELAY_AFTER_TEST=$(or $(TEST_DELAY_AFTER_TEST), 2) >> .env ; \
661670
echo SELENIUM_ENABLE_MANAGED_DOWNLOADS=$(or $(SELENIUM_ENABLE_MANAGED_DOWNLOADS), "true") >> .env ; \
671+
echo TEST_FIREFOX_INSTALL_LANG_PACKAGE=$${TEST_FIREFOX_INSTALL_LANG_PACKAGE} >> .env ; \
662672
echo BASIC_AUTH_USERNAME=$(or $(BASIC_AUTH_USERNAME), "admin") >> .env ; \
663673
echo BASIC_AUTH_PASSWORD=$(or $(BASIC_AUTH_PASSWORD), "admin") >> .env ; \
664674
echo SUB_PATH=$(or $(SUB_PATH), "/selenium") >> .env ; \

NodeBase/Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ ARG LANG_WHICH=en
1616
ARG LANG_WHERE=US
1717
ARG ENCODING=UTF-8
1818
ARG LANGUAGE=${LANG_WHICH}_${LANG_WHERE}.${ENCODING}
19-
ARG TARGETARCH
2019

2120
USER root
2221

NodeChrome/Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ USER root
1515
# google-chrome-unstable
1616
#============================================
1717
ARG CHROME_VERSION="google-chrome-stable"
18-
ARG TARGETARCH
1918
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor | tee /etc/apt/trusted.gpg.d/google.gpg >/dev/null \
2019
&& echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \
2120
&& apt-get update -qqy \

NodeEdge/Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ USER root
1313
# e.g. microsoft-edge-beta=88.0.692.0-1
1414
#============================================
1515
ARG EDGE_VERSION="microsoft-edge-stable"
16-
ARG TARGETARCH
1716
RUN wget -q -O - https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/microsoft.gpg >/dev/null \
1817
&& echo "deb https://packages.microsoft.com/repos/edge stable main" >> /etc/apt/sources.list.d/microsoft-edge.list \
1918
&& apt-get update -qqy \

NodeFirefox/Dockerfile

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ RUN if [ "$(dpkg --print-architecture)" = "amd64" ]; then \
1717
FIREFOX_DOWNLOAD_URL="https://download.mozilla.org/?product=firefox-nightly-latest-ssl&os=linux64-aarch64&lang=en-US" ; \
1818
fi \
1919
&& apt-get update -qqy \
20-
&& apt-get -qqy --no-install-recommends install libavcodec-extra \
21-
libgtk-3-dev libdbus-glib-1-dev \
22-
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/* \
20+
&& apt-get -qqy --no-install-recommends install libavcodec-extra libgtk-3-dev libdbus-glib-1-dev \
21+
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/* ${HOME}/firefox \
2322
&& wget --no-verbose -O /tmp/firefox.tar.bz2 $FIREFOX_DOWNLOAD_URL \
24-
&& rm -rf /opt/firefox \
25-
&& tar -C /opt -xjf /tmp/firefox.tar.bz2 \
23+
&& tar -C ${HOME} -xjf /tmp/firefox.tar.bz2 \
2624
&& rm /tmp/firefox.tar.bz2 \
27-
&& mv /opt/firefox /opt/firefox-$FIREFOX_VERSION \
28-
&& ln -fs /opt/firefox-$FIREFOX_VERSION/firefox /usr/bin/firefox
25+
&& mkdir -p ${HOME}/firefox/distribution/extensions \
26+
&& setfacl -Rm u:${SEL_USER}:rwx ${HOME}/firefox \
27+
&& setfacl -Rm g:${SEL_GROUP}:rwx ${HOME}/firefox \
28+
&& ln -fs ${HOME}/firefox/firefox /usr/bin/firefox
2929

3030
#============
3131
# GeckoDriver
@@ -46,16 +46,19 @@ RUN LATEST_VERSION=$(curl -sk https://api.github.com/repos/mozilla/geckodriver/r
4646
#============================================
4747
# Firefox cleanup script and supervisord file
4848
#============================================
49-
COPY firefox-cleanup.sh /opt/bin/firefox-cleanup.sh
50-
COPY firefox-cleanup.conf /etc/supervisor/conf.d/firefox-cleanup.conf
49+
COPY --chown="${SEL_UID}:${SEL_GID}" firefox-cleanup.sh get_lang_package.sh /opt/bin/
50+
COPY --chown="${SEL_UID}:${SEL_GID}" firefox-cleanup.conf /etc/supervisor/conf.d/firefox-cleanup.conf
51+
RUN chmod +x /opt/bin/firefox-cleanup.sh /opt/bin/get_lang_package.sh
5152

5253
USER ${SEL_UID}
5354

5455
#============================================
5556
# Dumping Browser information for config
5657
#============================================
57-
RUN echo "firefox" > /opt/selenium/browser_name
58-
RUN firefox --version | awk '{print $3}' > /opt/selenium/browser_version
59-
RUN echo "\"moz:firefoxOptions\": {\"binary\": \"/usr/bin/firefox\"}" > /opt/selenium/browser_binary_location
58+
RUN echo "firefox" > /opt/selenium/browser_name \
59+
&& firefox --version | awk '{print $3}' > /opt/selenium/browser_version \
60+
&& echo "\"moz:firefoxOptions\": {\"binary\": \"/usr/bin/firefox\"}" > /opt/selenium/browser_binary_location \
61+
# Download the language pack for Firefox
62+
&& /opt/bin/get_lang_package.sh
6063

6164
ENV SE_OTEL_SERVICE_NAME="selenium-node-firefox"

NodeFirefox/get_lang_package.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/bin/bash
2+
3+
function on_exit() {
4+
local exit_code=$?
5+
rm -f /tmp/xpi_files.txt
6+
exit $exit_code
7+
}
8+
trap on_exit EXIT ERR
9+
10+
# Script is used to download language packs for a specific version of Firefox.
11+
# It requires the version number as the first argument and the target directory as the second argument.
12+
13+
VERSION=${1:-$(firefox --version | awk '{print $3}')}
14+
TARGET_DIR="${2:-$(dirname $(readlink -f $(which firefox)))/distribution/extensions}"
15+
BASE_URL="https://ftp.mozilla.org/pub/firefox/releases/$VERSION/linux-x86_64/xpi/"
16+
17+
# Create target directory if it doesn't exist
18+
mkdir -p "${TARGET_DIR}"
19+
20+
# Download the list of files
21+
wget -q -O - "${BASE_URL}" | grep -oP '(?<=href=")[^"]*.xpi' >/tmp/xpi_files.txt
22+
23+
echo "Downloading language packs for Firefox version $VERSION to $TARGET_DIR ..."
24+
25+
# Loop through each file and download it
26+
while IFS= read -r file; do
27+
file=$(basename "${file}")
28+
echo "Downloading "${BASE_URL}${file}" ..."
29+
curl -sk -o "${TARGET_DIR}/${file}" "${BASE_URL}${file}"
30+
target_file="${TARGET_DIR}/langpack-${file%.xpi}@firefox.mozilla.org.xpi"
31+
mv "${TARGET_DIR}/${file}" "${target_file}"
32+
if [ -f "${target_file}" ]; then
33+
echo "Downloaded ${target_file}"
34+
fi
35+
done </tmp/xpi_files.txt
36+
37+
echo "All language packs are downloaded to $TARGET_DIR"

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Talk to us at https://www.selenium.dev/support/
6767
* [Automatic browser leftovers cleanup](#automatic-browser-leftovers-cleanup)
6868
* [Mask sensitive information in console logs](#mask-sensitive-information-in-console-logs)
6969
* [Secure Connection](#secure-connection)
70+
* [Browser language and locale](#browser-language-and-locale)
7071
* [Building the images](#building-the-images)
7172
* [Build the images with specific versions](#build-the-images-with-specific-versions)
7273
* [Upgrade browser version in the images](#upgrade-browser-version-in-the-images)
@@ -1278,6 +1279,36 @@ The self-signed certificate also needs to be trusted by the client (add to syste
12781279

12791280
Refer to sample: [`docker-compose-v3-full-grid-secure.yml`](docker-compose-v3-full-grid-secure.yml)
12801281

1282+
## Browser language and locale
1283+
1284+
Different browsers have different ways to set the language and locale from binding.
1285+
1286+
### Firefox
1287+
1288+
Firefox can be configured to use a specific language and locale by setting the profile preference when create WebDriver from binding. In addition, language pack need to be installed as add-on for browser UI language to take effect. For example, to set the browser language and locale to `vi-VN`, you can use the following steps:
1289+
1290+
Get the latest Firefox language pack for the desired language e.g. https://download.mozilla.org/?product=firefox-langpack-latest-SSL&lang=vi. Then, you can install the language pack as an add-on when creating the RemoteWebDriver instance.
1291+
1292+
```python
1293+
profile = webdriver.FirefoxProfile()
1294+
profile.set_preference('intl.accept_languages', 'vi-VN,vi')
1295+
profile.set_preference('intl.locale.requested', 'vi-VN,vi')
1296+
options = FirefoxOptions()
1297+
options.profile = profile
1298+
driver = webdriver.Remote(options=options, command_executor="http://selenium-hub:4444/wd/hub")
1299+
webdriver.Firefox.install_addon(driver, "/local/path/to/vi.xpi")
1300+
driver.get('https://google.com')
1301+
```
1302+
1303+
There is a [script](NodeFirefox/get_lang_package.sh) to get all available language packs for a given Firefox version. You can run the script to get the language packs to your source. For example:
1304+
1305+
```bash
1306+
FIREFOX_VERSION=$(docker run --rm --entrypoint="" selenium/node-firefox:latest firefox --version | awk '{print $3}') \
1307+
&& ./NodeFirefox/get_lang_package.sh ${FIREFOX_VERSION} /local/path/to/download
1308+
```
1309+
1310+
Or, you can mount the container directory `/home/seluser/firefox/distribution/extensions` to host directory to access packs were pre-built in the container for using in your test script.
1311+
12811312
___
12821313

12831314
## Building the images

tests/SeleniumTests/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
TEST_NODE_RELAY = os.environ.get('TEST_NODE_RELAY', 'false')
2626
TEST_ANDROID_PLATFORM_API = os.environ.get('ANDROID_PLATFORM_API')
2727
TEST_PLATFORMS = os.environ.get('TEST_PLATFORMS', 'linux/amd64')
28+
TEST_FIREFOX_INSTALL_LANG_PACKAGE = os.environ.get('TEST_FIREFOX_INSTALL_LANG_PACKAGE', 'false').lower() == 'true'
2829

2930
if SELENIUM_GRID_USERNAME and SELENIUM_GRID_PASSWORD:
3031
SELENIUM_GRID_HOST = f"{SELENIUM_GRID_USERNAME}:{SELENIUM_GRID_PASSWORD}@{SELENIUM_GRID_HOST}"
@@ -187,6 +188,8 @@ def setUp(self):
187188
profile = webdriver.FirefoxProfile()
188189
profile.set_preference("browser.download.manager.showWhenStarting", False)
189190
profile.set_preference("browser.helperApps.neverAsk.saveToDisk", "*/*")
191+
profile.set_preference('intl.accept_languages', 'vi-VN,vi')
192+
profile.set_preference('intl.locale.requested', 'vi-VN,vi')
190193
options = FirefoxOptions()
191194
options.profile = profile
192195
options.enable_downloads = SELENIUM_ENABLE_MANAGED_DOWNLOADS
@@ -212,6 +215,20 @@ def test_title_and_maximize_window(self):
212215
self.driver.maximize_window()
213216
self.assertTrue(self.driver.title == 'The Internet')
214217

218+
def test_accept_languages(self):
219+
if TEST_FIREFOX_INSTALL_LANG_PACKAGE:
220+
addon_id = webdriver.Firefox.install_addon(self.driver, "./target/firefox_lang_packs/[email protected]")
221+
self.driver.get('https://gtranslate.io/detect-browser-language')
222+
wait = WebDriverWait(self.driver, WEB_DRIVER_WAIT_TIMEOUT)
223+
lang_code = wait.until(
224+
EC.presence_of_element_located((By.XPATH, '(//*[@class="notranslate"])[1]'))
225+
)
226+
self.driver.execute_script("arguments[0].scrollIntoView();", lang_code)
227+
self.assertTrue(lang_code.text == 'vi-VN', "Language code should be vi-VN")
228+
time.sleep(1)
229+
self.driver.get('https://google.com')
230+
time.sleep(2)
231+
215232
class Autoscaling():
216233
def run(self, test_classes):
217234
with concurrent.futures.ThreadPoolExecutor() as executor:

tests/docker-compose-v3-test-standalone.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,5 @@ services:
7979
- BINDING_VERSION=${BINDING_VERSION}
8080
- TEST_DELAY_AFTER_TEST=${TEST_DELAY_AFTER_TEST}
8181
- SELENIUM_ENABLE_MANAGED_DOWNLOADS=${SELENIUM_ENABLE_MANAGED_DOWNLOADS}
82+
- TEST_FIREFOX_INSTALL_LANG_PACKAGE=${TEST_FIREFOX_INSTALL_LANG_PACKAGE}
8283
command: ["/bin/bash", "-c", "./bootstrap.sh ${NODE}"]

0 commit comments

Comments
 (0)