Skip to content

Commit 3e7fdbd

Browse files
authored
Firefox profile parsing (robotframework#1439)
Fixes robotframework#1332
1 parent d72372b commit 3e7fdbd

File tree

4 files changed

+101
-7
lines changed

4 files changed

+101
-7
lines changed

src/SeleniumLibrary/keywords/browsermanagement.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,12 @@ def open_browser(self, url, browser='firefox', alias=None,
117117
uses. Notice that prior to SeleniumLibrary 3.0, the library
118118
contained its own profile that was used by default. The
119119
``ff_profile_dir`` can also be instance of the
120-
[https://seleniumhq.github.io/selenium/docs/api/py/webdriver_firefox/selenium.webdriver.firefox.firefox_profile.html?highlight=firefoxprofile#selenium.webdriver.firefox.firefox_profile.FirefoxProfile|selenium.webdriver.FirefoxProfile].
120+
[https://seleniumhq.github.io/selenium/docs/api/py/webdriver_firefox/selenium.webdriver.firefox.firefox_profile.html|selenium.webdriver.FirefoxProfile]
121+
. As third option, it possible to use `FirefoxProfile` methods
122+
and attributes to define the profile. Using method and attributes
123+
in same way as with ``options`` argument. Example it is possible
124+
to use FirefoxProfile `set_preference` to define different
125+
profile settings.
121126
122127
Optional ``options`` argument allows to define browser specific
123128
Selenium options. Example for Chrome, the ``options`` argument
@@ -210,9 +215,14 @@ def open_browser(self, url, browser='firefox', alias=None,
210215
Example when using
211216
[https://seleniumhq.github.io/selenium/docs/api/py/webdriver_chrome/selenium.webdriver.chrome.options.html#selenium.webdriver.chrome.options.Options|Chrome options]
212217
method:
213-
| `Open Browser` | http://example.com | Chrome | options=add_argument("--disable-popup-blocking"); add_argument("--ignore-certificate-errors") | # Sting format |
214-
| ${options} = | Get Options | | | # Selenium options instance |
215-
| `Open Browser` | http://example.com | Chrome | options=${options} | |
218+
| `Open Browser` | http://example.com | Chrome | options=add_argument("--disable-popup-blocking"); add_argument("--ignore-certificate-errors") | # Sting format |
219+
| ${options} = | Get Options | | | # Selenium options instance |
220+
| `Open Browser` | http://example.com | Chrome | options=${options} | |
221+
222+
Example for FirefoxProfile
223+
| `Open Browser` | http://example.com | Firefox | ff_profile_dir=/path/to/profile | # Using profile from disk |
224+
| `Open Browser` | http://example.com | Firefox | ff_profile_dir=${FirefoxProfile_instance} | # Using instance of FirefoxProfile |
225+
| `Open Browser` | http://example.com | Firefox | ff_profile_dir=set_preference("key", "value");set_preference("other", "setting") | # Defining profile using FirefoxProfile mehtods |
216226
217227
If the provided configuration options are not enough, it is possible
218228
to use `Create Webdriver` to customize browser initialization even
@@ -225,7 +235,8 @@ def open_browser(self, url, browser='firefox', alias=None,
225235
in SeleniumLibrary 4.0. The ``options`` and ``service_log_path``
226236
are new in SeleniumLibrary 4.0. Support for ``ff_profile_dir``
227237
accepting instance of the `selenium.webdriver.FirefoxProfile`
228-
is new in SeleniumLibrary 4.0.
238+
and support defining FirefoxProfile with methods and
239+
attributes are new in SeleniumLibrary 4.0.
229240
"""
230241
index = self.drivers.get_index(alias)
231242
if index:

src/SeleniumLibrary/keywords/webdrivertools/webdrivertools.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
from selenium import webdriver
2727
from selenium.webdriver import FirefoxProfile
2828

29-
from SeleniumLibrary.utils import is_falsy, is_truthy, is_noney, is_string
29+
from SeleniumLibrary.utils import is_falsy, is_truthy, is_noney, is_string, PY3
3030
from SeleniumLibrary.keywords.webdrivertools.sl_file_detector import SelLibLocalFileDetector
31+
if not PY3:
32+
FileNotFoundError = object
3133

3234

3335
class WebDriverCreator(object):
@@ -140,7 +142,19 @@ def _get_ff_profile(self, ff_profile_dir):
140142
return ff_profile_dir
141143
if is_falsy(ff_profile_dir):
142144
return webdriver.FirefoxProfile()
143-
return webdriver.FirefoxProfile(ff_profile_dir)
145+
try:
146+
return webdriver.FirefoxProfile(ff_profile_dir)
147+
except (OSError, FileNotFoundError):
148+
ff_options = self.selenium_options._parse(ff_profile_dir)
149+
ff_profile = webdriver.FirefoxProfile()
150+
for option in ff_options:
151+
for key in option:
152+
attr = getattr(ff_profile, key)
153+
if callable(attr):
154+
attr(*option[key])
155+
else:
156+
setattr(ff_profile, key, *option[key])
157+
return ff_profile
144158

145159
@property
146160
def _geckodriver_log(self):
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Firefox profile parsing
2+
3+
0) key1 arg1
4+
1) key1 arg1
5+
2) key1 arg1 key2 arg2
6+
3) True
7+
4) 'FirefoxProfile' object has no attribute 'wrong_name'
8+
5) 'str' object has no attribute 'proxy_type'
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import os
2+
import unittest
3+
4+
import selenium
5+
from robot.utils import JYTHON
6+
from selenium import webdriver
7+
try:
8+
from approvaltests.approvals import verify_all
9+
from approvaltests.reporters.generic_diff_reporter_factory import GenericDiffReporterFactory
10+
except ImportError:
11+
if JYTHON:
12+
verify = None
13+
GenericDiffReporterFactory = None
14+
else:
15+
raise
16+
17+
from SeleniumLibrary.keywords import WebDriverCreator
18+
19+
20+
class FireFoxProfileParsingTests(unittest.TestCase):
21+
22+
@classmethod
23+
def setUpClass(cls):
24+
cls.log_dir = '/log/dir'
25+
cls.creator = WebDriverCreator(cls.log_dir)
26+
path = os.path.dirname(__file__)
27+
if not JYTHON:
28+
reporter_json = os.path.abspath(os.path.join(path, '..', 'approvals_reporters.json'))
29+
factory = GenericDiffReporterFactory()
30+
factory.load(reporter_json)
31+
cls.reporter = factory.get_first_working()
32+
33+
def setUp(self):
34+
self.results = []
35+
36+
@unittest.skipIf(JYTHON, 'ApprovalTest does not work with Jython')
37+
def test_single_method(self):
38+
self._parse_result(self.creator._get_ff_profile('set_preference("key1", "arg1")'))
39+
self._parse_result(
40+
self.creator._get_ff_profile('set_preference("key1", "arg1");set_preference("key1", "arg1")'))
41+
self._parse_result(
42+
self.creator._get_ff_profile('set_preference("key1", "arg1") ; set_preference("key2", "arg2")'))
43+
profile = self.creator._get_ff_profile('update_preferences()')
44+
self.results.append(isinstance(profile, webdriver.FirefoxProfile))
45+
try:
46+
self.creator._get_ff_profile('wrong_name("key1", "arg1")')
47+
except AttributeError as error:
48+
self.results.append(error)
49+
try:
50+
self.creator._get_ff_profile('set_proxy("foo")')
51+
except Exception as error:
52+
self.results.append(str(error))
53+
verify_all('Firefox profile parsing', self.results, reporter=self.reporter)
54+
55+
def _parse_result(self, result):
56+
to_str = ''
57+
if 'key1' in result.default_preferences:
58+
to_str = '%s %s %s' % (to_str, 'key1', result.default_preferences['key1'])
59+
if 'key2' in result.default_preferences:
60+
to_str = '%s %s %s' % (to_str, 'key2', result.default_preferences['key2'])
61+
self.results.append(to_str)

0 commit comments

Comments
 (0)