Skip to content

Commit 5c47878

Browse files
committed
Add a "--xvfb" option to run tests using an Xvfb virtual display
1 parent 5e07609 commit 5c47878

File tree

7 files changed

+74
-26
lines changed

7 files changed

+74
-26
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,8 +360,9 @@ The code above will leave your browser window open in case there's a failure. (i
360360
--firefox-pref=SET # (Set a Firefox preference:value set, comma-separated.)
361361
--extension-zip=ZIP # (Load a Chrome Extension .zip|.crx, comma-separated.)
362362
--extension-dir=DIR # (Load a Chrome Extension directory, comma-separated.)
363-
--headless # (Run tests headlessly. Default mode on Linux OS.)
364-
--headed # (Run tests with a GUI on Linux OS.)
363+
--headless # (Run tests in headless mode. The default arg on Linux OS.)
364+
--headed # (Run tests in headed/GUI mode on Linux OS.)
365+
--xvfb # (Run tests using the Xvfb virtual display server on Linux OS.)
365366
--locale=LOCALE_CODE # (Set the Language Locale Code for the web browser.)
366367
--interval=SECONDS # (The autoplay interval for presentations & tour steps)
367368
--start-page=URL # (The starting URL for the web browser when tests begin.)

examples/raw_parameter_script.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
sb.browser = "chrome"
3434
sb.headless = False
3535
sb.headed = False
36+
sb.xvfb = False
3637
sb.start_page = None
3738
sb.locale_code = None
3839
sb.protocol = "http"

help_docs/customizing_test_runs.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,9 @@ SeleniumBase provides additional ``pytest`` command-line options for tests:
122122
--firefox-pref=SET # (Set a Firefox preference:value set, comma-separated.)
123123
--extension-zip=ZIP # (Load a Chrome Extension .zip|.crx, comma-separated.)
124124
--extension-dir=DIR # (Load a Chrome Extension directory, comma-separated.)
125-
--headless # (Run tests headlessly. Default mode on Linux OS.)
126-
--headed # (Run tests with a GUI on Linux OS.)
125+
--headless # (Run tests in headless mode. The default arg on Linux OS.)
126+
--headed # (Run tests in headed/GUI mode on Linux OS.)
127+
--xvfb # (Run tests using the Xvfb virtual display server on Linux OS.)
127128
--locale=LOCALE_CODE # (Set the Language Locale Code for the web browser.)
128129
--interval=SECONDS # (The autoplay interval for presentations & tour steps)
129130
--start-page=URL # (The starting URL for the web browser when tests begin.)

seleniumbase/core/browser_launcher.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ def _set_firefox_options(
519519
options.set_preference(
520520
"browser.download.manager.showAlertOnComplete", False
521521
)
522-
if headless and "linux" not in PLATFORM:
522+
if headless:
523523
options.add_argument("--headless")
524524
if locale_code:
525525
options.set_preference("intl.accept_languages", locale_code)

seleniumbase/fixtures/base_case.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2458,7 +2458,7 @@ def get_new_driver(
24582458
if switch_to:
24592459
self.driver = new_driver
24602460
self.browser = browser_name
2461-
if self.headless:
2461+
if self.headless or self.xvfb:
24622462
# Make sure the invisible browser window is big enough
24632463
width = settings.HEADLESS_START_WIDTH
24642464
height = settings.HEADLESS_START_HEIGHT
@@ -5258,7 +5258,7 @@ def begin_presentation(
52585258
interval - The delay time between autoplaying slides. (in seconds)
52595259
If set to 0 (default), autoplay is disabled.
52605260
"""
5261-
if self.headless:
5261+
if self.headless or self.xvfb:
52625262
return # Presentations should not run in headless mode.
52635263
if not name:
52645264
name = "default"
@@ -5949,7 +5949,7 @@ def display_chart(self, chart_name=None, filename=None, interval=0):
59495949
interval - The delay time for auto-advancing charts. (in seconds)
59505950
If set to 0 (default), auto-advancing is disabled.
59515951
"""
5952-
if self.headless:
5952+
if self.headless or self.xvfb:
59535953
interval = 1 # Race through chart if running in headless mode
59545954
if not chart_name:
59555955
chart_name = "default"
@@ -6635,7 +6635,7 @@ def play_tour(self, name=None, interval=0):
66356635
"""
66366636
from seleniumbase.core import tour_helper
66376637

6638-
if self.headless:
6638+
if self.headless or self.xvfb:
66396639
return # Tours should not run in headless mode.
66406640

66416641
self.wait_for_ready_state_complete()
@@ -6852,7 +6852,7 @@ def get_jqc_button_input(self, message, buttons, options=None):
68526852
for option in options:
68536853
if not type(option) is list and not type(option) is tuple:
68546854
raise Exception('"options" should be a list of tuples!')
6855-
if self.headless:
6855+
if self.headless or self.xvfb:
68566856
return buttons[-1][0]
68576857
jqc_helper.jquery_confirm_button_dialog(
68586858
self.driver, message, buttons, options
@@ -6939,7 +6939,7 @@ def get_jqc_text_input(self, message, button=None, options=None):
69396939
for option in options:
69406940
if not type(option) is list and not type(option) is tuple:
69416941
raise Exception('"options" should be a list of tuples!')
6942-
if self.headless:
6942+
if self.headless or self.xvfb:
69436943
return ""
69446944
jqc_helper.jquery_confirm_text_dialog(
69456945
self.driver, message, button, options
@@ -7014,7 +7014,7 @@ def get_jqc_form_inputs(self, message, buttons, options=None):
70147014
for option in options:
70157015
if not type(option) is list and not type(option) is tuple:
70167016
raise Exception('"options" should be a list of tuples!')
7017-
if self.headless:
7017+
if self.headless or self.xvfb:
70187018
return ("", buttons[-1][0])
70197019
jqc_helper.jquery_confirm_full_dialog(
70207020
self.driver, message, buttons, options
@@ -8839,6 +8839,7 @@ def setUp(self, masterqa_mode=False):
88398839
self.headless = sb_config.headless
88408840
self.headless_active = False
88418841
self.headed = sb_config.headed
8842+
self.xvfb = sb_config.xvfb
88428843
self.locale_code = sb_config.locale_code
88438844
self.interval = sb_config.interval
88448845
self.start_page = sb_config.start_page
@@ -8956,7 +8957,7 @@ def setUp(self, masterqa_mode=False):
89568957
self.__skip_reason = None
89578958
self.testcase_manager.insert_testcase_data(data_payload)
89588959
self.case_start_time = int(time.time() * 1000)
8959-
if self.headless:
8960+
if self.headless or self.xvfb:
89608961
width = settings.HEADLESS_START_WIDTH
89618962
height = settings.HEADLESS_START_HEIGHT
89628963
try:
@@ -9907,7 +9908,7 @@ def tearDown(self):
99079908
self.__process_dashboard(has_exception)
99089909
# (Pytest) Finally close all open browser windows
99099910
self.__quit_all_drivers()
9910-
if self.headless:
9911+
if self.headless or self.xvfb:
99119912
if self.headless_active:
99129913
try:
99139914
self.display.stop()

seleniumbase/plugins/pytest_plugin.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ def pytest_addoption(parser):
4949
--firefox-pref=SET (Set a Firefox preference:value set, comma-separated.)
5050
--extension-zip=ZIP (Load a Chrome Extension .zip|.crx, comma-separated.)
5151
--extension-dir=DIR (Load a Chrome Extension directory, comma-separated.)
52-
--headless (Run tests headlessly. Default mode on Linux OS.)
53-
--headed (Run tests with a GUI on Linux OS.)
52+
--headless (Run tests in headless mode. The default arg on Linux OS.)
53+
--headed (Run tests in headed/GUI mode on Linux OS.)
54+
--xvfb (Run tests using the Xvfb virtual display server on Linux OS.)
5455
--locale=LOCALE_CODE (Set the Language Locale Code for the web browser.)
5556
--interval=SECONDS (The autoplay interval for presentations & tour steps)
5657
--start-page=URL (The starting URL for the web browser when tests begin.)
@@ -504,6 +505,17 @@ def pytest_addoption(parser):
504505
(The default setting on Linux is headless.)
505506
(The default setting on Mac or Windows is headed.)""",
506507
)
508+
parser.addoption(
509+
"--xvfb",
510+
action="store_true",
511+
dest="xvfb",
512+
default=False,
513+
help="""Using this makes tests run headlessly using Xvfb
514+
instead of the browser's built-in headless mode.
515+
When using "--xvfb", the "--headless" option
516+
will no longer be enabled by default on Linux.
517+
Default: False. (Linux-ONLY!)""",
518+
)
507519
parser.addoption(
508520
"--locale_code",
509521
"--locale-code",
@@ -957,6 +969,7 @@ def pytest_configure(config):
957969
sb_config.device_metrics = config.getoption("device_metrics")
958970
sb_config.headless = config.getoption("headless")
959971
sb_config.headed = config.getoption("headed")
972+
sb_config.xvfb = config.getoption("xvfb")
960973
sb_config.locale_code = config.getoption("locale_code")
961974
sb_config.interval = config.getoption("interval")
962975
sb_config.start_page = config.getoption("start_page")
@@ -1051,14 +1064,20 @@ def pytest_configure(config):
10511064
if sb_config._html_report_name == "dashboard.html":
10521065
sb_config._dash_is_html_report = True
10531066

1067+
if sb_config.xvfb and "linux" not in sys.platform:
1068+
# The Xvfb virtual display server is for Linux OS Only!
1069+
sb_config.xvfb = False
10541070
if (
10551071
"linux" in sys.platform
10561072
and not sb_config.headed
10571073
and not sb_config.headless
1074+
and not sb_config.xvfb
10581075
):
10591076
print(
1060-
"(Running with --headless on Linux. "
1061-
"Use --headed or --gui to override.)"
1077+
"(Linux uses --headless by default. "
1078+
"To override, use --headed / --gui. "
1079+
"For Xvfb mode instead, use --xvfb. "
1080+
"Or hide this info with --headless.)"
10621081
)
10631082
sb_config.headless = True
10641083
if not sb_config.headless:
@@ -1212,7 +1231,11 @@ def pytest_runtest_teardown(item):
12121231
except Exception:
12131232
pass
12141233
try:
1215-
if hasattr(self, "headless") and self.headless:
1234+
if hasattr(self, "xvfb") and self.xvfb:
1235+
if self.headless_active and "--pdb" not in sys.argv:
1236+
if hasattr(self, "display") and self.display:
1237+
self.display.stop()
1238+
elif hasattr(self, "headless") and self.headless:
12161239
if self.headless_active and "--pdb" not in sys.argv:
12171240
if hasattr(self, "display") and self.display:
12181241
self.display.stop()

seleniumbase/plugins/selenium_plugin.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ class SeleniumBrowser(Plugin):
2929
--firefox-pref=SET (Set a Firefox preference:value set, comma-separated.)
3030
--extension-zip=ZIP (Load a Chrome Extension .zip|.crx, comma-separated.)
3131
--extension-dir=DIR (Load a Chrome Extension directory, comma-separated.)
32-
--headless (Run tests headlessly. Default mode on Linux OS.)
33-
--headed (Run tests with a GUI on Linux OS.)
32+
--headless (Run tests in headless mode. The default arg on Linux OS.)
33+
--headed (Run tests in headed/GUI mode on Linux OS.)
34+
--xvfb (Run tests using the Xvfb virtual display server on Linux OS.)
3435
--locale=LOCALE_CODE (Set the Language Locale Code for the web browser.)
3536
--interval=SECONDS (The autoplay interval for presentations & tour steps)
3637
--start-page=URL (The starting URL for the web browser when tests begin.)
@@ -273,6 +274,17 @@ def options(self, parser, env):
273274
(The default setting on Linux is headless.)
274275
(The default setting on Mac or Windows is headed.)""",
275276
)
277+
parser.add_option(
278+
"--xvfb",
279+
action="store_true",
280+
dest="xvfb",
281+
default=False,
282+
help="""Using this makes tests run headlessly using Xvfb
283+
instead of the browser's built-in headless mode.
284+
When using "--xvfb", the "--headless" option
285+
will no longer be enabled by default on Linux.
286+
Default: False. (Linux-ONLY!)""",
287+
)
276288
parser.add_option(
277289
"--locale_code",
278290
"--locale-code",
@@ -575,6 +587,7 @@ def beforeTest(self, test):
575587
test.test.cap_string = self.options.cap_string
576588
test.test.headless = self.options.headless
577589
test.test.headed = self.options.headed
590+
test.test.xvfb = self.options.xvfb
578591
test.test.locale_code = self.options.locale_code
579592
test.test.interval = self.options.interval
580593
test.test.start_page = self.options.start_page
@@ -626,12 +639,20 @@ def beforeTest(self, test):
626639
if test.test.servername != "localhost":
627640
# Use Selenium Grid (Use --server="127.0.0.1" for localhost Grid)
628641
test.test.use_grid = True
629-
if "linux" in sys.platform and (
630-
not self.options.headed and not self.options.headless
642+
if self.options.xvfb and "linux" not in sys.platform:
643+
# The Xvfb virtual display server is for Linux OS Only!
644+
self.options.xvfb = False
645+
if (
646+
"linux" in sys.platform
647+
and not self.options.headed
648+
and not self.options.headless
649+
and not self.options.xvfb
631650
):
632651
print(
633-
"(Running with --headless on Linux. "
634-
"Use --headed or --gui to override.)"
652+
"(Linux uses --headless by default. "
653+
"To override, use --headed / --gui. "
654+
"For Xvfb mode instead, use --xvfb. "
655+
"Or hide this info with --headless.)"
635656
)
636657
self.options.headless = True
637658
test.test.headless = True
@@ -669,7 +690,7 @@ def afterTest(self, test):
669690
pass
670691
except Exception:
671692
pass
672-
if self.options.headless:
693+
if self.options.headless or self.options.xvfb:
673694
if self.headless_active:
674695
try:
675696
self.display.stop()

0 commit comments

Comments
 (0)