diff --git a/examples/capabilities/ReadMe.md b/examples/capabilities/ReadMe.md
index a50dacb552e..6f38c96f0b7 100644
--- a/examples/capabilities/ReadMe.md
+++ b/examples/capabilities/ReadMe.md
@@ -1,8 +1,8 @@
-
Using Desired Capabilities
+## [
](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 BrowserStack, Sauce Labs, or another.
+You can specify browser capabilities when running SeleniumBase tests on a remote Selenium Grid server (such as BrowserStack or Sauce Labs).
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.)
@@ -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",
}
```
@@ -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``.)
You can generate specific desired capabilities using:
@@ -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)
@@ -74,8 +90,7 @@ 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
@@ -83,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
diff --git a/examples/capabilities/sample_cap_file_BS.py b/examples/capabilities/sample_cap_file_BS.py
index 50c9773a894..41218235e10 100644
--- a/examples/capabilities/sample_cap_file_BS.py
+++ b/examples/capabilities/sample_cap_file_BS.py
@@ -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",
}
diff --git a/examples/capabilities/sample_cap_file_BS.yml b/examples/capabilities/sample_cap_file_BS.yml
new file mode 100644
index 00000000000..c1b3a9a0edd
--- /dev/null
+++ b/examples/capabilities/sample_cap_file_BS.yml
@@ -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
diff --git a/help_docs/chinese.md b/help_docs/chinese.md
index 45260c6aa58..fa1654bbfbf 100644
--- a/help_docs/chinese.md
+++ b/help_docs/chinese.md
@@ -114,6 +114,7 @@ pytest my_first_test.py --demo
```python
from seleniumbase import BaseCase
+BaseCase.main(__name__, __file__)
class MyTestClass(BaseCase):
def test_swag_labs(self):
@@ -121,20 +122,21 @@ class MyTestClass(BaseCase):
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")
@@ -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="李连杰"]')
```
diff --git a/help_docs/desired_capabilities.md b/help_docs/desired_capabilities.md
index 768db3fd6d0..f7183d6b2d5 100644
--- a/help_docs/desired_capabilities.md
+++ b/help_docs/desired_capabilities.md
@@ -2,7 +2,7 @@
## [
](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 BrowserStack or Sauce Labs.
+You can specify browser capabilities when running SeleniumBase tests on a remote Selenium Grid server (such as BrowserStack or Sauce Labs).
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.)
@@ -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",
}
```
@@ -46,7 +62,7 @@ capabilities = {
You can generate specific desired capabilities using:
@@ -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
diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt
index 56c36af0f86..7921b55a513 100644
--- a/mkdocs_build/requirements.txt
+++ b/mkdocs_build/requirements.txt
@@ -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
@@ -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
diff --git a/requirements.txt b/requirements.txt
index 7504a56e2f1..7329a17ee39 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,7 +3,7 @@ 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"
@@ -11,6 +11,7 @@ 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
@@ -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
@@ -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"
diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py
index fb51e17fd7c..7354291cd07 100755
--- a/seleniumbase/__version__.py
+++ b/seleniumbase/__version__.py
@@ -1,2 +1,2 @@
# seleniumbase package
-__version__ = "4.22.3"
+__version__ = "4.22.4"
diff --git a/seleniumbase/core/capabilities_parser.py b/seleniumbase/core/capabilities_parser.py
index 1f8a124b32c..a1dab1cd248 100644
--- a/seleniumbase/core/capabilities_parser.py
+++ b/seleniumbase/core/capabilities_parser.py
@@ -1,6 +1,7 @@
import re
import ast
import json
+import yaml # Requires pyyaml
def _analyze_ast(contents):
@@ -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
diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py
index f8bc8aefaf7..1c89db100e3 100644
--- a/seleniumbase/fixtures/base_case.py
+++ b/seleniumbase/fixtures/base_case.py
@@ -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 = ""
diff --git a/setup.py b/setup.py
index 286efcaf0bd..1d734c2e784 100755
--- a/setup.py
+++ b/setup.py
@@ -136,7 +136,7 @@
'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"',
@@ -144,6 +144,7 @@
'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',
@@ -169,7 +170,7 @@
'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", # Newer ones had issues
'pytest-metadata==3.0.0',
"pytest-ordering==0.6",
@@ -206,7 +207,7 @@
# Usage: coverage run -m pytest; coverage html; coverage report
"coverage": [
'coverage==7.2.7;python_version<"3.8"',
- 'coverage==7.3.4;python_version>="3.8"',
+ 'coverage==7.4.0;python_version>="3.8"',
'pytest-cov==4.1.0',
],
# pip install -e .[flake8]
@@ -229,7 +230,8 @@
# pip install -e .[pdfminer]
# (An optional library for parsing PDF files.)
"pdfminer": [
- 'pdfminer.six==20221105',
+ 'pdfminer.six==20221105;python_version<"3.8"',
+ 'pdfminer.six==20231228;python_version>="3.8"',
'cryptography==39.0.2;python_version<"3.9"',
'cryptography==41.0.7;python_version>="3.9"',
'cffi==1.15.1;python_version<"3.8"',
@@ -247,6 +249,10 @@
"psutil": [
"psutil==5.9.6",
],
+ # pip install -e .[selenium-stealth]
+ "selenium-stealth": [
+ 'selenium-stealth==1.0.6',
+ ],
# pip install -e .[selenium-wire]
"selenium-wire": [
'selenium-wire==5.1.0',