Skip to content

Commit 68479ff

Browse files
authored
Browserstack little improvements and Edge fix about options (#260)
* Fix settings of Edge capabilities KEY attribute does not exist in Edge options before selenium 4.X. see https://github.com/SeleniumHQ/selenium/blob/selenium-3.141.0/py/selenium/webdriver/edge/options.py * Update browserstack URL about API endpoint * Add ability to display public URL about browserstack report For several organizations it is useful to access to the browserstack report without any authentication.
1 parent 5c5be0e commit 68479ff

File tree

6 files changed

+78
-9
lines changed

6 files changed

+78
-9
lines changed

docs/user_guide.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,24 @@ See the
378378
for additional configuration that can be set using ``--capability`` command line
379379
arguments.
380380

381+
Test result links
382+
~~~~~~~~~~~~~~~~~
383+
384+
By default, links to BrowserStack jobs are only visible to users logged in to the account
385+
that ran the job. You can choose to display a public URL in the pytest summary.
386+
387+
This can be configured by setting the ``BROWSERSTACK_JOB_ACCESS`` environment variable or by
388+
adding ``report`` section in ``.browserstack`` configuration file.
389+
Allowed values are ``browser_url`` for private access and ``public_url`` for everyone.
390+
391+
An example using a configuration file:
392+
393+
.. code-block:: ini
394+
395+
[report]
396+
job_access = browser_url
397+
398+
381399
TestingBot
382400
----------
383401

pytest_selenium/drivers/browserstack.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
import pytest
66

77
from pytest_selenium.drivers.cloud import Provider
8+
from pytest_selenium.exceptions import MissingCloudSettingError
89

910

1011
class BrowserStack(Provider):
1112

12-
API = "https://www.browserstack.com/automate/sessions/{session}.json"
13+
API = "https://api.browserstack.com/automate/sessions/{session}.json"
1314

1415
@property
1516
def auth(self):
@@ -31,6 +32,21 @@ def key(self):
3132
"key", ["BROWSERSTACK_ACCESS_KEY", "BROWSERSTACK_PSW"]
3233
)
3334

35+
@property
36+
def job_access(self):
37+
"""Get job url field, private(required authentication) or public."""
38+
try:
39+
field = self.get_setting(
40+
key="job_access",
41+
envs=["BROWSERSTACK_JOB_ACCESS"],
42+
section="report",
43+
allowed_values=["browser_url", "public_url"],
44+
)
45+
except MissingCloudSettingError:
46+
field = "browser_url"
47+
48+
return field
49+
3450

3551
@pytest.mark.optionalhook
3652
def pytest_selenium_runtest_makereport(item, report, summary, extra):
@@ -47,7 +63,7 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
4763

4864
try:
4965
job_info = requests.get(api_url, auth=provider.auth, timeout=10).json()
50-
job_url = job_info["automation_session"]["browser_url"]
66+
job_url = job_info["automation_session"][provider.job_access]
5167
# Add the job URL to the summary
5268
summary.append("{0} Job: {1}".format(provider.name, job_url))
5369
pytest_html = item.config.pluginmanager.getplugin("html")
@@ -79,6 +95,7 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
7995

8096
def driver_kwargs(request, test, capabilities, **kwargs):
8197
provider = BrowserStack()
98+
assert provider.job_access
8299
capabilities.setdefault("name", test)
83100
capabilities.setdefault("browserstack.user", provider.username)
84101
capabilities.setdefault("browserstack.key", provider.key)

pytest_selenium/drivers/cloud.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
import os
66
import configparser
77

8-
from pytest_selenium.exceptions import MissingCloudCredentialError
8+
from pytest_selenium.exceptions import (
9+
MissingCloudCredentialError,
10+
MissingCloudSettingError,
11+
InvalidCloudSettingError,
12+
)
913

1014

1115
class Provider(object):
@@ -22,13 +26,25 @@ def config(self):
2226

2327
def get_credential(self, key, envs):
2428
try:
25-
return self.config.get("credentials", key)
29+
return self.get_setting(key, envs, "credentials")
30+
except MissingCloudSettingError:
31+
raise MissingCloudCredentialError(self.name, key, envs)
32+
33+
def get_setting(self, key, envs, section, allowed_values=None):
34+
try:
35+
value = self.config.get(section, key)
2636
except (configparser.NoSectionError, configparser.NoOptionError, KeyError):
2737
for env in envs:
2838
value = os.getenv(env)
2939
if value:
30-
return value
31-
raise MissingCloudCredentialError(self.name, key, envs)
40+
break
41+
42+
if value is None:
43+
raise MissingCloudSettingError(self.name, key, envs)
44+
if allowed_values and value not in allowed_values:
45+
raise InvalidCloudSettingError(self.name, key, value)
46+
47+
return value
3248

3349
def uses_driver(self, driver):
3450
return driver.lower() == self.name.lower()

pytest_selenium/exceptions.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,22 @@
55
import pytest
66

77

8-
class MissingCloudCredentialError(pytest.UsageError):
8+
class MissingCloudSettingError(pytest.UsageError):
99
def __init__(self, driver, key, envs):
10-
super(MissingCloudCredentialError, self).__init__(
10+
super(MissingCloudSettingError, self).__init__(
1111
"{0} {1} must be set. Try setting one of the following "
1212
"environment variables {2}, or see the documentation for "
1313
"how to use a configuration file.".format(driver, key, envs)
1414
)
15+
16+
17+
class MissingCloudCredentialError(MissingCloudSettingError):
18+
pass
19+
20+
21+
class InvalidCloudSettingError(pytest.UsageError):
22+
def __init__(self, driver, key, value):
23+
super(InvalidCloudSettingError, self).__init__(
24+
"{0} {1} invalid value `{2}`, see the documentation for how "
25+
"to use this parameter.".format(driver, key, value)
26+
)

pytest_selenium/pytest_selenium.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def capabilities(
112112
key = firefox_options.KEY
113113
options = firefox_options.to_capabilities()
114114
elif browser == "EDGE":
115-
key = edge_options.KEY
115+
key = getattr(edge_options, "KEY", None)
116116
options = edge_options.to_capabilities()
117117
if all([key, options]):
118118
capabilities[key] = _merge(capabilities.get(key, {}), options.get(key, {}))

testing/test_browserstack.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,9 @@ def test_invalid_credentials_file(failure, monkeypatch, tmpdir):
8080
out = failure()
8181
messages = ["Invalid username or password", "basic auth failed"]
8282
assert any(message in out for message in messages)
83+
84+
85+
def test_invalid_job_access_value(failure, monkeypatch, tmpdir):
86+
monkeypatch.setattr(os.path, "expanduser", lambda p: str(tmpdir))
87+
tmpdir.join(".browserstack").write("[report]\njob_access=foo")
88+
assert "BrowserStack job_access invalid value `foo`" in failure()

0 commit comments

Comments
 (0)