Skip to content

Add YAML option for capabilities #2405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 31 additions & 16 deletions examples/capabilities/ReadMe.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<!-- SeleniumBase Docs -->

<h3><img src="https://seleniumbase.github.io/img/green_logo.png" title="SeleniumBase" width="32" /> Using Desired Capabilities</h3>
## [<img src="https://seleniumbase.github.io/img/logo6.png" title="SeleniumBase" width="32">](https://github.com/seleniumbase/SeleniumBase/) Using Desired Capabilities

You can specify browser capabilities when running SeleniumBase tests on a remote Selenium Grid server such as <a href="https://www.browserstack.com/automate/capabilities" target="_blank">BrowserStack</a>, <a href="https://saucelabs.com/products/platform-configurator" target="_blank">Sauce Labs</a>, or another.
You can specify browser capabilities when running SeleniumBase tests on a remote Selenium Grid server (such as <a href="https://www.browserstack.com/automate/capabilities" target="_blank">BrowserStack</a> or <a href="https://saucelabs.com/products/platform-configurator" target="_blank">Sauce Labs</a>).

Sample run commands may look like this when run from the [SeleniumBase/examples/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples) folder: (The browser is now specified in the capabilities file.)

Expand All @@ -16,17 +16,33 @@ pytest test_demo_site.py --browser=remote --server=USERNAME:KEY@ondemand.us-east

(Parameters: ``--browser=remote``, ``--server=SERVER``, ``--port=PORT``, ``--protocol=PROTOCOL``, and ``--cap_file=CAP_FILE.py``)

Here's an example desired capabilities file for BrowserStack:
Here's an example desired capabilities file for BrowserStack using the newer SDK format in a `.yml` / `.yaml` file:

```yml
platforms:
- browserName: safari
osVersion: 17
deviceName: iPhone 15 Pro Max
buildIdentifier: ${BUILD_NUMBER}
parallelsPerPlatform: 1
projectName: My Project
browserstackLocal: true
debug: true
networkLogs: true
```

Here's an example desired capabilities file for BrowserStack using the legacy JSONWP format in a `.py` file:

```python
desired_cap = {
"os" : "Windows",
"os_version" : "11",
"browser" : "Chrome",
"browser_version" : "101.0",
"browserstack.local" : "false",
"browserstack.debug" : "true",
"browserstack.selenium_version" : "4.1.2",
"browser": "Chrome",
"os": "Windows",
"os_version": "11",
"browser_version": "latest",
"browserstack.console": "info",
"browserstack.debug": "true",
"browserstack.networkLogs": "true",
"browserstack.local": "true",
}
```

Expand All @@ -41,12 +57,12 @@ capabilities = {
}
```

(Note that the browser is now being specified in the capabilities file, rather than with ``--browser=BROWSER`` when using a **remote** Selenium Grid. If using a **local** Selenium Grid, specify the browser, eg: ``--browser=chrome`` or ``--browser=firefox``.)
(Note that the browser is now being specified in the capabilities file, rather than with ``--BROWSER`` when using a **remote** Selenium Grid. If using a **local** Selenium Grid, specify the browser, eg: ``--firefox``.)

<div><b>You can generate specific desired capabilities using:</b></div>

<ul>
<li><a href="https://www.browserstack.com/automate/capabilities" target="_blank">BrowserStack desired capabilities</a></li>
<li><a href="https://www.browserstack.com/docs/automate/capabilities" target="_blank">BrowserStack desired capabilities</a></li>
<li><a href="https://saucelabs.com/products/platform-configurator" target="_blank">Sauce Labs desired capabilities</a></li>
</ul>

Expand All @@ -65,7 +81,7 @@ caps['KEY'] = False

(Each pair must be on a separate line. You can interchange single and double quotes.)

You can also swap ``--browser=remote`` with an actual browser, eg ``--browser=chrome``, which will combine the default SeleniumBase desired capabilities with those that were specified in the capabilities file when using ``--cap_file=FILE.py``. Capabilities will override other parameters, so if you set the browser to one thing and the capabilities browser to another, SeleniumBase will use the capabilities browser as the browser.
You can also swap ``--browser=remote`` with an actual browser, eg ``--browser=chrome``, which will combine the default SeleniumBase desired capabilities with those that were specified in the capabilities file when using ``--cap_file=FILE.py``. Capabilities will override other parameters, so if you set the browser to one thing and the capabilities browser to another, SeleniumBase will use the capabilities browser.

You'll need default SeleniumBase capabilities for:
* Using a proxy server (not the same as a Selenium Grid server)
Expand All @@ -74,16 +90,15 @@ You'll need default SeleniumBase capabilities for:
* Overriding a website's Content Security Policy on Chrome
* Other possible reasons

You can also set browser desired capabilities from a command line string:
Example:
You can also set browser desired capabilities from a command-line string. Eg:

```bash
pytest test_swag_labs.py --cap-string='{"browserName":"chrome","name":"test1"}' --server="127.0.0.1" --browser=remote
```

(Enclose cap-string in single quotes. Enclose parameter keys in double quotes.)

If you pass ``"*"`` into the ``"name"`` field of ``--cap-string``, the name will become the test identifier. Example:
If you pass ``"*"`` into the ``"name"`` field of ``--cap-string``, the name will become the test identifier. Eg:

```bash
pytest my_first_test.py --cap-string='{"browserName":"chrome","name":"*"}' --server="127.0.0.1" --browser=chrome
Expand Down
13 changes: 7 additions & 6 deletions examples/capabilities/sample_cap_file_BS.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Desired capabilities example file for BrowserStack
# Generate from https://www.browserstack.com/automate/capabilities
# Desired capabilities example .py file for BrowserStack:
# https://www.browserstack.com/docs/automate/capabilities
desired_cap = {
"browser": "Chrome",
"os": "Windows",
"os_version": "11",
"browser": "Chrome",
"browser_version": "101.0",
"browserstack.local": "false",
"browser_version": "latest",
"browserstack.console": "info",
"browserstack.debug": "true",
"browserstack.selenium_version": "4.1.2",
"browserstack.networkLogs": "true",
"browserstack.local": "true",
}
12 changes: 12 additions & 0 deletions examples/capabilities/sample_cap_file_BS.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Desired capabilities example YML file for BrowserStack:
# https://www.browserstack.com/docs/automate/capabilities
platforms:
- browserName: safari
osVersion: 17
deviceName: iPhone 15 Pro Max
buildIdentifier: ${BUILD_NUMBER}
parallelsPerPlatform: 1
projectName: My Project
browserstackLocal: true
debug: true
networkLogs: true
31 changes: 19 additions & 12 deletions help_docs/chinese.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,27 +114,29 @@ pytest my_first_test.py --demo

```python
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__)

class MyTestClass(BaseCase):
def test_swag_labs(self):
self.open("https://www.saucedemo.com")
self.type("#user-name", "standard_user")
self.type("#password", "secret_sauce\n")
self.assert_element("div.inventory_list")
self.assert_text("PRODUCTS", "span.title")
self.assert_exact_text("Products", "span.title")
self.click('button[name*="backpack"]')
self.click("#shopping_cart_container a")
self.assert_text("YOUR CART", "span.title")
self.assert_exact_text("Your Cart", "span.title")
self.assert_text("Backpack", "div.cart_item")
self.click("button#checkout")
self.type("#first-name", "SeleniumBase")
self.type("#last-name", "Automation")
self.type("#postal-code", "77123")
self.click("input#continue")
self.assert_text("CHECKOUT: OVERVIEW")
self.assert_text("Checkout: Overview")
self.assert_text("Backpack", "div.cart_item")
self.assert_text("29.99", "div.inventory_item_price")
self.click("button#finish")
self.assert_exact_text("THANK YOU FOR YOUR ORDER", "h2")
self.assert_exact_text("Thank you for your order!", "h2")
self.assert_element('img[alt="Pony Express"]')
self.js_click("a#logout_sidebar_link")
self.assert_element("div#login_button_container")
Expand Down Expand Up @@ -173,23 +175,28 @@ self.save_screenshot(FILE_NAME) # 保存当前页面的截图

```python
from seleniumbase.translate.chinese import 硒测试用例
硒测试用例.main(__name__, __file__)

class 我的测试类(硒测试用例):
def test_例子1(self):
self.开启("https://zh.wikipedia.org/wiki/")
self.断言标题("维基百科,自由的百科全书")
self.断言元素('a[title="首页"]')
self.断言元素('a[title="Wikipedia:关于"]')
self.断言元素('span:contains("创建账号")')
self.断言元素('span:contains("登录")')
self.断言文本("新闻动态", "span#新闻动态")
self.输入文本("#searchInput", "舞龍")
self.单击("#searchButton")
self.输入文本('input[name="search"]', "舞龍")
self.单击('button:contains("搜索")')
self.断言文本("舞龍", "#firstHeading")
self.断言元素('img[src*="Chinese_draak.jpg"]')
self.输入文本("#searchInput", "麻婆豆腐")
self.单击("#searchButton")
self.回去()
self.输入文本('input[name="search"]', "麻婆豆腐")
self.单击('button:contains("搜索")')
self.断言文本("麻婆豆腐", "#firstHeading")
self.断言元素('div.thumb div:contains("一家中餐館的麻婆豆腐")')
self.输入文本("#searchInput", "精武英雄")
self.单击("#searchButton")
self.断言元素('figure:contains("一家中餐館的麻婆豆腐")')
self.回去()
self.输入文本('input[name="search"]', "精武英雄")
self.单击('button:contains("搜索")')
self.断言元素('img[src*="Fist_of_legend.jpg"]')
self.断言文本("李连杰", 'li a[title="李连杰"]')
```
Expand Down
38 changes: 27 additions & 11 deletions help_docs/desired_capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## [<img src="https://seleniumbase.github.io/img/logo6.png" title="SeleniumBase" width="32">](https://github.com/seleniumbase/SeleniumBase/) Using Desired Capabilities

You can specify browser capabilities when running SeleniumBase tests on a remote Selenium Grid server such as <a href="https://www.browserstack.com/automate/capabilities" target="_blank">BrowserStack</a> or <a href="https://saucelabs.com/products/platform-configurator" target="_blank">Sauce Labs</a>.
You can specify browser capabilities when running SeleniumBase tests on a remote Selenium Grid server (such as <a href="https://www.browserstack.com/automate/capabilities" target="_blank">BrowserStack</a> or <a href="https://saucelabs.com/products/platform-configurator" target="_blank">Sauce Labs</a>).

Sample run commands may look like this when run from the [SeleniumBase/examples/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples) folder: (The browser is now specified in the capabilities file.)

Expand All @@ -16,17 +16,33 @@ pytest test_demo_site.py --browser=remote --server=USERNAME:KEY@ondemand.us-east

(Parameters: ``--browser=remote``, ``--server=SERVER``, ``--port=PORT``, and ``--cap_file=CAP_FILE.py``)

Here's an example desired capabilities file for BrowserStack:
Here's an example desired capabilities file for BrowserStack using the newer SDK format in a `.yml` / `.yaml` file:

```yml
platforms:
- browserName: safari
osVersion: 17
deviceName: iPhone 15 Pro Max
buildIdentifier: ${BUILD_NUMBER}
parallelsPerPlatform: 1
projectName: My Project
browserstackLocal: true
debug: true
networkLogs: true
```

Here's an example desired capabilities file for BrowserStack using the legacy JSONWP format in a `.py` file:

```python
desired_cap = {
"os" : "Windows",
"os_version" : "11",
"browser" : "Chrome",
"browser_version" : "101.0",
"browserstack.local" : "false",
"browserstack.debug" : "true",
"browserstack.selenium_version" : "4.1.2",
"browser": "Chrome",
"os": "Windows",
"os_version": "11",
"browser_version": "latest",
"browserstack.console": "info",
"browserstack.debug": "true",
"browserstack.networkLogs": "true",
"browserstack.local": "true",
}
```

Expand All @@ -46,7 +62,7 @@ capabilities = {
<div><b>You can generate specific desired capabilities using:</b></div>

<ul>
<li><a href="https://www.browserstack.com/automate/capabilities" target="_blank">BrowserStack desired capabilities</a></li>
<li><a href="https://www.browserstack.com/docs/automate/capabilities" target="_blank">BrowserStack desired capabilities</a></li>
<li><a href="https://saucelabs.com/products/platform-configurator" target="_blank">Sauce Labs desired capabilities</a></li>
</ul>

Expand Down Expand Up @@ -82,7 +98,7 @@ pytest test_swag_labs.py --cap-string='{"browserName":"chrome","name":"test1"}'

(Enclose cap-string in single quotes. Enclose parameter keys in double quotes.)

If you pass ``"*"`` into the ``"name"`` field of ``--cap-string``, the name will become the test identifier. Example:
If you pass ``"*"`` into the ``"name"`` field of ``--cap-string``, the name will become the test identifier. Eg:

```bash
pytest my_first_test.py --cap-string='{"browserName":"chrome","name":"*"}' --server="127.0.0.1" --browser=chrome
Expand Down
9 changes: 4 additions & 5 deletions mkdocs_build/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# mkdocs dependencies for generating the seleniumbase.io website
# Minimum Python version: 3.8 (for generating docs only)

regex>=2023.10.3
PyYAML>=6.0.1
pymdown-extensions>=10.5
regex>=2023.12.25
pymdown-extensions>=10.7
pipdeptree>=2.13.1
python-dateutil>=2.8.2
Markdown==3.5.1
Expand All @@ -17,11 +16,11 @@ cairocffi==1.6.1
pathspec==0.12.1
Babel==2.14.0
paginate==0.5.6
lxml==4.9.4
lxml==5.0.0
pyquery==2.0.0
readtime==3.0.0
mkdocs==1.5.3
mkdocs-material==9.5.2
mkdocs-material==9.5.3
mkdocs-exclude-search==0.6.6
mkdocs-simple-hooks==0.1.5
mkdocs-material-extensions==1.3.1
7 changes: 4 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ packaging>=23.2
setuptools>=68.0.0;python_version<"3.8"
setuptools>=69.0.3;python_version>="3.8"
wheel>=0.42.0
attrs>=23.1.0
attrs>=23.2.0
certifi>=2023.11.17
filelock>=3.12.2;python_version<"3.8"
filelock>=3.13.1;python_version>="3.8"
platformdirs>=4.0.0;python_version<"3.8"
platformdirs>=4.1.0;python_version>="3.8"
parse>=1.20.0
parse-type>=0.6.2
pyyaml>=6.0.1
six==1.16.0
idna==3.6
chardet==5.2.0
Expand All @@ -36,7 +37,7 @@ iniconfig==2.0.0
pluggy==1.2.0;python_version<"3.8"
pluggy==1.3.0;python_version>="3.8"
py==1.11.0
pytest==7.4.3
pytest==7.4.4
pytest-html==2.0.1
pytest-metadata==3.0.0
pytest-ordering==0.6
Expand Down Expand Up @@ -65,7 +66,7 @@ rich==13.7.0

coverage==6.2;python_version<"3.7"
coverage==7.2.7;python_version>="3.7" and python_version<"3.8"
coverage==7.3.4;python_version>="3.8"
coverage==7.4.0;python_version>="3.8"
pytest-cov==4.0.0;python_version<"3.7"
pytest-cov==4.1.0;python_version>="3.7"
flake8==5.0.4;python_version<"3.9"
Expand Down
2 changes: 1 addition & 1 deletion seleniumbase/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# seleniumbase package
__version__ = "4.22.3"
__version__ = "4.22.4"
18 changes: 12 additions & 6 deletions seleniumbase/core/capabilities_parser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import re
import ast
import json
import yaml # Requires pyyaml


def _analyze_ast(contents):
Expand Down Expand Up @@ -183,28 +184,33 @@ def _read_file(file):
def _parse_py_file(cap_file):
all_code = _read_file(cap_file)
capabilities = _analyze_ast(all_code)

if not capabilities:
capabilities = _analyze_manual(all_code)

return capabilities


def _parse_json_file(cap_file):
all_code = _read_file(cap_file)

return json.loads(all_code)


def _parse_yaml_file(cap_file):
all_code = _read_file(cap_file)
return yaml.safe_load(all_code)


def get_desired_capabilities(cap_file):
if cap_file.endswith(".py"):
capabilities = _parse_py_file(cap_file)
elif cap_file.endswith(".json"):
capabilities = _parse_json_file(cap_file)
elif (cap_file.endswith(".yml") or cap_file.endswith(".yaml")):
capabilities = _parse_yaml_file(cap_file)
else:
raise Exception("\n\n`%s` is not a Python or JSON file!\n" % cap_file)

raise Exception(
'\n\n`%s` must end in ".py", ".json", ".yml", or ".yaml"!\n'
% cap_file
)
if len(capabilities.keys()) == 0:
raise Exception("Unable to parse desired capabilities file!")

return capabilities
7 changes: 6 additions & 1 deletion seleniumbase/fixtures/base_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -6650,7 +6650,12 @@ def get_pdf_text(
try:
from pdfminer.high_level import extract_text
except Exception:
shared_utils.pip_install("pdfminer.six")
if not sys.version_info >= (3, 8):
shared_utils.pip_install(
"pdfminer.six", version="20221105"
)
else:
shared_utils.pip_install("pdfminer.six")
from pdfminer.high_level import extract_text
if not password:
password = ""
Expand Down
Loading