Merge pull request #1548 from seleniumbase/context-managers-and-more
Context Managers and more
This commit is contained in:
commit
c406380b6e
|
@ -22,9 +22,9 @@ jobs:
|
|||
python-version: ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v1
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
|
|
67
README.md
67
README.md
|
@ -3,11 +3,11 @@
|
|||
<meta property="og:description" content="Fast, easy, and reliable Web/UI testing with Python." />
|
||||
<meta property="og:keywords" content="Python, pytest, selenium, webdriver, testing, automation, seleniumbase, framework, RPA, behave, BDD, nosetests, dashboard, recorder, reports, gui, screenshots">
|
||||
<meta property="og:image" content="https://seleniumbase.github.io/cdn/img/mac_sb_logo_5b.png" />
|
||||
<link rel="icon" href="https://seleniumbase.github.io/img/green_logo2.png" />
|
||||
<link rel="icon" href="https://seleniumbase.github.io/img/logo3b.png" />
|
||||
|
||||
<p align="center"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.github.io/cdn/img/sb_logo_gs.png" alt="SeleniumBase" title="SeleniumBase" width="450" /></a></p>
|
||||
<p align="center"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.github.io/cdn/img/sb_media_logo_t4.png" alt="SeleniumBase" title="SeleniumBase" width="408" /></a></p>
|
||||
|
||||
<p align="center"><b>SeleniumBase</b> simplifies <a href="https://www.selenium.dev/documentation/webdriver/" target="_blank">WebDriver</a> automation with <a href="https://docs.pytest.org/en/latest/how-to/usage.html" target="_blank">pytest</a>.</p>
|
||||
<p align="center"><b>SeleniumBase</b> simplifies <a href="https://www.selenium.dev/documentation/webdriver/" target="_blank">WebDriver</a> automation with <b>Python</b>.</p>
|
||||
|
||||
<p align="center"><a href="https://pypi.python.org/pypi/seleniumbase" target="_blank"><img src="https://img.shields.io/pypi/v/seleniumbase.svg?color=3399EE" alt="PyPI version" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/releases" target="_blank"><img src="https://img.shields.io/github/v/release/seleniumbase/SeleniumBase.svg?color=22AAEE" alt="GitHub version" /></a> <a href="https://seleniumbase.io"><img src="https://img.shields.io/badge/docs-seleniumbase.io-11BBAA.svg" alt="SeleniumBase Docs" /></a> <a href="https://github.com/seleniumbase/SeleniumBase/actions" target="_blank"><img src="https://github.com/seleniumbase/SeleniumBase/workflows/CI%20build/badge.svg" alt="SeleniumBase GitHub Actions" /></a> <a href="https://gitter.im/seleniumbase/SeleniumBase" target="_blank"><img src="https://badges.gitter.im/seleniumbase/SeleniumBase.svg" alt="SeleniumBase" /></a></p>
|
||||
|
||||
|
@ -123,7 +123,7 @@ pytest test_swag_labs.py --demo
|
|||
|
||||
<h4>Here are a few scripts to test that app with SeleniumBase:</h4>
|
||||
|
||||
<p align="left">📘📝 An example test with the <b>BaseCase</b> class. Runs with <code>pytest</code> or <code>nosetests</code>. (<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/ReadMe.md">Learn more</a>)</p>
|
||||
<p align="left">📘📝 An example test with the <b>BaseCase</b> class. Runs with <b><a href="https://docs.pytest.org/en/latest/how-to/usage.html">pytest</a></b> or <b>nosetests</b>. (<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/ReadMe.md">Learn more</a>)</p>
|
||||
|
||||
```python
|
||||
from seleniumbase import BaseCase
|
||||
|
@ -140,7 +140,7 @@ class TestMFALogin(BaseCase):
|
|||
self.save_screenshot_to_logs()
|
||||
```
|
||||
|
||||
<p align="left">📗📝 An example test with the <b>sb</b> <code>pytest</code> fixture. Runs with <code>pytest</code>.</p>
|
||||
<p align="left">📗📝 An example test with the <b><code>sb</code></b> <code>pytest</code> fixture. Runs with <b><a href="https://docs.pytest.org/en/latest/how-to/usage.html">pytest</a></b>.</p>
|
||||
|
||||
```python
|
||||
def test_mfa_login(sb):
|
||||
|
@ -154,7 +154,25 @@ def test_mfa_login(sb):
|
|||
sb.save_screenshot_to_logs()
|
||||
```
|
||||
|
||||
<p align="left">📕📝 An example test with <b>behave-BDD</b> <a href="https://behave.readthedocs.io/en/stable/gherkin.html" target="_blank">Gherkin</a> structure. Runs with <code>behave</code>. (<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/behave_bdd/ReadMe.md">Learn more</a>)</p>
|
||||
<p align="left">📙📝 An example test with the <b><code>SB</code></b> Context Manager. Runs with pure <b><code>python</code></b>.</p>
|
||||
|
||||
```python
|
||||
from seleniumbase import SB
|
||||
|
||||
with SB() as sb: # By default, browser="chrome" if not set.
|
||||
sb.open("https://seleniumbase.github.io/realworld/login")
|
||||
sb.type("#username", "demo_user")
|
||||
sb.type("#password", "secret_pass")
|
||||
sb.enter_mfa_code("#totpcode", "GAXG2MTEOR3DMMDG") # 6-digit
|
||||
sb.assert_text("Welcome!", "h1")
|
||||
sb.highlight("img#image1") # A fancier assert_element() call
|
||||
sb.click('a:contains("This Page")') # Use :contains() on any tag
|
||||
sb.click_link("Sign out") # Link must be "a" tag. Not "button".
|
||||
sb.assert_element('a:contains("Sign in")')
|
||||
sb.assert_exact_text("You have been signed out!", "#top_message")
|
||||
```
|
||||
|
||||
<p align="left">📕📝 An example test with <b>behave-BDD</b> <a href="https://behave.readthedocs.io/en/stable/gherkin.html" target="_blank">Gherkin</a> structure. Runs with <b><code>behave</code></b>. (<a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/behave_bdd/ReadMe.md">Learn more</a>)</p>
|
||||
|
||||
```gherkin
|
||||
Feature: SeleniumBase scenarios for the RealWorld App
|
||||
|
@ -178,7 +196,7 @@ Feature: SeleniumBase scenarios for the RealWorld App
|
|||
🔵 Using a <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/virtualenv_instructions.md">Python virtual env</a> is recommended.
|
||||
|
||||
<a id="install_seleniumbase"></a>
|
||||
<h2><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Install SeleniumBase:</h2>
|
||||
<h2><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Install SeleniumBase:</h2>
|
||||
|
||||
**You can install ``seleniumbase`` from [GitHub](https://github.com/seleniumbase/SeleniumBase) or [PyPI](https://pypi.org/project/seleniumbase/):**
|
||||
|
||||
|
@ -261,7 +279,7 @@ COMMANDS:
|
|||
```
|
||||
|
||||
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Downloading web drivers:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Downloading web drivers:</h3>
|
||||
|
||||
✅ SeleniumBase automatically downloads web drivers as needed, such as ``chromedriver`` and ``geckodriver`` (Firefox).
|
||||
|
||||
|
@ -269,7 +287,7 @@ COMMANDS:
|
|||
|
||||
|
||||
<a id="basic_example_and_usage"></a>
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Basic Example & Usage:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Basic Example & Usage:</h3>
|
||||
|
||||
🔵 If you've cloned SeleniumBase, you can run tests from the [examples/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples) folder.
|
||||
|
||||
|
@ -320,7 +338,7 @@ class MyTestClass(BaseCase):
|
|||
|
||||
|
||||
<a id="common_methods"></a>
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Here are some common SeleniumBase methods that you might find in tests:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Here are some common SeleniumBase methods that you might find in tests:</h3>
|
||||
|
||||
```python
|
||||
self.open(url) # Navigate the browser window to the URL.
|
||||
|
@ -361,7 +379,7 @@ self.assert_no_js_errors() # Verify there are no JS errors.
|
|||
|
||||
|
||||
<a id="fun_facts"></a>
|
||||
<h2><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Fun Facts / Learn More:</h2>
|
||||
<h2><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Fun Facts / Learn More:</h2>
|
||||
|
||||
<p>✅ SeleniumBase automatically handles common WebDriver actions such as launching web browsers before tests, saving screenshots during failures, and closing web browsers after tests.</p>
|
||||
|
||||
|
@ -418,7 +436,7 @@ nosetests [FILE_NAME.py]:[CLASS_NAME].[METHOD_NAME]
|
|||
|
||||
|
||||
<a id="detailed_instructions"></a>
|
||||
<h2><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Detailed Instructions:</h2>
|
||||
<h2><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Detailed Instructions:</h2>
|
||||
|
||||
<a id="seleniumbase_demo_mode"></a>
|
||||
🔵 <b>Demo Mode</b> helps you see what a test is doing. If a test is moving too fast for your eyes, run it in <b>Demo Mode</b>, which pauses the browser briefly between actions, highlights page elements being acted on, and displays assertions:
|
||||
|
@ -528,7 +546,8 @@ pytest my_first_test.py --pdb
|
|||
--enable-ws # (Enable Web Security on Chromium-based browsers.)
|
||||
--enable-sync # (Enable "Chrome Sync" on websites.)
|
||||
--use-auto-ext # (Use Chrome's automation extension.)
|
||||
--undetected | --uc # (Use undetected-chromedriver to evade bot-detection.)
|
||||
--uc | --undetected # (Use undetected-chromedriver to evade bot-detection.)
|
||||
--uc-sub | --uc-subprocess # (Use undetected-chromedriver as a subprocess.)
|
||||
--remote-debug # (Enable Chrome's Remote Debugger on http://localhost:9222)
|
||||
--final-debug # (Enter Debug Mode after each test ends. Don't use with CI!)
|
||||
--dashboard # (Enable the SeleniumBase Dashboard. Saved at: dashboard.html)
|
||||
|
@ -570,7 +589,7 @@ Here's the command-line option to add to tests: (See [examples/custom_settings.p
|
|||
Inside your tests, you can use ``self.data`` to access that.
|
||||
|
||||
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Test Directory Configuration:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Test Directory Configuration:</h3>
|
||||
|
||||
🔵 When running tests with **pytest**, you'll want a copy of **[pytest.ini](https://github.com/seleniumbase/SeleniumBase/blob/master/pytest.ini)** in your root folders. When running tests with **nosetests**, you'll want a copy of **[setup.cfg](https://github.com/seleniumbase/SeleniumBase/blob/master/setup.cfg)** in your root folders. These files specify default configuration details for tests. Folders should also include a blank ``__init__.py`` file, which allows your tests to import files from that folder.
|
||||
|
||||
|
@ -626,7 +645,7 @@ Of those files, the ``pytest.ini`` config file is the most important, followed b
|
|||
|
||||
--------
|
||||
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Log files from failed tests:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Log files from failed tests:</h3>
|
||||
|
||||
Let's try an example of a test that fails:
|
||||
|
||||
|
@ -651,7 +670,7 @@ pytest test_fail.py
|
|||
|
||||
--------
|
||||
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> The SeleniumBase Dashboard:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> The SeleniumBase Dashboard:</h3>
|
||||
|
||||
🔵 The ``--dashboard`` option for pytest generates a SeleniumBase Dashboard located at ``dashboard.html``, which updates automatically as tests run and produce results. Example:
|
||||
|
||||
|
@ -680,7 +699,7 @@ pytest test_suite.py --dashboard --rs --headless
|
|||
--------
|
||||
|
||||
<a id="creating_visual_reports"></a>
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Generating Test Reports:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Generating Test Reports:</h3>
|
||||
|
||||
<h4><b>Pytest Reports:</b></h4>
|
||||
|
||||
|
@ -755,7 +774,7 @@ pytest test_suite.py --alluredir=allure_results
|
|||
```
|
||||
|
||||
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Using a Proxy Server:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Using a Proxy Server:</h3>
|
||||
|
||||
If you wish to use a proxy server for your browser tests (Chromium or Firefox), you can add ``--proxy=IP_ADDRESS:PORT`` as an argument on the command line.
|
||||
|
||||
|
@ -784,7 +803,7 @@ pytest proxy_test.py --proxy=proxy1
|
|||
```
|
||||
|
||||
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Changing the User-Agent:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Changing the User-Agent:</h3>
|
||||
|
||||
🔵 If you wish to change the User-Agent for your browser tests (Chromium and Firefox only), you can add ``--agent="USER AGENT STRING"`` as an argument on the command-line.
|
||||
|
||||
|
@ -793,12 +812,12 @@ pytest user_agent_test.py --agent="Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1
|
|||
```
|
||||
|
||||
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Handling Pop-Up / Pop Up Alerts:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Handling Pop-Up / Pop Up Alerts:</h3>
|
||||
|
||||
🔵 <code>self.accept_alert()</code> automatically waits for and accepts alert pop-ups. <code>self.dismiss_alert()</code> automatically waits for and dismisses alert pop-ups. On occasion, some methods like <code>self.click(SELECTOR)</code> might dismiss a pop-up on its own because they call JavaScript to make sure that the <code>readyState</code> of the page is <code>complete</code> before advancing. If you're trying to accept a pop-up that got dismissed this way, use this workaround: Call <code>self.find_element(SELECTOR).click()</code> instead, (which will let the pop-up remain on the screen), and then use <code>self.accept_alert()</code> to accept the pop-up (<a href="https://github.com/seleniumbase/SeleniumBase/issues/600#issuecomment-647270426">more on that here</a>). If pop-ups are intermittent, wrap code in a try/except block.
|
||||
|
||||
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Building Guided Tours for Websites:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Building Guided Tours for Websites:</h3>
|
||||
|
||||
🔵 Learn about <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/tour_examples/ReadMe.md">SeleniumBase Interactive Walkthroughs</a> (in the ``examples/tour_examples/`` folder). It's great for prototyping a website onboarding experience.
|
||||
|
||||
|
@ -808,7 +827,7 @@ pytest user_agent_test.py --agent="Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1
|
|||
--------
|
||||
|
||||
<div></div>
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Production Environments & Integrations:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Production Environments & Integrations:</h3>
|
||||
|
||||
<div></div>
|
||||
<details>
|
||||
|
@ -834,7 +853,7 @@ pytest [YOUR_TEST_FILE.py] --with-db-reporting --with-s3-logging
|
|||
|
||||
|
||||
<a id="detailed_method_specifications"></a>
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Detailed Method Specifications and Examples:</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Detailed Method Specifications and Examples:</h3>
|
||||
|
||||
🔵 Navigating to a web page: (and related commands)
|
||||
|
||||
|
@ -1128,7 +1147,7 @@ pytest --reruns=1 --reruns-delay=1
|
|||
<p>You can use the <code>@retry_on_exception()</code> decorator to retry failing methods. (First import: <code>from seleniumbase import decorators</code>). To learn more about SeleniumBase decorators, <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/seleniumbase/common">click here</a>.</p>
|
||||
|
||||
|
||||
<h3><img src="https://seleniumbase.github.io/img/green_logo2.png" title="SeleniumBase" width="32" /> Wrap-Up</h3>
|
||||
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> Wrap-Up</h3>
|
||||
|
||||
<b>Congratulations on getting started with SeleniumBase!</b>
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
class HomePage(object):
|
||||
dialog_box = '[role="dialog"] div'
|
||||
search_box = 'input[title="Search"]'
|
||||
list_box = '[role="listbox"]'
|
||||
search_button = 'input[value="Google Search"]'
|
||||
feeling_lucky_button = """input[value="I'm Feeling Lucky"]"""
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ class GoogleTests(BaseCase):
|
|||
def test_google_dot_com(self):
|
||||
self.open("https://google.com/ncr")
|
||||
self.type(HomePage.search_box, "github")
|
||||
self.assert_element(HomePage.list_box)
|
||||
self.assert_element(HomePage.search_button)
|
||||
self.assert_element(HomePage.feeling_lucky_button)
|
||||
self.click(HomePage.search_button)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
"""Context Manager Tests"""
|
||||
from seleniumbase import SB
|
||||
|
||||
with SB(test=True) as sb:
|
||||
sb.open("https://google.com/ncr")
|
||||
sb.type('[name="q"]', "SeleniumBase on GitHub\n")
|
||||
sb.click('a[href*="github.com/seleniumbase"]')
|
||||
sb.highlight("div.Layout-main")
|
||||
sb.highlight("div.Layout-sidebar")
|
||||
sb.sleep(0.5)
|
||||
|
||||
with SB(test=True, rtf=True, demo=True) as sb:
|
||||
sb.open("seleniumbase.github.io/demo_page")
|
||||
sb.type("#myTextInput", "This is Automated")
|
||||
sb.assert_text("This is Automated", "#myTextInput")
|
||||
sb.assert_text("This Text is Green", "#pText")
|
||||
sb.click('button:contains("Click Me")')
|
||||
sb.assert_text("This Text is Purple", "#pText")
|
||||
sb.click("#checkBox1")
|
||||
sb.assert_element_not_visible("div#drop2 img#logo")
|
||||
sb.drag_and_drop("img#logo", "div#drop2")
|
||||
sb.assert_element("div#drop2 img#logo")
|
|
@ -10,8 +10,10 @@ class GitHubTests(BaseCase):
|
|||
self.open("https://github.com/search?q=SeleniumBase")
|
||||
self.slow_click('a[href="/seleniumbase/SeleniumBase"]')
|
||||
self.click_if_visible('[data-action="click:signup-prompt#dismiss"]')
|
||||
self.highlight("div.Layout-main")
|
||||
self.highlight("div.Layout-sidebar")
|
||||
self.assert_element("div.repository-content")
|
||||
self.assert_text("SeleniumBase", "strong a")
|
||||
self.slow_click('a[title="seleniumbase"]')
|
||||
self.click('a[title="seleniumbase"]')
|
||||
self.slow_click('a[title="fixtures"]')
|
||||
self.assert_element('a[title="base_case.py"]')
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
from seleniumbase import js_utils
|
||||
from seleniumbase import page_actions
|
||||
from seleniumbase import Driver
|
||||
|
||||
with Driver() as driver:
|
||||
driver.get("https://google.com/ncr")
|
||||
js_utils.highlight_with_js(driver, 'img[alt="Google"]', 6, "")
|
||||
|
||||
with Driver() as driver: # By default, browser="chrome"
|
||||
driver.get("https://seleniumbase.github.io/demo_page")
|
||||
js_utils.highlight_with_js(driver, "h2", 5, "")
|
||||
CSS = "css selector"
|
||||
driver.find_element(CSS, "#myTextInput").send_keys("Automation")
|
||||
driver.find_element(CSS, "#checkBox1").click()
|
||||
js_utils.highlight_with_js(driver, "img", 5, "")
|
||||
|
||||
with Driver(browser="chrome", incognito=True) as driver:
|
||||
driver.get("https://seleniumbase.io/apps/calculator")
|
||||
page_actions.wait_for_element_visible(driver, "4", "id").click()
|
||||
page_actions.wait_for_element_visible(driver, "2", "id").click()
|
||||
page_actions.wait_for_text_visible(driver, "42", "output", "id")
|
||||
js_utils.highlight_with_js(driver, "#output", 6, "")
|
|
@ -66,6 +66,7 @@ if pure_python:
|
|||
sb.enable_sync = False
|
||||
sb.use_auto_ext = False
|
||||
sb.undetectable = False
|
||||
sb.uc_subprocess = False
|
||||
sb.no_sandbox = False
|
||||
sb.disable_js = False
|
||||
sb.disable_gpu = False
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
"""Context Manager Tests"""
|
||||
from seleniumbase import SB
|
||||
|
||||
with SB() as sb: # By default, browser="chrome" if not set.
|
||||
sb.open("https://seleniumbase.github.io/realworld/login")
|
||||
sb.type("#username", "demo_user")
|
||||
sb.type("#password", "secret_pass")
|
||||
sb.enter_mfa_code("#totpcode", "GAXG2MTEOR3DMMDG") # 6-digit
|
||||
sb.assert_text("Welcome!", "h1")
|
||||
sb.highlight("img#image1") # A fancier assert_element() call
|
||||
sb.click('a:contains("This Page")') # Use :contains() on any tag
|
||||
sb.click_link("Sign out") # Link must be "a" tag. Not "button".
|
||||
sb.assert_element('a:contains("Sign in")')
|
||||
sb.assert_exact_text("You have been signed out!", "#top_message")
|
|
@ -9,8 +9,8 @@ class TestMFALogin(BaseCase):
|
|||
self.enter_mfa_code("#totpcode", "GAXG2MTEOR3DMMDG") # 6-digit
|
||||
self.assert_text("Welcome!", "h1")
|
||||
self.highlight("img#image1") # A fancier assert_element() call
|
||||
self.click('a:contains("This Page")')
|
||||
self.click('a:contains("This Page")') # Use :contains() on any tag
|
||||
self.save_screenshot_to_logs() # In "./latest_logs/" folder.
|
||||
self.click_link("Sign out") # Must be "a" tag. Not "button".
|
||||
self.click_link("Sign out") # Link must be "a" tag. Not "button".
|
||||
self.assert_element('a:contains("Sign in")')
|
||||
self.assert_exact_text("You have been signed out!", "#top_message")
|
||||
|
|
|
@ -11,8 +11,8 @@ class Test_UseFixtures:
|
|||
sb.enter_mfa_code("#totpcode", "GAXG2MTEOR3DMMDG") # 6-digit
|
||||
sb.assert_text("Welcome!", "h1")
|
||||
sb.highlight("img#image1") # A fancier assert_element() call
|
||||
sb.click('a:contains("This Page")')
|
||||
sb.click('a:contains("This Page")') # Use :contains() on any tag
|
||||
sb.save_screenshot_to_logs() # In "./latest_logs/" folder.
|
||||
sb.click_link("Sign out") # Must be "a" tag. Not "button".
|
||||
sb.click_link("Sign out") # Link must be "a" tag. Not "button".
|
||||
sb.assert_element('a:contains("Sign in")')
|
||||
sb.assert_exact_text("You have been signed out!", "#top_message")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<p align="center"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.io/cdn/img/sb_logo_f6.png" alt="SeleniumBase" width="330" /></a></p>
|
||||
<p align="center"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.io/cdn/img/sb_logo_f6.png" alt="SeleniumBase" width="445" /></a></p>
|
||||
|
||||
## [<img src="https://seleniumbase.io/img/logo6.png" title="SeleniumBase" width="32">](https://github.com/seleniumbase/SeleniumBase/) Automated Visual Regression Testing
|
||||
|
||||
|
|
|
@ -61,9 +61,8 @@ class WordleTests(BaseCase):
|
|||
def test_wordle(self):
|
||||
self.skip_if_incorrect_env()
|
||||
self.open("https://www.nytimes.com/games/wordle/index.html")
|
||||
self.remove_elements("div.ad")
|
||||
self.click('svg[data-testid="icon-close"]')
|
||||
self.remove_elements("div.ad")
|
||||
self.click_if_visible('svg[data-testid="icon-close"]', timeout=2)
|
||||
self.remove_elements("div.place-ad")
|
||||
self.initialize_word_list()
|
||||
word = random.choice(self.word_list)
|
||||
num_attempts = 0
|
||||
|
|
|
@ -162,7 +162,8 @@ pytest my_first_test.py --settings-file=custom_settings.py
|
|||
--enable-ws # (Enable Web Security on Chromium-based browsers.)
|
||||
--enable-sync # (Enable "Chrome Sync" on websites.)
|
||||
--use-auto-ext # (Use Chrome's automation extension.)
|
||||
--undetected | --uc # (Use undetected-chromedriver to evade bot-detection.)
|
||||
--uc | --undetected # (Use undetected-chromedriver to evade bot-detection.)
|
||||
--uc-sub | --uc-subprocess # (Use undetected-chromedriver as a subprocess.)
|
||||
--remote-debug # (Enable Chrome's Remote Debugger on http://localhost:9222)
|
||||
--final-debug # (Enter Debug Mode after each test ends. Don't use with CI!)
|
||||
--dashboard # (Enable the SeleniumBase Dashboard. Saved at: dashboard.html)
|
||||
|
|
|
@ -31,9 +31,9 @@ class TestMFALogin(BaseCase):
|
|||
self.enter_mfa_code("#totpcode", "GAXG2MTEOR3DMMDG") # 6-digit
|
||||
self.assert_text("Welcome!", "h1")
|
||||
self.highlight("img#image1") # A fancier assert_element() call
|
||||
self.click('a:contains("This Page")')
|
||||
self.click('a:contains("This Page")') # Use :contains() on any tag
|
||||
self.save_screenshot_to_logs() # In "./latest_logs/" folder.
|
||||
self.click_link("Sign out") # Must be "a" tag. Not "button".
|
||||
self.click_link("Sign out") # Link must be "a" tag. Not "button".
|
||||
self.assert_element('a:contains("Sign in")')
|
||||
self.assert_exact_text("You have been signed out!", "#top_message")
|
||||
```
|
||||
|
|
|
@ -126,7 +126,7 @@ self.click_visible_elements(selector, by="css selector", limit=0, timeout=None)
|
|||
|
||||
self.click_nth_visible_element(selector, number, by="css selector", timeout=None)
|
||||
|
||||
self.click_if_visible(selector, by="css selector")
|
||||
self.click_if_visible(selector, by="css selector", timeout=0)
|
||||
|
||||
self.click_active_element()
|
||||
|
||||
|
@ -356,9 +356,9 @@ self.click_xpath(xpath)
|
|||
|
||||
self.js_click(selector, by="css selector", all_matches=False, scroll=True)
|
||||
|
||||
self.js_click_if_present(selector, by="css selector")
|
||||
self.js_click_if_present(selector, by="css selector", timeout=0)
|
||||
|
||||
self.js_click_if_visible(selector, by="css selector")
|
||||
self.js_click_if_visible(selector, by="css selector", timeout=0)
|
||||
|
||||
self.js_click_all(selector, by="css selector")
|
||||
|
||||
|
|
|
@ -1,9 +1,42 @@
|
|||
<a id="syntax_formats"></a>
|
||||
|
||||
## [<img src="https://seleniumbase.io/img/logo6.png" title="SeleniumBase" width="32">](https://github.com/seleniumbase/SeleniumBase/) The 20 Syntax Formats
|
||||
## [<img src="https://seleniumbase.io/img/logo6.png" title="SeleniumBase" width="32">](https://github.com/seleniumbase/SeleniumBase/) The 22 Syntax Formats
|
||||
|
||||
<b>SeleniumBase</b> supports 20 different syntax formats (<i>design patterns</i>) for structuring tests. (<i>The first 6 are the most common.</i>)
|
||||
<b>SeleniumBase</b> supports 22 different syntax formats (<i>design patterns</i>) for structuring tests.
|
||||
|
||||
--------
|
||||
|
||||
<blockquote>
|
||||
<p dir="auto"><strong>Table of Contents / Navigation:</strong></p>
|
||||
<ul dir="auto">
|
||||
<li><a href="#sb_sf_01"><strong>01. BaseCase direct inheritance</strong></a></li>
|
||||
<li><a href="#sb_sf_02"><strong>02. BaseCase subclass inheritance</strong></a></li>
|
||||
<li><a href="#sb_sf_03"><strong>03. The "sb" pytest fixture (no class)</strong></a></li>
|
||||
<li><a href="#sb_sf_04"><strong>04. The "sb" pytest fixture (in class)</strong></a></li>
|
||||
<li><a href="#sb_sf_05"><strong>05. Page Object Model with BaseCase</strong></a></li>
|
||||
<li><a href="#sb_sf_06"><strong>06. Page Object Model with "sb" fixture</strong></a></li>
|
||||
<li><a href="#sb_sf_07"><strong>07. Using "request" to get "sb" (no class)</strong></a></li>
|
||||
<li><a href="#sb_sf_08"><strong>08. Using "request" to get "sb" (in class)</strong></a></li>
|
||||
<li><a href="#sb_sf_09"><strong>09. BaseCase while overriding driver setup</strong></a></li>
|
||||
<li><a href="#sb_sf_10"><strong>10. The driver manager without BaseCase</strong></a></li>
|
||||
<li><a href="#sb_sf_11"><strong>11. SeleniumBase translated into Chinese</strong></a></li>
|
||||
<li><a href="#sb_sf_12"><strong>12. SeleniumBase translated into Dutch</strong></a></li>
|
||||
<li><a href="#sb_sf_13"><strong>13. SeleniumBase translated into French</strong></a></li>
|
||||
<li><a href="#sb_sf_14"><strong>14. SeleniumBase translated into Italian</strong></a></li>
|
||||
<li><a href="#sb_sf_15"><strong>15. SeleniumBase translated into Japanese</strong></a></li>
|
||||
<li><a href="#sb_sf_16"><strong>16. SeleniumBase translated into Korean</strong></a></li>
|
||||
<li><a href="#sb_sf_17"><strong>17. SeleniumBase translated into Portuguese</strong></a></li>
|
||||
<li><a href="#sb_sf_18"><strong>18. SeleniumBase translated into Russian</strong></a></li>
|
||||
<li><a href="#sb_sf_19"><strong>19. SeleniumBase translated into Spanish</strong></a></li>
|
||||
<li><a href="#sb_sf_20"><strong>20. SeleniumBase "behave" Gherkin format</strong></a></li>
|
||||
<li><a href="#sb_sf_21"><strong>21. SeleniumBase as a Python context manager</strong></a></li>
|
||||
<li><a href="#sb_sf_22"><strong>22. The driver manager as a context manager</strong></a></li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
--------
|
||||
|
||||
<a id="sb_sf_01"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 1. <code>BaseCase</code> direct inheritance</h3>
|
||||
|
||||
This format is used by most of the examples in the <a href="https://github.com/seleniumbase/SeleniumBase/tree/master/examples">SeleniumBase examples folder</a>. It's a great starting point for anyone learning SeleniumBase, and it follows good object-oriented programming principles. In this format, <code>BaseCase</code> is imported at the top of a Python file, followed by a Python class inheriting <code>BaseCase</code>. Then, any test method defined in that class automatically gains access to SeleniumBase methods, including the <code>setUp()</code> and <code>tearDown()</code> methods that are automatically called to spin up and spin down web browsers at the beginning and end of test methods. Here's an example of that:
|
||||
|
@ -25,6 +58,7 @@ class MyTestClass(BaseCase):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_demo_site.py">examples/test_demo_site.py</a> for the full test.)
|
||||
|
||||
<a id="sb_sf_02"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 2. <code>BaseCase</code> subclass inheritance</h3>
|
||||
|
||||
There are situations where you may want to customize the <code>setUp</code> and <code>tearDown</code> of your tests. Maybe you want to have all your tests login to a specific web site first, or maybe you want to have your tests report results through an API call depending on whether a test passed or failed. <b>This can be done by creating a subclass of <code>BaseCase</code> and then carefully creating custom <code>setUp()</code> and <code>tearDown()</code> methods that don't overwrite the critical functionality of the default SeleniumBase <code>setUp()</code> and <code>tearDown()</code> methods.</b> Afterwards, your test classes will inherit the subclass of <code>BaseCase</code> with the added functionality, rather than directly inheriting <code>BaseCase</code> itself. Here's an example of that:
|
||||
|
@ -70,6 +104,7 @@ class MyTests(BaseTestCase):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/boilerplates/base_test_case.py">examples/boilerplates/base_test_case.py</a> for more info.)
|
||||
|
||||
<a id="sb_sf_03"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 3. The <code>sb</code> pytest fixture (no class)</h3>
|
||||
|
||||
The pytest framework comes with a unique system called fixtures, which replaces import statements at the top of Python files by importing libraries directly into test definitions. More than just being an import, a pytest fixture can also automatically call predefined <code>setUp()</code> and <code>tearDown()</code> methods at the beginning and end of test methods. To work, <code>sb</code> is added as an argument to each test method definition that needs SeleniumBase functionality. This means you no longer need import statements in your Python files to use SeleniumBase. <b>If using other pytest fixtures in your tests, you may need to use the SeleniumBase fixture (instead of <code>BaseCase</code> class inheritance) for compatibility reasons.</b> Here's an example of the <code>sb</code> fixture in a test that does not use Python classes:
|
||||
|
@ -84,6 +119,7 @@ def test_sb_fixture_with_no_class(sb):
|
|||
|
||||
(See the top of <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_sb_fixture.py">examples/test_sb_fixture.py</a> for the test.)
|
||||
|
||||
<a id="sb_sf_04"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 4. The <code>sb</code> pytest fixture (in class)</h3>
|
||||
|
||||
The <code>sb</code> pytest fixture can also be used inside of a class. There is a slight change to the syntax because that means test methods must also include <code>self</code> in their argument definitions when test methods are defined. (The <code>self</code> argument represents the class object, and is used in every test method that lives inside of a class.) Once again, no import statements are needed in your Python files for this to work. Here's an example of using the <code>sb</code> fixture in a test method that lives inside of a Python class:
|
||||
|
@ -99,6 +135,7 @@ class Test_SB_Fixture:
|
|||
|
||||
(See the bottom of <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_sb_fixture.py">examples/test_sb_fixture.py</a> for the test.)
|
||||
|
||||
<a id="sb_sf_05"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 5. The classic Page Object Model with <code>BaseCase</code> inheritance</h3>
|
||||
|
||||
With SeleniumBase, you can use Page Objects to break out code from tests, but remember, the <code>self</code> variable (from test methods that inherit <code>BaseCase</code>) contains the driver and all other framework-specific variable definitions. Therefore, that <code>self</code> must be passed as an arg into any outside class method in order to call SeleniumBase methods from there. In the example below, the <code>self</code> variable from the test method is passed into the <code>sb</code> arg of the Page Object class method because the <code>self</code> arg of the Page Object class method is already being used for its own class. Every Python class method definition must include the <code>self</code> as the first arg.
|
||||
|
@ -122,6 +159,7 @@ class MyTests(BaseCase):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/boilerplates/samples/swag_labs_test.py">examples/boilerplates/samples/swag_labs_test.py</a> for the full test.)
|
||||
|
||||
<a id="sb_sf_06"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 6. The classic Page Object Model with the <code>sb</code> pytest fixture</h3>
|
||||
|
||||
This is similar to the classic Page Object Model with <code>BaseCase</code> inheritance, except that this time we pass the <code>sb</code> pytest fixture from the test into the <code>sb</code> arg of the page object class method, (instead of passing <code>self</code>). Now that you're using <code>sb</code> as a pytest fixture, you no longer need to import <code>BaseCase</code> anywhere in your code. See the example below:
|
||||
|
@ -143,6 +181,7 @@ class MyTests:
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/boilerplates/samples/sb_swag_test.py">examples/boilerplates/samples/sb_swag_test.py</a> for the full test.)
|
||||
|
||||
<a id="sb_sf_07"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 7. Using the <code>request</code> fixture to get the <code>sb</code> fixture (no class)</h3>
|
||||
|
||||
The pytest <code>request</code> fixture can be used to retrieve other pytest fixtures from within tests, such as the <code>sb</code> fixture. This allows you to have more control over when fixtures get initialized because the fixture no longer needs to be loaded at the very beginning of test methods. This is done by calling <code>request.getfixturevalue('sb')</code> from the test. Here's an example of using the pytest <code>request</code> fixture to load the <code>sb</code> fixture in a test method that does not use Python classes:
|
||||
|
@ -160,6 +199,7 @@ def test_request_sb_fixture(request):
|
|||
|
||||
(See the top of <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_request_sb_fixture.py">examples/test_request_sb_fixture.py</a> for the test.)
|
||||
|
||||
<a id="sb_sf_08"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 8. Using the <code>request</code> fixture to get the <code>sb</code> fixture (in class)</h3>
|
||||
|
||||
The pytest <code>request</code> fixture can also be used to get the <code>sb</code> fixture from inside a Python class. Here's an example of that:
|
||||
|
@ -179,6 +219,7 @@ class Test_Request_Fixture:
|
|||
|
||||
(See the bottom of <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_request_sb_fixture.py">examples/test_request_sb_fixture.py</a> for the test.)
|
||||
|
||||
<a id="sb_sf_09"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 9. Overriding the SeleniumBase browser launcher </h3>
|
||||
|
||||
When you want to use SeleniumBase methods, but you want total freedom to control how you spin up your web browsers, this is the format you want. Although SeleniumBase gives you plenty of command-line options to change how your browsers are launched, this format gives you even more control. Here's an example of that:
|
||||
|
@ -233,6 +274,7 @@ class WireTestCase(BaseCase):
|
|||
print(request.url)
|
||||
```
|
||||
|
||||
<a id="sb_sf_10"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 10. Using the SeleniumBase browser launcher without BaseCase </h3>
|
||||
|
||||
One way of running Selenium tests with pure ``python`` (as opposed to using ``pytest`` or ``nosetests``) is by using this format, which bypasses [BaseCase](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/fixtures/base_case.py) methods while still giving you ``browser_launcher`` with its powerful webdriver management software. SeleniumBase includes helper files such as [page_actions.py](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/fixtures/page_actions.py), which may help you get around some of the limitations of bypassing ``BaseCase``. Here's an example:
|
||||
|
@ -257,6 +299,7 @@ finally:
|
|||
|
||||
The above format can be used as a drop-in replacement for virtually every Python/selenium framework, as it uses the raw ``driver`` for handling commands. The ``get_driver()`` method simplifies the work of managing drivers and spinning them up with optimal settings. Note that now you'll need to manage the spin-up and spin-down of browsers in tests, which was done automatically in tests that inherit ``BaseCase`` (or ones that use the ``sb`` pytest fixture). You'll also need to use extra code (as shown above) to make sure you don't leave any browsers hanging after your tests complete.
|
||||
|
||||
<a id="sb_sf_11"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 11. SeleniumBase in Chinese</h3>
|
||||
|
||||
This format is similar to the English version with <code>BaseCase</code> inheritance, but there's a different import statement, and method names have been translated into Chinese. Here's an example of that:
|
||||
|
@ -286,6 +329,7 @@ class 我的测试类(硒测试用例):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/translations/chinese_test_1.py">examples/translations/chinese_test_1.py</a> for the Chinese test.)
|
||||
|
||||
<a id="sb_sf_12"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 12. SeleniumBase in Dutch</h3>
|
||||
|
||||
This format is similar to the English version with <code>BaseCase</code> inheritance, but there's a different import statement, and method names have been translated into Dutch. Here's an example of that:
|
||||
|
@ -314,6 +358,7 @@ class MijnTestklasse(Testgeval):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/translations/dutch_test_1.py">examples/translations/dutch_test_1.py</a> for the Dutch test.)
|
||||
|
||||
<a id="sb_sf_13"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 13. SeleniumBase in French</h3>
|
||||
|
||||
This format is similar to the English version with <code>BaseCase</code> inheritance, but there's a different import statement, and method names have been translated into French. Here's an example of that:
|
||||
|
@ -342,6 +387,7 @@ class MaClasseDeTest(CasDeBase):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/translations/french_test_1.py">examples/translations/french_test_1.py</a> for the French test.)
|
||||
|
||||
<a id="sb_sf_14"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 14. SeleniumBase in Italian</h3>
|
||||
|
||||
This format is similar to the English version with <code>BaseCase</code> inheritance, but there's a different import statement, and method names have been translated into Italian. Here's an example of that:
|
||||
|
@ -370,6 +416,7 @@ class MiaClasseDiTest(CasoDiProva):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/translations/italian_test_1.py">examples/translations/italian_test_1.py</a> for the Italian test.)
|
||||
|
||||
<a id="sb_sf_15"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 15. SeleniumBase in Japanese</h3>
|
||||
|
||||
This format is similar to the English version with <code>BaseCase</code> inheritance, but there's a different import statement, and method names have been translated into Japanese. Here's an example of that:
|
||||
|
@ -399,6 +446,7 @@ class 私のテストクラス(セレニウムテストケース):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/translations/japanese_test_1.py">examples/translations/japanese_test_1.py</a> for the Japanese test.)
|
||||
|
||||
<a id="sb_sf_16"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 16. SeleniumBase in Korean</h3>
|
||||
|
||||
This format is similar to the English version with <code>BaseCase</code> inheritance, but there's a different import statement, and method names have been translated into Korean. Here's an example of that:
|
||||
|
@ -426,6 +474,7 @@ class 테스트_클래스(셀레늄_테스트_케이스):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/translations/korean_test_1.py">examples/translations/korean_test_1.py</a> for the Korean test.)
|
||||
|
||||
<a id="sb_sf_17"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 17. SeleniumBase in Portuguese</h3>
|
||||
|
||||
This format is similar to the English version with <code>BaseCase</code> inheritance, but there's a different import statement, and method names have been translated into Portuguese. Here's an example of that:
|
||||
|
@ -457,6 +506,7 @@ class MinhaClasseDeTeste(CasoDeTeste):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/translations/portuguese_test_1.py">examples/translations/portuguese_test_1.py</a> for the Portuguese test.)
|
||||
|
||||
<a id="sb_sf_18"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 18. SeleniumBase in Russian</h3>
|
||||
|
||||
This format is similar to the English version with <code>BaseCase</code> inheritance, but there's a different import statement, and method names have been translated into Russian. Here's an example of that:
|
||||
|
@ -485,6 +535,7 @@ class МойТестовыйКласс(ТестНаСелен):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/translations/russian_test_1.py">examples/translations/russian_test_1.py</a> for the Russian test.)
|
||||
|
||||
<a id="sb_sf_19"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 19. SeleniumBase in Spanish</h3>
|
||||
|
||||
This format is similar to the English version with <code>BaseCase</code> inheritance, but there's a different import statement, and method names have been translated into Spanish. Here's an example of that:
|
||||
|
@ -513,6 +564,7 @@ class MiClaseDePrueba(CasoDePrueba):
|
|||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/translations/spanish_test_1.py">examples/translations/spanish_test_1.py</a> for the Spanish test.)
|
||||
|
||||
<a id="sb_sf_20"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 20. Behave-BDD Gherkin tests that use SeleniumBase </h3>
|
||||
|
||||
With [Behave's BDD Gherkin format](https://behave.readthedocs.io/en/stable/gherkin.html), you can use natural language to write tests that work with SeleniumBase methods. Behave tests are run by calling ``behave`` on the command-line. This requires some special files in a specific directory structure. Here's an example of that structure:
|
||||
|
@ -614,6 +666,89 @@ def login_to_swag_labs(context, user):
|
|||
|
||||
(For more information, see the <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/behave_bdd/ReadMe.md">SeleniumBase Behave BDD ReadMe</a>.)
|
||||
|
||||
<a id="sb_sf_21"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 21. Using the <code>SB</code> context manager to get an instance of <code>sb</code> in a <code>with</code> block.</h3>
|
||||
|
||||
This format provides a pure Python way of using SeleniumBase without a test runner. Options can be passed via method instantiation or from the command-line. When setting the <code>test</code> option to <code>True</code> (or calling <code>python --test</code>), then standard test logging will occur, such as screenshots and reports for failing tests. All the usual SeleniumBase options are available, such as customizing the browser settings, etc. Here are some examples:
|
||||
|
||||
```python
|
||||
from seleniumbase import SB
|
||||
|
||||
with SB() as sb: # By default, browser="chrome" if not set.
|
||||
sb.open("https://seleniumbase.github.io/realworld/login")
|
||||
sb.type("#username", "demo_user")
|
||||
sb.type("#password", "secret_pass")
|
||||
sb.enter_mfa_code("#totpcode", "GAXG2MTEOR3DMMDG") # 6-digit
|
||||
sb.assert_text("Welcome!", "h1")
|
||||
sb.highlight("img#image1") # A fancier assert_element() call
|
||||
sb.click('a:contains("This Page")') # Use :contains() on any tag
|
||||
sb.click_link("Sign out") # Link must be "a" tag. Not "button".
|
||||
sb.assert_element('a:contains("Sign in")')
|
||||
sb.assert_exact_text("You have been signed out!", "#top_message")
|
||||
```
|
||||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_sb.py">examples/raw_sb.py</a> for the test.)
|
||||
|
||||
Here's another example, which uses <code>test</code> mode:
|
||||
|
||||
```python
|
||||
from seleniumbase import SB
|
||||
|
||||
with SB(test=True) as sb:
|
||||
sb.open("https://google.com/ncr")
|
||||
sb.type('[name="q"]', "SeleniumBase on GitHub\n")
|
||||
sb.click('a[href*="github.com/seleniumbase"]')
|
||||
sb.highlight("div.Layout-main")
|
||||
sb.highlight("div.Layout-sidebar")
|
||||
sb.sleep(0.5)
|
||||
|
||||
with SB(test=True, rtf=True, demo=True) as sb:
|
||||
sb.open("seleniumbase.github.io/demo_page")
|
||||
sb.type("#myTextInput", "This is Automated")
|
||||
sb.assert_text("This is Automated", "#myTextInput")
|
||||
sb.assert_text("This Text is Green", "#pText")
|
||||
sb.click('button:contains("Click Me")')
|
||||
sb.assert_text("This Text is Purple", "#pText")
|
||||
sb.click("#checkBox1")
|
||||
sb.assert_element_not_visible("div#drop2 img#logo")
|
||||
sb.drag_and_drop("img#logo", "div#drop2")
|
||||
sb.assert_element("div#drop2 img#logo")
|
||||
```
|
||||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/context_scripts.py">examples/context_scripts.py</a> for the test.)
|
||||
|
||||
<a id="sb_sf_22"></a>
|
||||
<h3><img src="https://seleniumbase.io/img/green_logo.png" title="SeleniumBase" width="32" /> 22. Using the <code>GetDriver</code> context manager to get an instance of <code>driver</code> in a <code>with</code> block.</h3>
|
||||
|
||||
This pure Python format gives you a raw <code>webdriver</code> instance in a <code>with</code> block. The SeleniumBase Driver Manager will automatically make sure that your driver is compatible with your browser version. It gives you full access to customize driver options via method args or via the command-line. The driver will automatically call <code>quit()</code> after the code leaves the <code>with</code> block. Here are some examples:
|
||||
|
||||
```python
|
||||
from seleniumbase import js_utils
|
||||
from seleniumbase import page_actions
|
||||
from seleniumbase import Driver
|
||||
|
||||
with Driver() as driver:
|
||||
driver.get("https://google.com/ncr")
|
||||
js_utils.highlight_with_js(driver, 'img[alt="Google"]', 6, "")
|
||||
|
||||
with Driver() as driver: # By default, browser="chrome"
|
||||
driver.get("https://seleniumbase.github.io/demo_page")
|
||||
js_utils.highlight_with_js(driver, "h2", 5, "")
|
||||
CSS = "css selector"
|
||||
driver.find_element(CSS, "#myTextInput").send_keys("Automation")
|
||||
driver.find_element(CSS, "#checkBox1").click()
|
||||
js_utils.highlight_with_js(driver, "img", 5, "")
|
||||
|
||||
with Driver(browser="chrome", incognito=True) as driver:
|
||||
driver.get("https://seleniumbase.io/apps/calculator")
|
||||
page_actions.wait_for_element_visible(driver, "4", "id").click()
|
||||
page_actions.wait_for_element_visible(driver, "2", "id").click()
|
||||
page_actions.wait_for_text_visible(driver, "42", "output", "id")
|
||||
js_utils.highlight_with_js(driver, "#output", 6, "")
|
||||
```
|
||||
|
||||
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_driver.py">examples/raw_driver.py</a> for the test.)
|
||||
|
||||
--------
|
||||
|
||||
<h3 align="left"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.io/img/sb_logo_10.png" title="SeleniumBase" width="280" /></a></h3>
|
||||
|
|
|
@ -7,8 +7,11 @@ from seleniumbase.common import encryption # noqa
|
|||
from seleniumbase.core.browser_launcher import get_driver # noqa
|
||||
from seleniumbase.fixtures import js_utils # noqa
|
||||
from seleniumbase.fixtures import page_actions # noqa
|
||||
from seleniumbase.fixtures import page_utils # noqa
|
||||
from seleniumbase.fixtures.base_case import BaseCase # noqa
|
||||
from seleniumbase.masterqa.master_qa import MasterQA # noqa
|
||||
from seleniumbase.plugins.sb_manager import SB # noqa
|
||||
from seleniumbase.plugins.driver_manager import Driver # noqa
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
from seleniumbase import translate # noqa
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
# seleniumbase package
|
||||
__version__ = "4.5.6"
|
||||
__version__ = "4.6.0"
|
||||
|
|
|
@ -72,7 +72,8 @@ behave -D agent="User Agent String" -D demo
|
|||
-D enable-ws (Enable Web Security on Chromium-based browsers.)
|
||||
-D enable-sync (Enable "Chrome Sync".)
|
||||
-D use-auto-ext (Use Chrome's automation extension.)
|
||||
-D undetected | -D uc (Use undetected-chromedriver to evade bot-detection)
|
||||
-D uc | -D undetected (Use undetected-chromedriver to evade bot-detection)
|
||||
-D uc-sub | -D uc-subprocess (Use undetected-chromedriver as a subprocess)
|
||||
-D remote-debug (Enable Chrome's Remote Debugger on http://localhost:9222)
|
||||
-D dashboard (Enable the SeleniumBase Dashboard. Saved at: dashboard.html)
|
||||
-D dash-title=STRING (Set the title shown for the generated dashboard.)
|
||||
|
@ -169,6 +170,7 @@ def get_configured_sb(context):
|
|||
sb.enable_sync = False
|
||||
sb.use_auto_ext = False
|
||||
sb.undetectable = False
|
||||
sb.uc_subprocess = False
|
||||
sb.no_sandbox = False
|
||||
sb.disable_gpu = False
|
||||
sb._multithreaded = False
|
||||
|
@ -178,6 +180,7 @@ def get_configured_sb(context):
|
|||
sb.visual_baseline = False
|
||||
sb.window_size = None
|
||||
sb.maximize_option = False
|
||||
sb.is_context_manager = False
|
||||
sb.save_screenshot_after_test = False
|
||||
sb.timeout_multiplier = None
|
||||
sb.pytest_html_report = None
|
||||
|
@ -213,6 +216,7 @@ def get_configured_sb(context):
|
|||
sb.proxy_pac_url = None
|
||||
sb.swiftshader = False
|
||||
sb.ad_block_on = False
|
||||
sb.is_nosetest = False
|
||||
sb.highlights = None
|
||||
sb.interval = None
|
||||
sb.cap_file = None
|
||||
|
@ -497,10 +501,15 @@ def get_configured_sb(context):
|
|||
if low_key in ["use-auto-ext", "use_auto_ext", "auto-ext"]:
|
||||
sb.use_auto_ext = True
|
||||
continue
|
||||
# Handle: -D use-auto-ext / use_auto_ext / auto-ext
|
||||
# Handle: -D undetected / undetectable / uc
|
||||
if low_key in ["undetected", "undetectable", "uc"]:
|
||||
sb.undetectable = True
|
||||
continue
|
||||
# Handle: -D uc-subprocess / uc_subprocess / uc-sub
|
||||
if low_key in ["uc-subprocess", "uc_subprocess", "uc-sub"]:
|
||||
sb.uc_subprocess = True
|
||||
sb.undetectable = True
|
||||
continue
|
||||
# Handle: -D no-sandbox / no_sandbox
|
||||
if low_key in ["no-sandbox", "no_sandbox"]:
|
||||
sb.no_sandbox = True
|
||||
|
@ -748,7 +757,10 @@ def get_configured_sb(context):
|
|||
if sb.recorder_ext and sb.headless:
|
||||
sb.headless = False
|
||||
sb.headless2 = True
|
||||
if sb.browser not in ["chrome", "edge"]:
|
||||
if sb.headless2 and sb.browser == "firefox":
|
||||
sb.headless2 = False # Only for Chromium browsers
|
||||
sb.headless = True # Firefox has regular headless
|
||||
elif sb.browser not in ["chrome", "edge"]:
|
||||
sb.headless2 = False # Only for Chromium browsers
|
||||
# Recorder Mode only supports Chromium browsers.
|
||||
if sb.recorder_ext and (sb.browser not in ["chrome", "edge"]):
|
||||
|
@ -756,10 +768,6 @@ def get_configured_sb(context):
|
|||
"\n\n Recorder Mode ONLY supports Chrome and Edge!"
|
||||
'\n (Your browser choice was: "%s")\n' % sb.browser
|
||||
)
|
||||
# Recorder Mode can still optimize scripts in --headless2 mode.
|
||||
if sb.recorder_mode and sb.headless:
|
||||
sb.headless = False
|
||||
sb.headless2 = True
|
||||
# The Xvfb virtual display server is for Linux OS Only.
|
||||
if sb.xvfb and "linux" not in sys.platform:
|
||||
sb.xvfb = False
|
||||
|
@ -778,6 +786,10 @@ def get_configured_sb(context):
|
|||
'or by calling the new "-D headless2".)'
|
||||
)
|
||||
sb.headless = True
|
||||
# Recorder Mode can still optimize scripts in --headless2 mode.
|
||||
if sb.recorder_mode and sb.headless:
|
||||
sb.headless = False
|
||||
sb.headless2 = True
|
||||
if not sb.headless and not sb.headless2:
|
||||
sb.headed = True
|
||||
if sb.servername != "localhost":
|
||||
|
@ -816,6 +828,10 @@ def get_configured_sb(context):
|
|||
sb_config.headless = sb.headless
|
||||
sb_config.headless_active = False
|
||||
sb_config.headed = sb.headed
|
||||
sb_config.is_behave = True
|
||||
sb_config.is_pytest = False
|
||||
sb_config.is_nosetest = False
|
||||
sb_config.is_context_manager = False
|
||||
sb_config.window_size = sb.window_size
|
||||
sb_config.maximize_option = sb.maximize_option
|
||||
sb_config.xvfb = sb.xvfb
|
||||
|
|
|
@ -60,13 +60,13 @@ sbase install [DRIVER] [OPTIONS]
|
|||
sbase get chromedriver # (Default: 72.0.3626.69 - Tries to detect first.)
|
||||
sbase get geckodriver
|
||||
sbase get edgedriver
|
||||
sbase get chromedriver 105
|
||||
sbase get chromedriver 105.0.5195.52
|
||||
sbase get chromedriver 106
|
||||
sbase get chromedriver 106.0.5249.61
|
||||
sbase get chromedriver latest
|
||||
sbase get chromedriver latest-1 # (Latest minus one)
|
||||
sbase get chromedriver -p
|
||||
sbase get chromedriver latest -p
|
||||
sbase get edgedriver 105.0.1343.53
|
||||
sbase get edgedriver 106.0.1370.42
|
||||
```
|
||||
|
||||
(Drivers: ``chromedriver``, ``geckodriver``, ``edgedriver``,
|
||||
|
|
|
@ -144,13 +144,13 @@ def show_install_usage():
|
|||
print(" sbase get chromedriver")
|
||||
print(" sbase get geckodriver")
|
||||
print(" sbase get edgedriver")
|
||||
print(" sbase get chromedriver 105")
|
||||
print(" sbase get chromedriver 105.0.5195.52")
|
||||
print(" sbase get chromedriver 106")
|
||||
print(" sbase get chromedriver 106.0.5249.61")
|
||||
print(" sbase get chromedriver latest")
|
||||
print(" sbase get chromedriver latest-1")
|
||||
print(" sbase get chromedriver -p")
|
||||
print(" sbase get chromedriver latest -p")
|
||||
print(" sbase get edgedriver 105.0.1343.53")
|
||||
print(" sbase get edgedriver 106.0.1370.42")
|
||||
print(" Output:")
|
||||
print(" Downloads the chosen webdriver to seleniumbase/drivers")
|
||||
print(" (chromedriver is required for Chrome automation)")
|
||||
|
|
|
@ -15,13 +15,13 @@ Examples:
|
|||
sbase get chromedriver
|
||||
sbase get geckodriver
|
||||
sbase get edgedriver
|
||||
sbase get chromedriver 105.0.5195.52
|
||||
sbase get chromedriver 105
|
||||
sbase get chromedriver 106.0.5249.61
|
||||
sbase get chromedriver 106
|
||||
sbase get chromedriver latest
|
||||
sbase get chromedriver latest-1 # (Latest minus one)
|
||||
sbase get chromedriver -p
|
||||
sbase get chromedriver latest -p
|
||||
sbase get edgedriver 105.0.1343.53
|
||||
sbase get edgedriver 106.0.1370.42
|
||||
Output:
|
||||
Downloads the chosen webdriver to seleniumbase/drivers
|
||||
(chromedriver is required for Chrome automation)
|
||||
|
@ -49,9 +49,9 @@ if sys.version_info[0] == 3 and sys.version_info[1] >= 7:
|
|||
selenium4_or_newer = True
|
||||
DRIVER_DIR = os.path.dirname(os.path.realpath(drivers.__file__))
|
||||
LOCAL_PATH = "/usr/local/bin/" # On Mac and Linux systems
|
||||
DEFAULT_CHROMEDRIVER_VERSION = "72.0.3626.69" # (Specify "latest" for latest)
|
||||
DEFAULT_GECKODRIVER_VERSION = "v0.31.0"
|
||||
DEFAULT_EDGEDRIVER_VERSION = "102.0.1245.44" # (Looks for LATEST_STABLE first)
|
||||
DEFAULT_CHROMEDRIVER_VERSION = "72.0.3626.69" # (If can't find LATEST_STABLE)
|
||||
DEFAULT_GECKODRIVER_VERSION = "v0.32.0"
|
||||
DEFAULT_EDGEDRIVER_VERSION = "106.0.1370.42" # (If can't find LATEST_STABLE)
|
||||
DEFAULT_OPERADRIVER_VERSION = "v.96.0.4664.45"
|
||||
|
||||
|
||||
|
@ -545,7 +545,7 @@ def main(override=None):
|
|||
remote_file = requests_get_with_retry(headless_ie_url)
|
||||
with open(headless_ie_file_path, "wb") as file:
|
||||
file.write(remote_file.content)
|
||||
print("Download Complete!\n")
|
||||
print("%sDownload Complete!%s\n" % (c1, cr))
|
||||
zip_file_path = headless_ie_file_path
|
||||
zip_ref = zipfile.ZipFile(zip_file_path, "r")
|
||||
contents = zip_ref.namelist()
|
||||
|
@ -589,7 +589,7 @@ def main(override=None):
|
|||
zip_ref.close()
|
||||
os.remove(zip_file_path)
|
||||
shutil.copyfile(driver_path, os.path.join(downloads_folder, filename))
|
||||
print("Unzip Complete!\n")
|
||||
print("%sUnzip Complete!%s\n" % (c2, cr))
|
||||
to_remove = [
|
||||
"%s/%s/ruby_example/Gemfile" % (downloads_folder, h_ie_fn),
|
||||
"%s/%s/ruby_example/Gemfile.lock" % (downloads_folder, h_ie_fn),
|
||||
|
@ -614,13 +614,16 @@ def main(override=None):
|
|||
)
|
||||
print("Making [%s %s] executable ..." % (driver_file, use_version))
|
||||
make_executable(driver_path)
|
||||
print("%s[%s] is now ready for use!%s" % (c1, driver_file, cr))
|
||||
print(
|
||||
"%s[%s %s] is now ready for use!%s"
|
||||
% (c1, driver_file, use_version, cr)
|
||||
)
|
||||
|
||||
print("\nDownloading %s from:\n%s ..." % (file_name, download_url))
|
||||
remote_file = requests_get_with_retry(download_url)
|
||||
with open(file_path, "wb") as file:
|
||||
file.write(remote_file.content)
|
||||
print("Download Complete!\n")
|
||||
print("%sDownload Complete!%s\n" % (c1, cr))
|
||||
|
||||
if file_name.endswith(".zip"):
|
||||
zip_file_path = file_path
|
||||
|
@ -639,14 +642,17 @@ def main(override=None):
|
|||
zip_ref.extractall(downloads_folder)
|
||||
zip_ref.close()
|
||||
os.remove(zip_file_path)
|
||||
print("Unzip Complete!\n")
|
||||
print("%sUnzip Complete!%s\n" % (c2, cr))
|
||||
for f_name in contents:
|
||||
new_file = os.path.join(downloads_folder, str(f_name))
|
||||
pr_file = c3 + new_file + cr
|
||||
print("The file [%s] was saved to:\n%s\n" % (f_name, pr_file))
|
||||
print("Making [%s %s] executable ..." % (f_name, use_version))
|
||||
make_executable(new_file)
|
||||
print("%s[%s] is now ready for use!%s" % (c1, f_name, cr))
|
||||
print(
|
||||
"%s[%s %s] is now ready for use!%s" %
|
||||
(c1, f_name, use_version, cr)
|
||||
)
|
||||
if copy_to_path and os.path.exists(LOCAL_PATH):
|
||||
path_file = LOCAL_PATH + f_name
|
||||
shutil.copyfile(new_file, path_file)
|
||||
|
@ -709,7 +715,7 @@ def main(override=None):
|
|||
zip_ref.extractall(downloads_folder)
|
||||
zip_ref.close()
|
||||
os.remove(zip_file_path)
|
||||
print("Unzip Complete!\n")
|
||||
print("%sUnzip Complete!%s\n" % (c2, cr))
|
||||
to_remove = [
|
||||
"%s/Driver_Notes/credits.html" % downloads_folder,
|
||||
"%s/Driver_Notes/EULA" % downloads_folder,
|
||||
|
@ -721,13 +727,17 @@ def main(override=None):
|
|||
if os.path.exists(os.path.join(downloads_folder, "Driver_Notes/")):
|
||||
# Only works if the directory is empty
|
||||
os.rmdir(os.path.join(downloads_folder, "Driver_Notes/"))
|
||||
pr_driver_path = c3 + driver_path + cr
|
||||
print(
|
||||
"The file [%s] was saved to:\n%s\n"
|
||||
% (driver_file, driver_path)
|
||||
% (driver_file, pr_driver_path)
|
||||
)
|
||||
print("Making [%s %s] executable ..." % (driver_file, use_version))
|
||||
make_executable(driver_path)
|
||||
print("%s[%s] is now ready for use!%s" % (c1, driver_file, cr))
|
||||
print(
|
||||
"%s[%s %s] is now ready for use!%s"
|
||||
% (c1, driver_file, use_version, cr)
|
||||
)
|
||||
if copy_to_path and os.path.exists(LOCAL_PATH):
|
||||
path_file = LOCAL_PATH + f_name
|
||||
shutil.copyfile(new_file, path_file)
|
||||
|
@ -755,7 +765,7 @@ def main(override=None):
|
|||
zip_ref.extractall(downloads_folder)
|
||||
zip_ref.close()
|
||||
os.remove(zip_file_path)
|
||||
print("Unzip Complete!\n")
|
||||
print("%sUnzip Complete!%s\n" % (c2, cr))
|
||||
inner_driver = os.path.join(
|
||||
downloads_folder, inner_folder, driver_file
|
||||
)
|
||||
|
@ -770,7 +780,10 @@ def main(override=None):
|
|||
)
|
||||
print("Making [%s %s] executable ..." % (driver_file, use_version))
|
||||
make_executable(driver_path)
|
||||
print("%s[%s] is now ready for use!%s" % (c1, driver_file, cr))
|
||||
print(
|
||||
"%s[%s %s] is now ready for use!%s"
|
||||
% (c1, driver_file, use_version, cr)
|
||||
)
|
||||
if copy_to_path and os.path.exists(LOCAL_PATH):
|
||||
path_file = LOCAL_PATH + driver_file
|
||||
shutil.copyfile(driver_path, path_file)
|
||||
|
@ -804,14 +817,17 @@ def main(override=None):
|
|||
tar.extractall(downloads_folder)
|
||||
tar.close()
|
||||
os.remove(tar_file_path)
|
||||
print("Unzip Complete!\n")
|
||||
print("%sUnzip Complete!%s\n" % (c2, cr))
|
||||
for f_name in contents:
|
||||
new_file = os.path.join(downloads_folder, str(f_name))
|
||||
pr_file = c3 + new_file + cr
|
||||
print("The file [%s] was saved to:\n%s\n" % (f_name, pr_file))
|
||||
print("Making [%s %s] executable ..." % (f_name, use_version))
|
||||
make_executable(new_file)
|
||||
print("%s[%s] is now ready for use!%s" % (c1, f_name, cr))
|
||||
print(
|
||||
"%s[%s %s] is now ready for use!%s"
|
||||
% (c1, f_name, use_version, cr)
|
||||
)
|
||||
if copy_to_path and os.path.exists(LOCAL_PATH):
|
||||
path_file = LOCAL_PATH + f_name
|
||||
shutil.copyfile(new_file, path_file)
|
||||
|
|
|
@ -613,7 +613,6 @@ def main():
|
|||
data.append(" def test_google_dot_com(self):")
|
||||
data.append(' self.open("https://google.com/ncr")')
|
||||
data.append(' self.type(HomePage.search_box, "github")')
|
||||
data.append(" self.assert_element(HomePage.list_box)")
|
||||
data.append(" self.assert_element(HomePage.search_button)")
|
||||
data.append(" self.assert_element(HomePage.feeling_lucky_button)")
|
||||
data.append(" self.click(HomePage.search_button)")
|
||||
|
@ -631,7 +630,6 @@ def main():
|
|||
data.append("class HomePage(object):")
|
||||
data.append(" dialog_box = '[role=\"dialog\"] div'")
|
||||
data.append(" search_box = 'input[title=\"Search\"]'")
|
||||
data.append(" list_box = '[role=\"listbox\"]'")
|
||||
data.append(" search_button = 'input[value=\"Google Search\"]'")
|
||||
data.append(
|
||||
' feeling_lucky_button = """input[value="I\'m Feeling Lucky"]"""'
|
||||
|
|
|
@ -354,6 +354,7 @@ def _set_chrome_options(
|
|||
enable_sync,
|
||||
use_auto_ext,
|
||||
undetectable,
|
||||
uc_subprocess,
|
||||
no_sandbox,
|
||||
disable_gpu,
|
||||
headless2,
|
||||
|
@ -875,7 +876,7 @@ def validate_proxy_string(proxy_string):
|
|||
|
||||
|
||||
def get_driver(
|
||||
browser_name,
|
||||
browser_name=None,
|
||||
headless=False,
|
||||
locale_code=None,
|
||||
use_grid=False,
|
||||
|
@ -895,6 +896,7 @@ def get_driver(
|
|||
enable_sync=False,
|
||||
use_auto_ext=False,
|
||||
undetectable=False,
|
||||
uc_subprocess=False,
|
||||
no_sandbox=False,
|
||||
disable_gpu=False,
|
||||
headless2=False,
|
||||
|
@ -919,7 +921,19 @@ def get_driver(
|
|||
device_width=None,
|
||||
device_height=None,
|
||||
device_pixel_ratio=None,
|
||||
browser=None, # A duplicate of browser_name to avoid confusion
|
||||
):
|
||||
if not browser_name:
|
||||
if browser:
|
||||
browser_name = browser
|
||||
else:
|
||||
browser_name = "chrome" # The default if not specified
|
||||
browser_name = browser_name.lower()
|
||||
if headless2 and browser_name == constants.Browser.FIREFOX:
|
||||
headless2 = False # Only for Chromium
|
||||
headless = True
|
||||
if uc_subprocess and not undetectable:
|
||||
undetectable = True
|
||||
proxy_auth = False
|
||||
proxy_user = None
|
||||
proxy_pass = None
|
||||
|
@ -1046,6 +1060,7 @@ def get_driver(
|
|||
enable_sync,
|
||||
use_auto_ext,
|
||||
undetectable,
|
||||
uc_subprocess,
|
||||
no_sandbox,
|
||||
disable_gpu,
|
||||
headless2,
|
||||
|
@ -1091,6 +1106,7 @@ def get_driver(
|
|||
enable_sync,
|
||||
use_auto_ext,
|
||||
undetectable,
|
||||
uc_subprocess,
|
||||
no_sandbox,
|
||||
disable_gpu,
|
||||
headless2,
|
||||
|
@ -1140,6 +1156,7 @@ def get_remote_driver(
|
|||
enable_sync,
|
||||
use_auto_ext,
|
||||
undetectable,
|
||||
uc_subprocess,
|
||||
no_sandbox,
|
||||
disable_gpu,
|
||||
headless2,
|
||||
|
@ -1239,6 +1256,7 @@ def get_remote_driver(
|
|||
enable_sync,
|
||||
use_auto_ext,
|
||||
undetectable,
|
||||
uc_subprocess,
|
||||
no_sandbox,
|
||||
disable_gpu,
|
||||
headless2,
|
||||
|
@ -1467,6 +1485,7 @@ def get_remote_driver(
|
|||
enable_sync,
|
||||
use_auto_ext,
|
||||
undetectable,
|
||||
uc_subprocess,
|
||||
no_sandbox,
|
||||
disable_gpu,
|
||||
headless2,
|
||||
|
@ -1661,6 +1680,7 @@ def get_local_driver(
|
|||
enable_sync,
|
||||
use_auto_ext,
|
||||
undetectable,
|
||||
uc_subprocess,
|
||||
no_sandbox,
|
||||
disable_gpu,
|
||||
headless2,
|
||||
|
@ -2260,6 +2280,7 @@ def get_local_driver(
|
|||
enable_sync,
|
||||
use_auto_ext,
|
||||
undetectable,
|
||||
uc_subprocess,
|
||||
no_sandbox,
|
||||
disable_gpu,
|
||||
headless2,
|
||||
|
@ -2322,6 +2343,7 @@ def get_local_driver(
|
|||
enable_sync,
|
||||
use_auto_ext,
|
||||
undetectable,
|
||||
uc_subprocess,
|
||||
no_sandbox,
|
||||
disable_gpu,
|
||||
headless2,
|
||||
|
@ -2592,6 +2614,7 @@ def get_local_driver(
|
|||
driver_executable_path=uc_path,
|
||||
headless=False, # Xvfb needed!
|
||||
version_main=uc_chrome_version,
|
||||
use_subprocess=uc_subprocess,
|
||||
)
|
||||
except URLError as e:
|
||||
if (
|
||||
|
@ -2609,6 +2632,7 @@ def get_local_driver(
|
|||
driver_executable_path=uc_path,
|
||||
headless=False, # Xvfb needed!
|
||||
version_main=uc_chrome_version,
|
||||
use_subprocess=uc_subprocess,
|
||||
)
|
||||
else:
|
||||
raise
|
||||
|
@ -2700,6 +2724,7 @@ def get_local_driver(
|
|||
enable_sync,
|
||||
use_auto_ext,
|
||||
undetectable,
|
||||
uc_subprocess,
|
||||
no_sandbox,
|
||||
disable_gpu,
|
||||
headless2,
|
||||
|
|
|
@ -330,6 +330,24 @@ def get_test_id(test):
|
|||
scenario_name = scenario_name.split(" -- @")[0]
|
||||
test_id = "%s:%s => %s" % (file_name, line_num, scenario_name)
|
||||
return test_id
|
||||
elif hasattr(test, "is_context_manager") and test.is_context_manager:
|
||||
filename = test.__class__.__module__.split(".")[-1] + ".py"
|
||||
classname = test.__class__.__name__
|
||||
methodname = test._testMethodName
|
||||
context_id = None
|
||||
if filename == "base_case.py" or methodname == "runTest":
|
||||
import traceback
|
||||
|
||||
stack_base = traceback.format_stack()[0].split(", in ")[0]
|
||||
test_base = stack_base.split(", in ")[0].split(os.sep)[-1]
|
||||
if hasattr(test, "cm_filename") and test.cm_filename:
|
||||
filename = test.cm_filename
|
||||
else:
|
||||
filename = test_base.split('"')[0]
|
||||
classname = "SB"
|
||||
methodname = ".py:" + test_base.split(", line ")[-1]
|
||||
context_id = filename.split(".")[0] + methodname + ":" + classname
|
||||
return context_id
|
||||
test_id = None
|
||||
try:
|
||||
test_id = get_test_name(test)
|
||||
|
|
|
@ -1902,13 +1902,24 @@ class BaseCase(unittest.TestCase):
|
|||
):
|
||||
self.__switch_to_newest_window_if_not_blank()
|
||||
|
||||
def click_if_visible(self, selector, by="css selector"):
|
||||
def click_if_visible(self, selector, by="css selector", timeout=0):
|
||||
"""If the page selector exists and is visible, clicks on the element.
|
||||
This method only clicks on the first matching element found.
|
||||
(Use click_visible_elements() to click all matching elements.)"""
|
||||
Use click_visible_elements() to click all matching elements.
|
||||
If a "timeout" is provided, waits that long for the element
|
||||
to appear before giving up and returning without a click()."""
|
||||
self.wait_for_ready_state_complete()
|
||||
if self.is_element_visible(selector, by=by):
|
||||
self.click(selector, by=by)
|
||||
elif timeout > 0:
|
||||
try:
|
||||
self.wait_for_element_visible(
|
||||
selector, by=by, timeout=timeout
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
if self.is_element_visible(selector, by=by):
|
||||
self.click(selector, by=by)
|
||||
|
||||
def click_active_element(self):
|
||||
self.wait_for_ready_state_complete()
|
||||
|
@ -3170,6 +3181,7 @@ class BaseCase(unittest.TestCase):
|
|||
enable_sync=None,
|
||||
use_auto_ext=None,
|
||||
undetectable=None,
|
||||
uc_subprocess=None,
|
||||
no_sandbox=None,
|
||||
disable_gpu=None,
|
||||
headless2=None,
|
||||
|
@ -3218,6 +3230,7 @@ class BaseCase(unittest.TestCase):
|
|||
enable_sync - the option to enable the Chrome Sync feature (Chrome)
|
||||
use_auto_ext - the option to enable Chrome's Automation Extension
|
||||
undetectable - the option to use an undetectable chromedriver
|
||||
uc_subprocess - use the undetectable chromedriver as a subprocess
|
||||
no_sandbox - the option to enable the "No-Sandbox" feature (Chrome)
|
||||
disable_gpu - the option to enable Chrome's "Disable GPU" feature
|
||||
headless2 - the option to use the newer headless mode (Chromium)
|
||||
|
@ -3312,6 +3325,8 @@ class BaseCase(unittest.TestCase):
|
|||
use_auto_ext = self.use_auto_ext
|
||||
if undetectable is None:
|
||||
undetectable = self.undetectable
|
||||
if uc_subprocess is None:
|
||||
uc_subprocess = self.uc_subprocess
|
||||
if no_sandbox is None:
|
||||
no_sandbox = self.no_sandbox
|
||||
if disable_gpu is None:
|
||||
|
@ -3393,6 +3408,7 @@ class BaseCase(unittest.TestCase):
|
|||
enable_sync=enable_sync,
|
||||
use_auto_ext=use_auto_ext,
|
||||
undetectable=undetectable,
|
||||
uc_subprocess=uc_subprocess,
|
||||
no_sandbox=no_sandbox,
|
||||
disable_gpu=disable_gpu,
|
||||
headless2=headless2,
|
||||
|
@ -3417,6 +3433,7 @@ class BaseCase(unittest.TestCase):
|
|||
device_width=d_width,
|
||||
device_height=d_height,
|
||||
device_pixel_ratio=d_p_r,
|
||||
browser=browser_name,
|
||||
)
|
||||
self._drivers_list.append(new_driver)
|
||||
self._drivers_browser_map[new_driver] = browser_name
|
||||
|
@ -4555,6 +4572,23 @@ class BaseCase(unittest.TestCase):
|
|||
filename = self.__get_filename()
|
||||
classname = self.__class__.__name__
|
||||
methodname = self._testMethodName
|
||||
context_filename = None
|
||||
if (
|
||||
hasattr(sb_config, "is_context_manager")
|
||||
and sb_config.is_context_manager
|
||||
and (filename == "base_case.py" or methodname == "runTest")
|
||||
):
|
||||
import traceback
|
||||
|
||||
stack_base = traceback.format_stack()[0].split(os.sep)[-1]
|
||||
test_base = stack_base.split(", in ")[0]
|
||||
if hasattr(self, "cm_filename") and self.cm_filename:
|
||||
filename = self.cm_filename
|
||||
else:
|
||||
filename = test_base.split('"')[0]
|
||||
classname = "SB"
|
||||
methodname = "test_line_" + test_base.split(", line ")[-1]
|
||||
context_filename = filename.split(".")[0] + "_rec.py"
|
||||
if hasattr(self, "is_behave") and self.is_behave:
|
||||
classname = sb_config.behave_feature.name
|
||||
classname = classname.replace("/", " ").replace(" & ", " ")
|
||||
|
@ -4611,6 +4645,8 @@ class BaseCase(unittest.TestCase):
|
|||
file_name = sb_config.behave_scenario.filename.replace(".", "_")
|
||||
file_name = file_name.split("/")[-1].split("\\")[-1]
|
||||
file_name = file_name + "_rec.py"
|
||||
elif context_filename:
|
||||
file_name = context_filename
|
||||
file_path = os.path.join(recordings_folder, file_name)
|
||||
out_file = codecs.open(file_path, "w+", "utf-8")
|
||||
out_file.writelines("\r\n".join(data))
|
||||
|
@ -5292,19 +5328,41 @@ class BaseCase(unittest.TestCase):
|
|||
pass
|
||||
self.__demo_mode_pause_if_active()
|
||||
|
||||
def js_click_if_present(self, selector, by="css selector"):
|
||||
def js_click_if_present(self, selector, by="css selector", timeout=0):
|
||||
"""If the page selector exists, js_click() the element.
|
||||
This method only clicks on the first matching element found."""
|
||||
This method only clicks on the first matching element found.
|
||||
If a "timeout" is provided, waits that long for the element to
|
||||
be present before giving up and returning without a js_click()."""
|
||||
self.wait_for_ready_state_complete()
|
||||
if self.is_element_present(selector, by=by):
|
||||
self.js_click(selector, by=by)
|
||||
elif timeout > 0:
|
||||
try:
|
||||
self.wait_for_element_present(
|
||||
selector, by=by, timeout=timeout
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
if self.is_element_present(selector, by=by):
|
||||
self.js_click(selector, by=by)
|
||||
|
||||
def js_click_if_visible(self, selector, by="css selector"):
|
||||
def js_click_if_visible(self, selector, by="css selector", timeout=0):
|
||||
"""If the page selector exists and is visible, js_click() the element.
|
||||
This method only clicks on the first matching element found."""
|
||||
This method only clicks on the first matching element found.
|
||||
If a "timeout" is provided, waits that long for the element
|
||||
to appear before giving up and returning without a js_click()."""
|
||||
self.wait_for_ready_state_complete()
|
||||
if self.is_element_visible(selector, by=by):
|
||||
self.js_click(selector, by=by)
|
||||
elif timeout > 0:
|
||||
try:
|
||||
self.wait_for_element_visible(
|
||||
selector, by=by, timeout=timeout
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
if self.is_element_visible(selector, by=by):
|
||||
self.js_click(selector, by=by)
|
||||
|
||||
def js_click_all(self, selector, by="css selector"):
|
||||
"""Clicks all matching elements using pure JS. (No jQuery)"""
|
||||
|
@ -11436,16 +11494,14 @@ class BaseCase(unittest.TestCase):
|
|||
|
||||
page_domain = self.get_domain_url(page_url)
|
||||
page_data_domain = self.get_domain_url(page_url_data)
|
||||
unittest.TestCase.maxDiff = 3200
|
||||
unittest.TestCase.maxDiff = 65536 # 2^16
|
||||
if level != 0 and check_domain:
|
||||
self.assertEqual(page_data_domain, page_domain, domain_fail)
|
||||
unittest.TestCase.maxDiff = 6400 # Use `None` for no limit
|
||||
if level == 3:
|
||||
if not full_diff:
|
||||
self.__assert_eq(level_3_data, level_3, level_3_failure)
|
||||
else:
|
||||
self.assertEqual(level_3_data, level_3, level_3_failure)
|
||||
unittest.TestCase.maxDiff = 3200
|
||||
if level == 2:
|
||||
if not full_diff:
|
||||
self.__assert_eq(level_2_data, level_2, level_2_failure)
|
||||
|
@ -11456,10 +11512,8 @@ class BaseCase(unittest.TestCase):
|
|||
self.__assert_eq(level_1_data, level_1, level_1_failure)
|
||||
else:
|
||||
self.assertEqual(level_1_data, level_1, level_1_failure)
|
||||
unittest.TestCase.maxDiff = 6400 # Use `None` for no limit
|
||||
if level == 0:
|
||||
try:
|
||||
unittest.TestCase.maxDiff = 3200
|
||||
if check_domain:
|
||||
self.assertEqual(
|
||||
page_domain, page_data_domain, domain_fail
|
||||
|
@ -11486,7 +11540,6 @@ class BaseCase(unittest.TestCase):
|
|||
)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
unittest.TestCase.maxDiff = 6400 # Use `None` for no limit
|
||||
if not full_diff:
|
||||
self.__assert_eq(
|
||||
level_3_data, level_3, level_3_failure
|
||||
|
@ -12517,6 +12570,7 @@ class BaseCase(unittest.TestCase):
|
|||
self.display = Display(visible=0, size=(width, height))
|
||||
self.display.start()
|
||||
self.headless_active = True
|
||||
sb_config.headless_active = True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
@ -12602,6 +12656,7 @@ class BaseCase(unittest.TestCase):
|
|||
self.with_selenium = sb_config.with_selenium # Should be True
|
||||
self.headless = sb_config.headless
|
||||
self.headless_active = False
|
||||
sb_config.headless_active = False
|
||||
self.headed = sb_config.headed
|
||||
self.xvfb = sb_config.xvfb
|
||||
self.locale_code = sb_config.locale_code
|
||||
|
@ -12659,6 +12714,7 @@ class BaseCase(unittest.TestCase):
|
|||
self.enable_sync = sb_config.enable_sync
|
||||
self.use_auto_ext = sb_config.use_auto_ext
|
||||
self.undetectable = sb_config.undetectable
|
||||
self.uc_subprocess = sb_config.uc_subprocess
|
||||
self.no_sandbox = sb_config.no_sandbox
|
||||
self.disable_gpu = sb_config.disable_gpu
|
||||
self.headless2 = sb_config.headless2
|
||||
|
@ -12950,6 +13006,7 @@ class BaseCase(unittest.TestCase):
|
|||
enable_sync=self.enable_sync,
|
||||
use_auto_ext=self.use_auto_ext,
|
||||
undetectable=self.undetectable,
|
||||
uc_subprocess=self.uc_subprocess,
|
||||
no_sandbox=self.no_sandbox,
|
||||
disable_gpu=self.disable_gpu,
|
||||
headless2=self.headless2,
|
||||
|
@ -13208,6 +13265,11 @@ class BaseCase(unittest.TestCase):
|
|||
has_exception = False
|
||||
if hasattr(sys, "last_traceback") and sys.last_traceback is not None:
|
||||
has_exception = True
|
||||
elif hasattr(self, "is_context_manager") and self.is_context_manager:
|
||||
if self.with_testing_base and self._has_failure:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
elif python3 and hasattr(self, "_outcome"):
|
||||
if hasattr(self._outcome, "errors") and self._outcome.errors:
|
||||
has_exception = True
|
||||
|
@ -13240,6 +13302,22 @@ class BaseCase(unittest.TestCase):
|
|||
scenario_name = scenario_name.replace(" ", "_")
|
||||
test_id = "%s.%s" % (file_name, scenario_name)
|
||||
return test_id
|
||||
elif hasattr(self, "is_context_manager") and self.is_context_manager:
|
||||
filename = self.__class__.__module__.split(".")[-1] + ".py"
|
||||
methodname = self._testMethodName
|
||||
context_id = None
|
||||
if filename == "base_case.py" or methodname == "runTest":
|
||||
import traceback
|
||||
|
||||
stack_base = traceback.format_stack()[0].split(", in ")[0]
|
||||
test_base = stack_base.split(", in ")[0].split(os.sep)[-1]
|
||||
if hasattr(self, "cm_filename") and self.cm_filename:
|
||||
filename = self.cm_filename
|
||||
else:
|
||||
filename = test_base.split('"')[0]
|
||||
methodname = ".line_" + test_base.split(", line ")[-1]
|
||||
context_id = filename.split(".")[0] + methodname
|
||||
return context_id
|
||||
test_id = "%s.%s.%s" % (
|
||||
self.__class__.__module__,
|
||||
self.__class__.__name__,
|
||||
|
|
|
@ -7,6 +7,7 @@ import ast
|
|||
import sys
|
||||
import time
|
||||
from nose.plugins import Plugin
|
||||
from seleniumbase import config as sb_config
|
||||
from seleniumbase.config import settings
|
||||
from seleniumbase.core import download_helper
|
||||
from seleniumbase.core import log_helper
|
||||
|
@ -200,10 +201,12 @@ class Base(Plugin):
|
|||
archive_logs = options.archive_logs
|
||||
log_helper.log_folder_setup(log_path, archive_logs)
|
||||
download_helper.reset_downloads_folder()
|
||||
sb_config.is_nosetest = True
|
||||
if self.report_on:
|
||||
report_helper.clear_out_old_report_logs(archive_past_runs=False)
|
||||
|
||||
def beforeTest(self, test):
|
||||
sb_config._context_of_runner = False # Context Manager Compatibility
|
||||
variables = self.options.variables
|
||||
if variables and type(variables) is str and len(variables) > 0:
|
||||
bad_input = False
|
||||
|
|
|
@ -0,0 +1,366 @@
|
|||
from contextlib import contextmanager
|
||||
|
||||
|
||||
@contextmanager # Usage: -> ``with Driver() as driver:``
|
||||
def Driver(
|
||||
browser=None, # Choose from "chrome", "edge", "firefox", or "safari".
|
||||
headless=None, # The original headless mode for Chromium and Firefox.
|
||||
headless2=None, # Chromium's new headless mode. (Has more features)
|
||||
headed=None, # Run tests in headed/GUI mode on Linux, where not default.
|
||||
locale_code=None, # Set the Language Locale Code for the web browser.
|
||||
protocol=None, # The Selenium Grid protocol: "http" or "https".
|
||||
servername=None, # The Selenium Grid server/IP used for tests.
|
||||
port=None, # The Selenium Grid port used by the test server.
|
||||
proxy=None, # Use proxy. Format: "SERVER:PORT" or "USER:PASS@SERVER:PORT".
|
||||
proxy_bypass_list=None, # Skip proxy when using the listed domains.
|
||||
proxy_pac_url=None, # Use PAC file. (Format: URL or USERNAME:PASSWORD@URL)
|
||||
agent=None, # Modify the web browser's User-Agent string.
|
||||
cap_file=None, # The desired capabilities to use with a Selenium Grid.
|
||||
cap_string=None, # The desired capabilities to use with a Selenium Grid.
|
||||
recorder_ext=None, # Enables the SeleniumBase Recorder Chromium extension.
|
||||
disable_js=None, # Disable JavaScript on websites. Pages might break!
|
||||
disable_csp=None, # Disable the Content Security Policy of websites.
|
||||
enable_ws=None, # Enable Web Security on Chromium-based browsers.
|
||||
enable_sync=None, # Enable "Chrome Sync" on websites.
|
||||
use_auto_ext=None, # Use Chrome's automation extension.
|
||||
undetectable=None, # Use undetected-chromedriver to evade bot-detection.
|
||||
uc_subprocess=None, # Use undetected-chromedriver as a subprocess.
|
||||
no_sandbox=None, # (DEPRECATED) - "--no-sandbox" is always used now.
|
||||
disable_gpu=None, # (DEPRECATED) - GPU is disabled if no "swiftshader".
|
||||
incognito=None, # Enable Chromium's Incognito mode.
|
||||
guest_mode=None, # Enable Chromium's Guest mode.
|
||||
devtools=None, # Open Chromium's DevTools when the browser opens.
|
||||
remote_debug=None, # Enable Chrome's Debugger on "http://localhost:9222".
|
||||
swiftshader=None, # Use Chrome's "--use-gl=swiftshader" feature.
|
||||
ad_block_on=None, # Block some types of display ads from loading.
|
||||
block_images=None, # Block images from loading during tests.
|
||||
do_not_track=None, # Tell websites that you don't want to be tracked.
|
||||
chromium_arg=None, # "ARG=N,ARG2" (Set Chromium args, ","-separated.)
|
||||
firefox_arg=None, # "ARG=N,ARG2" (Set Firefox args, comma-separated.)
|
||||
firefox_pref=None, # SET (Set Firefox PREFERENCE:VALUE set, ","-separated)
|
||||
user_data_dir=None, # Set the Chrome user data directory to use.
|
||||
extension_zip=None, # Load a Chrome Extension .zip|.crx, comma-separated.)
|
||||
extension_dir=None, # Load a Chrome Extension directory, comma-separated.)
|
||||
page_load_strategy=None, # Set Chrome PLS to "normal", "eager", or "none".
|
||||
external_pdf=None, # Set Chrome "plugins.always_open_pdf_externally":True.
|
||||
is_mobile=None, # Use the mobile device emulator while running tests.
|
||||
d_width=None, # Set device width
|
||||
d_height=None, # Set device height
|
||||
d_p_r=None, # Set device pixel ratio
|
||||
uc=None, # Shortcut / Duplicate of "undetectable" to avoid confusion.
|
||||
undetected=None, # Duplicate of "undetectable" to avoid confusion.
|
||||
uc_sub=None, # Duplicate of "uc_subprocess" to avoid confusion.
|
||||
):
|
||||
""" Context Manager for the SeleniumBase Driver Manager.
|
||||
Usage example:
|
||||
from seleniumbase import Driver
|
||||
with Driver() as driver:
|
||||
driver.get("https://google.com/ncr")
|
||||
# The browser exits automatically after the "with" block ends.
|
||||
"""
|
||||
import sys
|
||||
from seleniumbase.fixtures import constants
|
||||
|
||||
sys_argv = sys.argv
|
||||
browser_changes = 0
|
||||
browser_set = None
|
||||
browser_text = None
|
||||
browser_list = []
|
||||
# As a shortcut, you can use "--edge" instead of "--browser=edge", etc,
|
||||
# but you can only specify one default browser for tests. (Default: chrome)
|
||||
if "--browser=chrome" in sys_argv or "--browser chrome" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "chrome"
|
||||
browser_list.append("--browser=chrome")
|
||||
if "--browser=edge" in sys_argv or "--browser edge" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "edge"
|
||||
browser_list.append("--browser=edge")
|
||||
if "--browser=firefox" in sys_argv or "--browser firefox" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "firefox"
|
||||
browser_list.append("--browser=firefox")
|
||||
if "--browser=opera" in sys_argv or "--browser opera" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "opera"
|
||||
browser_list.append("--browser=opera")
|
||||
if "--browser=safari" in sys_argv or "--browser safari" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "safari"
|
||||
browser_list.append("--browser=safari")
|
||||
if "--browser=ie" in sys_argv or "--browser ie" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "ie"
|
||||
browser_list.append("--browser=ie")
|
||||
if "--browser=phantomjs" in sys_argv or "--browser phantomjs" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "phantomjs"
|
||||
browser_list.append("--browser=phantomjs")
|
||||
if "--browser=remote" in sys_argv or "--browser remote" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "remote"
|
||||
browser_list.append("--browser=remote")
|
||||
browser_text = browser_set
|
||||
if "--chrome" in sys_argv and not browser_set == "chrome":
|
||||
browser_changes += 1
|
||||
browser_text = "chrome"
|
||||
browser_list.append("--chrome")
|
||||
if "--edge" in sys_argv and not browser_set == "edge":
|
||||
browser_changes += 1
|
||||
browser_text = "edge"
|
||||
browser_list.append("--edge")
|
||||
if "--firefox" in sys_argv and not browser_set == "firefox":
|
||||
browser_changes += 1
|
||||
browser_text = "firefox"
|
||||
browser_list.append("--firefox")
|
||||
if "--ie" in sys_argv and not browser_set == "ie":
|
||||
browser_changes += 1
|
||||
browser_text = "ie"
|
||||
browser_list.append("--ie")
|
||||
if "--opera" in sys_argv and not browser_set == "opera":
|
||||
browser_changes += 1
|
||||
browser_text = "opera"
|
||||
browser_list.append("--opera")
|
||||
if "--safari" in sys_argv and not browser_set == "safari":
|
||||
browser_changes += 1
|
||||
browser_text = "safari"
|
||||
browser_list.append("--safari")
|
||||
if browser_changes > 1:
|
||||
message = "\n\n TOO MANY browser types were entered!"
|
||||
message += "\n There were %s found:\n > %s" % (
|
||||
browser_changes,
|
||||
", ".join(browser_list),
|
||||
)
|
||||
message += "\n ONLY ONE default browser is allowed!"
|
||||
message += "\n Select a single browser & try again!\n"
|
||||
if not browser:
|
||||
raise Exception(message)
|
||||
if browser is None:
|
||||
if browser_text:
|
||||
browser = browser_text
|
||||
else:
|
||||
browser = "chrome"
|
||||
else:
|
||||
browser = browser.lower()
|
||||
valid_browsers = constants.ValidBrowsers.valid_browsers
|
||||
if browser not in valid_browsers:
|
||||
raise Exception(
|
||||
"Browser: {%s} is not a valid browser option. "
|
||||
"Valid options = {%s}" % (browser, valid_browsers)
|
||||
)
|
||||
if headless is None:
|
||||
if "--headless" in sys_argv:
|
||||
headless = True
|
||||
else:
|
||||
headless = False
|
||||
if headless2 is None:
|
||||
if "--headless2" in sys_argv:
|
||||
headless2 = True
|
||||
else:
|
||||
headless2 = False
|
||||
if protocol is None:
|
||||
protocol = "http" # For the Selenium Grid only!
|
||||
if servername is None:
|
||||
servername = "localhost" # For the Selenium Grid only!
|
||||
use_grid = False
|
||||
if servername != "localhost":
|
||||
# Use Selenium Grid (Use "127.0.0.1" for localhost Grid)
|
||||
use_grid = True
|
||||
if port is None:
|
||||
port = "4444" # For the Selenium Grid only!
|
||||
if incognito is None:
|
||||
if "--incognito" in sys_argv:
|
||||
incognito = True
|
||||
else:
|
||||
incognito = False
|
||||
if guest_mode is None:
|
||||
if "--guest" in sys_argv:
|
||||
guest_mode = True
|
||||
else:
|
||||
guest_mode = False
|
||||
if devtools is None:
|
||||
if "--devtools" in sys_argv:
|
||||
devtools = True
|
||||
else:
|
||||
devtools = False
|
||||
if is_mobile is None:
|
||||
if "--mobile" in sys_argv:
|
||||
is_mobile = True
|
||||
else:
|
||||
is_mobile = False
|
||||
test_id = "direct_driver"
|
||||
proxy_string = proxy
|
||||
user_agent = agent
|
||||
recorder_mode = False
|
||||
if recorder_ext:
|
||||
recorder_mode = True
|
||||
if (
|
||||
"--recorder" in sys_argv
|
||||
or "--record" in sys_argv
|
||||
or "--rec" in sys_argv
|
||||
):
|
||||
recorder_mode = True
|
||||
recorder_ext = True
|
||||
if (
|
||||
"linux" in sys.platform
|
||||
and not headed
|
||||
and not headless
|
||||
and not headless2
|
||||
):
|
||||
headless = True
|
||||
if recorder_mode and headless:
|
||||
headless = False
|
||||
headless2 = True
|
||||
if headless2 and browser == "firefox":
|
||||
headless2 = False # Only for Chromium browsers
|
||||
headless = True # Firefox has regular headless
|
||||
elif browser not in ["chrome", "edge"]:
|
||||
headless2 = False # Only for Chromium browsers
|
||||
if disable_csp is None:
|
||||
disable_csp = False
|
||||
if enable_ws is None:
|
||||
enable_ws = False
|
||||
if enable_sync is None:
|
||||
enable_sync = False
|
||||
if (
|
||||
enable_ws is None
|
||||
or (enable_ws is not None and enable_ws)
|
||||
):
|
||||
enable_ws = True
|
||||
else:
|
||||
enable_ws = False
|
||||
if undetectable or undetected or uc or uc_subprocess or uc_sub:
|
||||
undetectable = True
|
||||
elif (
|
||||
"--undetectable" in sys_argv
|
||||
or "--undetected" in sys_argv
|
||||
or "--uc" in sys_argv
|
||||
or "--uc-subprocess" in sys_argv
|
||||
or "--uc_subprocess" in sys_argv
|
||||
or "--uc-sub" in sys_argv
|
||||
):
|
||||
undetectable = True
|
||||
else:
|
||||
undetectable = False
|
||||
if uc_subprocess or uc_sub:
|
||||
uc_subprocess = True
|
||||
elif (
|
||||
"--uc-subprocess" in sys_argv
|
||||
or "--uc_subprocess" in sys_argv
|
||||
or "--uc-sub" in sys_argv
|
||||
):
|
||||
uc_subprocess = True
|
||||
else:
|
||||
uc_subprocess = False
|
||||
if use_auto_ext is None:
|
||||
if "--use-auto-ext" in sys_argv:
|
||||
use_auto_ext = True
|
||||
else:
|
||||
use_auto_ext = False
|
||||
if disable_js is None:
|
||||
if "--disable-js" in sys_argv:
|
||||
disable_js = True
|
||||
else:
|
||||
disable_js = False
|
||||
if page_load_strategy is not None:
|
||||
if page_load_strategy.lower() not in ["normal", "eager", "none"]:
|
||||
raise Exception(
|
||||
'page_load_strategy must be "normal", "eager", or "none"!'
|
||||
)
|
||||
page_load_strategy = page_load_strategy.lower()
|
||||
elif "--pls=normal" in sys_argv or '--pls="normal"' in sys_argv:
|
||||
page_load_strategy = "normal"
|
||||
elif "--pls=eager" in sys_argv or '--pls="eager"' in sys_argv:
|
||||
page_load_strategy = "eager"
|
||||
elif "--pls=none" in sys_argv or '--pls="none"' in sys_argv:
|
||||
page_load_strategy = "none"
|
||||
if block_images is None:
|
||||
if "--block-images" in sys_argv:
|
||||
block_images = True
|
||||
else:
|
||||
block_images = False
|
||||
if do_not_track is None:
|
||||
if "--do-not-track" in sys_argv:
|
||||
do_not_track = True
|
||||
else:
|
||||
do_not_track = False
|
||||
if external_pdf is None:
|
||||
if "--external-pdf" in sys_argv:
|
||||
external_pdf = True
|
||||
else:
|
||||
external_pdf = False
|
||||
if remote_debug is None:
|
||||
if "--remote-debug" in sys_argv:
|
||||
remote_debug = True
|
||||
else:
|
||||
remote_debug = False
|
||||
if swiftshader is None:
|
||||
if "--swiftshader" in sys_argv:
|
||||
swiftshader = True
|
||||
else:
|
||||
swiftshader = False
|
||||
if ad_block_on is None:
|
||||
if "--ad-block" in sys_argv:
|
||||
ad_block_on = True
|
||||
else:
|
||||
ad_block_on = False
|
||||
browser_name = browser
|
||||
|
||||
# Launch a web browser
|
||||
from seleniumbase.core import browser_launcher
|
||||
|
||||
driver = browser_launcher.get_driver(
|
||||
browser_name=browser_name,
|
||||
headless=headless,
|
||||
locale_code=locale_code,
|
||||
use_grid=use_grid,
|
||||
protocol=protocol,
|
||||
servername=servername,
|
||||
port=port,
|
||||
proxy_string=proxy_string,
|
||||
proxy_bypass_list=proxy_bypass_list,
|
||||
proxy_pac_url=proxy_pac_url,
|
||||
user_agent=user_agent,
|
||||
cap_file=cap_file,
|
||||
cap_string=cap_string,
|
||||
recorder_ext=recorder_ext,
|
||||
disable_js=disable_js,
|
||||
disable_csp=disable_csp,
|
||||
enable_ws=enable_ws,
|
||||
enable_sync=enable_sync,
|
||||
use_auto_ext=use_auto_ext,
|
||||
undetectable=undetectable,
|
||||
uc_subprocess=uc_subprocess,
|
||||
no_sandbox=no_sandbox,
|
||||
disable_gpu=disable_gpu,
|
||||
headless2=headless2,
|
||||
incognito=incognito,
|
||||
guest_mode=guest_mode,
|
||||
devtools=devtools,
|
||||
remote_debug=remote_debug,
|
||||
swiftshader=swiftshader,
|
||||
ad_block_on=ad_block_on,
|
||||
block_images=block_images,
|
||||
do_not_track=do_not_track,
|
||||
chromium_arg=chromium_arg,
|
||||
firefox_arg=firefox_arg,
|
||||
firefox_pref=firefox_pref,
|
||||
user_data_dir=user_data_dir,
|
||||
extension_zip=extension_zip,
|
||||
extension_dir=extension_dir,
|
||||
page_load_strategy=page_load_strategy,
|
||||
external_pdf=external_pdf,
|
||||
test_id=test_id,
|
||||
mobile_emulator=is_mobile,
|
||||
device_width=d_width,
|
||||
device_height=d_height,
|
||||
device_pixel_ratio=d_p_r,
|
||||
browser=browser_name,
|
||||
)
|
||||
try:
|
||||
yield driver
|
||||
finally:
|
||||
try:
|
||||
driver.quit()
|
||||
except Exception:
|
||||
pass
|
|
@ -90,7 +90,8 @@ def pytest_addoption(parser):
|
|||
--enable-ws (Enable Web Security on Chromium-based browsers.)
|
||||
--enable-sync (Enable "Chrome Sync" on websites.)
|
||||
--use-auto-ext (Use Chrome's automation extension.)
|
||||
--undetected | --uc (Use undetected-chromedriver to evade bot-detection.)
|
||||
--uc | --undetected (Use undetected-chromedriver to evade bot-detection.)
|
||||
--uc-sub | --uc-subprocess (Use undetected-chromedriver as a subprocess.)
|
||||
--remote-debug (Enable Chrome's Remote Debugger on http://localhost:9222)
|
||||
--final-debug (Enter Debug Mode after each test ends. Don't use with CI!)
|
||||
--dashboard (Enable the SeleniumBase Dashboard. Saved at: dashboard.html)
|
||||
|
@ -910,6 +911,17 @@ def pytest_addoption(parser):
|
|||
to websites that use anti-bot services to block
|
||||
automation tools from navigating them freely.""",
|
||||
)
|
||||
parser.addoption(
|
||||
"--uc_subprocess",
|
||||
"--uc-subprocess",
|
||||
"--uc-sub", # undetected-chromedriver subprocess mode
|
||||
action="store_true",
|
||||
dest="uc_subprocess",
|
||||
default=False,
|
||||
help="""Use undetectable-chromedriver as a subprocess,
|
||||
which can help avoid issues that might result.
|
||||
It may reduce UC's ability to avoid detection.""",
|
||||
)
|
||||
parser.addoption(
|
||||
"--no_sandbox",
|
||||
"--no-sandbox",
|
||||
|
@ -1223,7 +1235,7 @@ def pytest_addoption(parser):
|
|||
browser_list.append("--opera")
|
||||
if "--safari" in sys_argv and not browser_set == "safari":
|
||||
browser_changes += 1
|
||||
browser_text = "opera"
|
||||
browser_text = "safari"
|
||||
sb_config._browser_shortcut = "safari"
|
||||
browser_list.append("--safari")
|
||||
if browser_changes > 1:
|
||||
|
@ -1252,6 +1264,9 @@ def pytest_addoption(parser):
|
|||
"--undetected" in sys_argv
|
||||
or "--undetectable" in sys_argv
|
||||
or "--uc" in sys_argv
|
||||
or "--uc-subprocess" in sys_argv
|
||||
or "--uc_subprocess" in sys_argv
|
||||
or "--uc-sub" in sys_argv
|
||||
)
|
||||
):
|
||||
message = (
|
||||
|
@ -1270,6 +1285,9 @@ def pytest_configure(config):
|
|||
sb_config.item_count_skipped = 0
|
||||
sb_config.item_count_untested = 0
|
||||
sb_config.is_pytest = True
|
||||
sb_config.is_behave = False
|
||||
sb_config.is_nosetest = False
|
||||
sb_config.is_context_manager = False
|
||||
sb_config.pytest_config = config
|
||||
sb_config.browser = config.getoption("browser")
|
||||
if sb_config._browser_shortcut:
|
||||
|
@ -1287,7 +1305,10 @@ def pytest_configure(config):
|
|||
sb_config.device_metrics = config.getoption("device_metrics")
|
||||
sb_config.headless = config.getoption("headless")
|
||||
sb_config.headless2 = config.getoption("headless2")
|
||||
if sb_config.browser not in ["chrome", "edge"]:
|
||||
if sb_config.headless2 and sb_config.browser == "firefox":
|
||||
sb_config.headless2 = False # Only for Chromium browsers
|
||||
sb_config.headless = True # Firefox has regular headless
|
||||
elif sb_config.browser not in ["chrome", "edge"]:
|
||||
sb_config.headless2 = False # Only for Chromium browsers
|
||||
sb_config.headed = config.getoption("headed")
|
||||
sb_config.xvfb = config.getoption("xvfb")
|
||||
|
@ -1363,6 +1384,9 @@ def pytest_configure(config):
|
|||
sb_config.enable_sync = config.getoption("enable_sync")
|
||||
sb_config.use_auto_ext = config.getoption("use_auto_ext")
|
||||
sb_config.undetectable = config.getoption("undetectable")
|
||||
sb_config.uc_subprocess = config.getoption("uc_subprocess")
|
||||
if sb_config.uc_subprocess and not sb_config.undetectable:
|
||||
sb_config.undetectable = True
|
||||
sb_config.no_sandbox = config.getoption("no_sandbox")
|
||||
sb_config.disable_gpu = config.getoption("disable_gpu")
|
||||
sb_config.remote_debug = config.getoption("remote_debug")
|
||||
|
@ -1457,11 +1481,6 @@ def pytest_configure(config):
|
|||
sb_config.recorder_mode = False
|
||||
sb_config.recorder_ext = False
|
||||
|
||||
# Recorder Mode can still optimize scripts in --headless2 mode.
|
||||
if sb_config.recorder_mode and sb_config.headless:
|
||||
sb_config.headless = False
|
||||
sb_config.headless2 = True
|
||||
|
||||
if sb_config.xvfb and "linux" not in sys.platform:
|
||||
# The Xvfb virtual display server is for Linux OS Only!
|
||||
sb_config.xvfb = False
|
||||
|
@ -1480,6 +1499,12 @@ def pytest_configure(config):
|
|||
"or by calling the new --headless2.)"
|
||||
)
|
||||
sb_config.headless = True
|
||||
|
||||
# Recorder Mode can still optimize scripts in --headless2 mode.
|
||||
if sb_config.recorder_mode and sb_config.headless:
|
||||
sb_config.headless = False
|
||||
sb_config.headless2 = True
|
||||
|
||||
if not sb_config.headless and not sb_config.headless2:
|
||||
sb_config.headed = True
|
||||
|
||||
|
@ -1605,6 +1630,7 @@ def pytest_collection_finish(session):
|
|||
"""This runs after item collection is finalized.
|
||||
https://docs.pytest.org/en/stable/reference.html
|
||||
"""
|
||||
sb_config._context_of_runner = False # Context Manager Compatibility
|
||||
if "--co" in sys_argv or "--collect-only" in sys_argv:
|
||||
return
|
||||
if len(session.items) > 0 and not sb_config._multithreaded:
|
||||
|
@ -1694,14 +1720,20 @@ def pytest_runtest_teardown(item):
|
|||
if hasattr(self, "xvfb") and self.xvfb:
|
||||
if self.headless_active and "--pdb" not in sys_argv:
|
||||
if hasattr(self, "display") and self.display:
|
||||
self.headless_active = False
|
||||
sb_config.headless_active = False
|
||||
self.display.stop()
|
||||
elif hasattr(self, "headless") and self.headless:
|
||||
if self.headless_active and "--pdb" not in sys_argv:
|
||||
if hasattr(self, "display") and self.display:
|
||||
self.headless_active = False
|
||||
sb_config.headless_active = False
|
||||
self.display.stop()
|
||||
elif hasattr(self, "headless2") and self.headless2:
|
||||
if self.headless_active and "--pdb" not in sys_argv:
|
||||
if hasattr(self, "display") and self.display:
|
||||
self.headless_active = False
|
||||
sb_config.headless_active = False
|
||||
self.display.stop()
|
||||
except Exception:
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,800 @@
|
|||
from contextlib import contextmanager
|
||||
|
||||
|
||||
@contextmanager # Usage: -> ``with SB() as sb:``
|
||||
def SB(
|
||||
test=None, # Test Mode: Output, Logging, Continue on failure unless "rtf".
|
||||
raise_test_failure=None, # In "test" mode, raise Exception at 1st failure.
|
||||
rtf=None, # Short form of "raise_test_failure". (Less typing, same thing!)
|
||||
browser=None, # Choose from "chrome", "edge", "firefox", or "safari".
|
||||
headless=None, # The original headless mode for Chromium and Firefox.
|
||||
headless2=None, # Chromium's new headless mode. (Has more features)
|
||||
locale_code=None, # Set the Language Locale Code for the web browser.
|
||||
protocol=None, # The Selenium Grid protocol: "http" or "https".
|
||||
servername=None, # The Selenium Grid server/IP used for tests.
|
||||
port=None, # The Selenium Grid port used by the test server.
|
||||
proxy=None, # Use proxy. Format: "SERVER:PORT" or "USER:PASS@SERVER:PORT".
|
||||
proxy_bypass_list=None, # Skip proxy when using the listed domains.
|
||||
proxy_pac_url=None, # Use PAC file. (Format: URL or USERNAME:PASSWORD@URL)
|
||||
agent=None, # Modify the web browser's User-Agent string.
|
||||
cap_file=None, # The desired capabilities to use with a Selenium Grid.
|
||||
cap_string=None, # The desired capabilities to use with a Selenium Grid.
|
||||
recorder_ext=None, # Enables the SeleniumBase Recorder Chromium extension.
|
||||
disable_js=None, # Disable JavaScript on websites. Pages might break!
|
||||
disable_csp=None, # Disable the Content Security Policy of websites.
|
||||
enable_ws=None, # Enable Web Security on Chromium-based browsers.
|
||||
enable_sync=None, # Enable "Chrome Sync" on websites.
|
||||
use_auto_ext=None, # Use Chrome's automation extension.
|
||||
undetectable=None, # Use undetected-chromedriver to evade bot-detection.
|
||||
uc_subprocess=None, # Use undetected-chromedriver as a subprocess.
|
||||
incognito=None, # Enable Chromium's Incognito mode.
|
||||
guest_mode=None, # Enable Chromium's Guest mode.
|
||||
devtools=None, # Open Chromium's DevTools when the browser opens.
|
||||
remote_debug=None, # Enable Chrome's Debugger on "http://localhost:9222".
|
||||
swiftshader=None, # Use Chrome's "--use-gl=swiftshader" feature.
|
||||
ad_block_on=None, # Block some types of display ads from loading.
|
||||
block_images=None, # Block images from loading during tests.
|
||||
do_not_track=None, # Tell websites that you don't want to be tracked.
|
||||
chromium_arg=None, # "ARG=N,ARG2" (Set Chromium args, ","-separated.)
|
||||
firefox_arg=None, # "ARG=N,ARG2" (Set Firefox args, comma-separated.)
|
||||
firefox_pref=None, # SET (Set Firefox PREFERENCE:VALUE set, ","-separated)
|
||||
user_data_dir=None, # Set the Chrome user data directory to use.
|
||||
extension_zip=None, # Load a Chrome Extension .zip|.crx, comma-separated.)
|
||||
extension_dir=None, # Load a Chrome Extension directory, comma-separated.)
|
||||
page_load_strategy=None, # Set Chrome PLS to "normal", "eager", or "none".
|
||||
external_pdf=None, # Set Chrome "plugins.always_open_pdf_externally":True.
|
||||
is_mobile=None, # Use the mobile device emulator while running tests.
|
||||
device_metrics=None, # Set mobile metrics: "CSSWidth,CSSHeight,PixelRatio"
|
||||
xvfb=None, # Run tests using the Xvfb virtual display server on Linux OS.
|
||||
start_page=None, # The starting URL for the web browser when tests begin.
|
||||
rec_print=None, # If Recorder is enabled, prints output after tests end.
|
||||
rec_behave=None, # Like Recorder Mode, but also generates behave-gherkin.
|
||||
record_sleep=None, # If Recorder enabled, also records self.sleep calls.
|
||||
data=None, # Extra test data. Access with "self.data" in tests.
|
||||
var1=None, # Extra test data. Access with "self.var1" in tests.
|
||||
var2=None, # Extra test data. Access with "self.var2" in tests.
|
||||
var3=None, # Extra test data. Access with "self.var3" in tests.
|
||||
variables=None, # DICT (Extra test data. Access with "self.variables")
|
||||
account=None, # Set account. Access with "self.account" in tests.
|
||||
environment=None, # Set the test env. Access with "self.env" in tests.
|
||||
headed=None, # Run tests in headed/GUI mode on Linux, where not default.
|
||||
maximize=None, # Start tests with the browser window maximized.
|
||||
disable_ws=None, # Reverse of "enable_ws". (None and False are different)
|
||||
disable_beforeunload=None, # Disable the "beforeunload" event on Chromium.
|
||||
settings_file=None, # A file for overriding default SeleniumBase settings.
|
||||
uc=None, # Shortcut / Duplicate of "undetectable" to avoid confusion.
|
||||
undetected=None, # Duplicate of "undetectable" to avoid confusion.
|
||||
uc_sub=None, # Duplicate of "uc_subprocess" to avoid confusion.
|
||||
save_screenshot=None, # Save a screenshot at the end of each test.
|
||||
timeout_multiplier=None, # Multiplies the default timeout values.
|
||||
js_checking_on=None, # Check for JavaScript errors after page loads.
|
||||
slow=None, # Slow down the automation. Faster than using Demo Mode.
|
||||
demo=None, # Slow down and visually see test actions as they occur.
|
||||
demo_sleep=None, # SECONDS (Set wait time after Slow & Demo Mode actions.)
|
||||
message_duration=None, # SECONDS (The time length for Messenger alerts.)
|
||||
highlights=None, # Number of highlight animations for Demo Mode actions.
|
||||
interval=None, # SECONDS (Autoplay interval for SB Slides & Tour steps.)
|
||||
time_limit=None, # SECONDS (Safely fail tests that exceed the time limit.)
|
||||
):
|
||||
"""Context Manager for SeleniumBase.
|
||||
Usage example ->
|
||||
from seleniumbase import SB
|
||||
with SB() as sb:
|
||||
sb.open("https://google.com/ncr")
|
||||
sb.type('[name="q"]', "SeleniumBase on GitHub\n")
|
||||
sb.click('a[href*="github.com/seleniumbase"]')
|
||||
sb.highlight("div.Layout-main")
|
||||
sb.highlight("div.Layout-sidebar")
|
||||
sb.sleep(0.5)
|
||||
# The browser exits automatically after the "with" block ends.
|
||||
"""
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from seleniumbase import BaseCase
|
||||
from seleniumbase import config as sb_config
|
||||
from seleniumbase.config import settings
|
||||
from seleniumbase.fixtures import constants
|
||||
|
||||
sb_config_backup = sb_config
|
||||
sys_argv = sys.argv
|
||||
archive_logs = False
|
||||
existing_runner = False
|
||||
do_log_folder_setup = False # The first "test=True" run does it
|
||||
if (
|
||||
(hasattr(sb_config, "is_behave") and sb_config.is_behave)
|
||||
or (hasattr(sb_config, "is_pytest") and sb_config.is_pytest)
|
||||
or (hasattr(sb_config, "is_nosetest") and sb_config.is_nosetest)
|
||||
):
|
||||
existing_runner = True
|
||||
test = False # Already using a test runner. Skip extra test steps.
|
||||
elif test is None and "--test" in sys_argv:
|
||||
test = True
|
||||
if (
|
||||
existing_runner
|
||||
and not hasattr(sb_config, "_context_of_runner")
|
||||
):
|
||||
sb_config._context_of_runner = True
|
||||
if hasattr(sb_config, "is_pytest") and sb_config.is_pytest:
|
||||
print(
|
||||
"\n SB Manager script was triggered by pytest collection!"
|
||||
'\n (Prevent that by using: `if __name__ == "__main__":`)'
|
||||
)
|
||||
elif hasattr(sb_config, "is_nosetest") and sb_config.is_nosetest:
|
||||
print(
|
||||
"\n SB Manager script was triggered by nosetest collection!"
|
||||
'\n (Prevent that by using: ``if __name__ == "__main__":``)'
|
||||
)
|
||||
if (
|
||||
not existing_runner
|
||||
and not hasattr(sb_config, "_has_older_context")
|
||||
and test
|
||||
):
|
||||
# This is the first "test" from context manager scripts run.
|
||||
sb_config._has_older_context = True
|
||||
do_log_folder_setup = True
|
||||
else:
|
||||
if test:
|
||||
pass # Not the first "test" of context manager scripts.
|
||||
else:
|
||||
pass # Not in "test" mode. (No special output/logging.)
|
||||
with_testing_base = False
|
||||
if test:
|
||||
with_testing_base = True
|
||||
if (
|
||||
raise_test_failure
|
||||
or rtf
|
||||
or "--raise-test-failure" in sys_argv
|
||||
or "--rtf" in sys_argv
|
||||
or "-x" in sys_argv # Carry-over from "pytest"
|
||||
or "--exitfirst" in sys_argv # Carry-over from "pytest"
|
||||
):
|
||||
raise_test_failure = True # Exit on first error or failed test.
|
||||
else:
|
||||
raise_test_failure = False
|
||||
browser_changes = 0
|
||||
browser_set = None
|
||||
browser_text = None
|
||||
browser_list = []
|
||||
# As a shortcut, you can use "--edge" instead of "--browser=edge", etc,
|
||||
# but you can only specify one default browser for tests. (Default: chrome)
|
||||
if "--browser=chrome" in sys_argv or "--browser chrome" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "chrome"
|
||||
browser_list.append("--browser=chrome")
|
||||
if "--browser=edge" in sys_argv or "--browser edge" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "edge"
|
||||
browser_list.append("--browser=edge")
|
||||
if "--browser=firefox" in sys_argv or "--browser firefox" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "firefox"
|
||||
browser_list.append("--browser=firefox")
|
||||
if "--browser=opera" in sys_argv or "--browser opera" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "opera"
|
||||
browser_list.append("--browser=opera")
|
||||
if "--browser=safari" in sys_argv or "--browser safari" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "safari"
|
||||
browser_list.append("--browser=safari")
|
||||
if "--browser=ie" in sys_argv or "--browser ie" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "ie"
|
||||
browser_list.append("--browser=ie")
|
||||
if "--browser=phantomjs" in sys_argv or "--browser phantomjs" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "phantomjs"
|
||||
browser_list.append("--browser=phantomjs")
|
||||
if "--browser=remote" in sys_argv or "--browser remote" in sys_argv:
|
||||
browser_changes += 1
|
||||
browser_set = "remote"
|
||||
browser_list.append("--browser=remote")
|
||||
browser_text = browser_set
|
||||
if "--chrome" in sys_argv and not browser_set == "chrome":
|
||||
browser_changes += 1
|
||||
browser_text = "chrome"
|
||||
sb_config._browser_shortcut = "chrome"
|
||||
browser_list.append("--chrome")
|
||||
if "--edge" in sys_argv and not browser_set == "edge":
|
||||
browser_changes += 1
|
||||
browser_text = "edge"
|
||||
sb_config._browser_shortcut = "edge"
|
||||
browser_list.append("--edge")
|
||||
if "--firefox" in sys_argv and not browser_set == "firefox":
|
||||
browser_changes += 1
|
||||
browser_text = "firefox"
|
||||
sb_config._browser_shortcut = "firefox"
|
||||
browser_list.append("--firefox")
|
||||
if "--ie" in sys_argv and not browser_set == "ie":
|
||||
browser_changes += 1
|
||||
browser_text = "ie"
|
||||
sb_config._browser_shortcut = "ie"
|
||||
browser_list.append("--ie")
|
||||
if "--opera" in sys_argv and not browser_set == "opera":
|
||||
browser_changes += 1
|
||||
browser_text = "opera"
|
||||
sb_config._browser_shortcut = "opera"
|
||||
browser_list.append("--opera")
|
||||
if "--safari" in sys_argv and not browser_set == "safari":
|
||||
browser_changes += 1
|
||||
browser_text = "safari"
|
||||
sb_config._browser_shortcut = "safari"
|
||||
browser_list.append("--safari")
|
||||
if browser_changes > 1:
|
||||
message = "\n\n TOO MANY browser types were entered!"
|
||||
message += "\n There were %s found:\n > %s" % (
|
||||
browser_changes,
|
||||
", ".join(browser_list),
|
||||
)
|
||||
message += "\n ONLY ONE default browser is allowed!"
|
||||
message += "\n Select a single browser & try again!\n"
|
||||
if not browser:
|
||||
raise Exception(message)
|
||||
if browser is None:
|
||||
if browser_text:
|
||||
browser = browser_text
|
||||
else:
|
||||
browser = "chrome"
|
||||
else:
|
||||
browser = browser.lower()
|
||||
valid_browsers = constants.ValidBrowsers.valid_browsers
|
||||
if browser not in valid_browsers:
|
||||
raise Exception(
|
||||
"Browser: {%s} is not a valid browser option. "
|
||||
"Valid options = {%s}" % (browser, valid_browsers)
|
||||
)
|
||||
if headless is None:
|
||||
if "--headless" in sys_argv:
|
||||
headless = True
|
||||
else:
|
||||
headless = False
|
||||
if headless2 is None:
|
||||
if "--headless2" in sys_argv:
|
||||
headless2 = True
|
||||
else:
|
||||
headless2 = False
|
||||
if protocol is None:
|
||||
protocol = "http" # For the Selenium Grid only!
|
||||
if servername is None:
|
||||
servername = "localhost" # For the Selenium Grid only!
|
||||
if port is None:
|
||||
port = "4444" # For the Selenium Grid only!
|
||||
if not environment:
|
||||
environment = "test"
|
||||
if incognito is None:
|
||||
if "--incognito" in sys_argv:
|
||||
incognito = True
|
||||
else:
|
||||
incognito = False
|
||||
if guest_mode is None:
|
||||
if "--guest" in sys_argv:
|
||||
guest_mode = True
|
||||
else:
|
||||
guest_mode = False
|
||||
if devtools is None:
|
||||
if "--devtools" in sys_argv:
|
||||
devtools = True
|
||||
else:
|
||||
devtools = False
|
||||
if is_mobile is None:
|
||||
if "--mobile" in sys_argv:
|
||||
is_mobile = True
|
||||
else:
|
||||
is_mobile = False
|
||||
proxy_string = proxy
|
||||
user_agent = agent
|
||||
recorder_mode = False
|
||||
if recorder_ext:
|
||||
recorder_mode = True
|
||||
if (
|
||||
"--recorder" in sys_argv
|
||||
or "--record" in sys_argv
|
||||
or "--rec" in sys_argv
|
||||
):
|
||||
recorder_mode = True
|
||||
recorder_ext = True
|
||||
if rec_print is None:
|
||||
if "--rec-print" in sys_argv:
|
||||
rec_print = True
|
||||
else:
|
||||
rec_print = False
|
||||
if rec_behave is None:
|
||||
if "--rec-behave" in sys_argv:
|
||||
rec_behave = True
|
||||
else:
|
||||
rec_behave = False
|
||||
if record_sleep is None:
|
||||
if "--rec-sleep" in sys_argv or "--record-sleep" in sys_argv:
|
||||
record_sleep = True
|
||||
else:
|
||||
record_sleep = False
|
||||
if "linux" not in sys.platform:
|
||||
# The Xvfb virtual display server is for Linux OS Only!
|
||||
xvfb = False
|
||||
if (
|
||||
"linux" in sys.platform
|
||||
and not headed
|
||||
and not headless
|
||||
and not headless2
|
||||
and not xvfb
|
||||
):
|
||||
headless = True
|
||||
if headless2 and browser == "firefox":
|
||||
headless2 = False # Only for Chromium browsers
|
||||
headless = True # Firefox has regular headless
|
||||
elif browser not in ["chrome", "edge"]:
|
||||
headless2 = False # Only for Chromium browsers
|
||||
if not headless and not headless2:
|
||||
headed = True
|
||||
if rec_print and not recorder_mode:
|
||||
recorder_mode = True
|
||||
recorder_ext = True
|
||||
elif rec_behave and not recorder_mode:
|
||||
recorder_mode = True
|
||||
recorder_ext = True
|
||||
elif record_sleep and not recorder_mode:
|
||||
recorder_mode = True
|
||||
recorder_ext = True
|
||||
if recorder_mode and headless:
|
||||
headless = False
|
||||
headless2 = True
|
||||
if variables and type(variables) is str and len(variables) > 0:
|
||||
import ast
|
||||
|
||||
bad_input = False
|
||||
if (
|
||||
not variables.startswith("{")
|
||||
or not variables.endswith("}")
|
||||
):
|
||||
bad_input = True
|
||||
else:
|
||||
try:
|
||||
variables = ast.literal_eval(variables)
|
||||
if not type(variables) is dict:
|
||||
bad_input = True
|
||||
except Exception:
|
||||
bad_input = True
|
||||
if bad_input:
|
||||
raise Exception(
|
||||
'\nExpecting a Python dictionary for "variables"!'
|
||||
"\nEg. --variables=\"{'KEY1':'VALUE', 'KEY2':123}\""
|
||||
)
|
||||
else:
|
||||
variables = {}
|
||||
if disable_csp is None:
|
||||
disable_csp = False
|
||||
if enable_ws is None:
|
||||
enable_ws = False
|
||||
if enable_sync is None:
|
||||
enable_sync = False
|
||||
if (
|
||||
(enable_ws is None and disable_ws is None)
|
||||
or (disable_ws is not None and not disable_ws)
|
||||
or (enable_ws is not None and enable_ws)
|
||||
):
|
||||
enable_ws = True
|
||||
disable_ws = False
|
||||
else:
|
||||
enable_ws = False
|
||||
disable_ws = True
|
||||
if undetectable or undetected or uc or uc_subprocess or uc_sub:
|
||||
undetectable = True
|
||||
elif (
|
||||
"--undetectable" in sys_argv
|
||||
or "--undetected" in sys_argv
|
||||
or "--uc" in sys_argv
|
||||
or "--uc-subprocess" in sys_argv
|
||||
or "--uc_subprocess" in sys_argv
|
||||
or "--uc-sub" in sys_argv
|
||||
):
|
||||
undetectable = True
|
||||
else:
|
||||
undetectable = False
|
||||
if uc_subprocess or uc_sub:
|
||||
uc_subprocess = True
|
||||
elif (
|
||||
"--uc-subprocess" in sys_argv
|
||||
or "--uc_subprocess" in sys_argv
|
||||
or "--uc-sub" in sys_argv
|
||||
):
|
||||
uc_subprocess = True
|
||||
else:
|
||||
uc_subprocess = False
|
||||
if use_auto_ext is None:
|
||||
if "--use-auto-ext" in sys_argv:
|
||||
use_auto_ext = True
|
||||
else:
|
||||
use_auto_ext = False
|
||||
if disable_js is None:
|
||||
if "--disable-js" in sys_argv:
|
||||
disable_js = True
|
||||
else:
|
||||
disable_js = False
|
||||
maximize_option = False
|
||||
if maximize or "--maximize" in sys_argv:
|
||||
maximize_option = True
|
||||
_disable_beforeunload = False
|
||||
if disable_beforeunload:
|
||||
_disable_beforeunload = True
|
||||
if page_load_strategy is not None:
|
||||
if page_load_strategy.lower() not in ["normal", "eager", "none"]:
|
||||
raise Exception(
|
||||
'page_load_strategy must be "normal", "eager", or "none"!'
|
||||
)
|
||||
page_load_strategy = page_load_strategy.lower()
|
||||
elif "--pls=normal" in sys_argv or '--pls="normal"' in sys_argv:
|
||||
page_load_strategy = "normal"
|
||||
elif "--pls=eager" in sys_argv or '--pls="eager"' in sys_argv:
|
||||
page_load_strategy = "eager"
|
||||
elif "--pls=none" in sys_argv or '--pls="none"' in sys_argv:
|
||||
page_load_strategy = "none"
|
||||
if (
|
||||
"--sjw" in sys_argv
|
||||
or "--skip_js_waits" in sys_argv
|
||||
or "--skip-js-waits" in sys_argv
|
||||
):
|
||||
settings.SKIP_JS_WAITS = True
|
||||
if save_screenshot is None:
|
||||
if "--screenshot" in sys_argv or "--save-screenshot" in sys_argv:
|
||||
save_screenshot = True
|
||||
else:
|
||||
save_screenshot = False
|
||||
if js_checking_on is None:
|
||||
if "--check-js" in sys_argv:
|
||||
js_checking_on = True
|
||||
else:
|
||||
js_checking_on = False
|
||||
slow_mode = False
|
||||
if slow:
|
||||
slow_mode = True
|
||||
elif "--slow" in sys_argv:
|
||||
slow_mode = True
|
||||
demo_mode = False
|
||||
if demo:
|
||||
demo_mode = True
|
||||
elif "--demo" in sys_argv:
|
||||
demo_mode = True
|
||||
if block_images is None:
|
||||
if "--block-images" in sys_argv:
|
||||
block_images = True
|
||||
else:
|
||||
block_images = False
|
||||
if do_not_track is None:
|
||||
if "--do-not-track" in sys_argv:
|
||||
do_not_track = True
|
||||
else:
|
||||
do_not_track = False
|
||||
if external_pdf is None:
|
||||
if "--external-pdf" in sys_argv:
|
||||
external_pdf = True
|
||||
else:
|
||||
external_pdf = False
|
||||
if remote_debug is None:
|
||||
if "--remote-debug" in sys_argv:
|
||||
remote_debug = True
|
||||
else:
|
||||
remote_debug = False
|
||||
if swiftshader is None:
|
||||
if "--swiftshader" in sys_argv:
|
||||
swiftshader = True
|
||||
else:
|
||||
swiftshader = False
|
||||
if ad_block_on is None:
|
||||
if "--ad-block" in sys_argv:
|
||||
ad_block_on = True
|
||||
else:
|
||||
ad_block_on = False
|
||||
if highlights is not None:
|
||||
try:
|
||||
highlights = int(highlights)
|
||||
except Exception:
|
||||
raise Exception('"highlights" must be an integer!')
|
||||
if interval is not None:
|
||||
try:
|
||||
interval = float(interval)
|
||||
except Exception:
|
||||
raise Exception('"interval" must be numeric!')
|
||||
if time_limit is not None:
|
||||
try:
|
||||
time_limit = float(time_limit)
|
||||
except Exception:
|
||||
raise Exception('"time_limit" must be numeric!')
|
||||
|
||||
sb_config.with_testing_base = with_testing_base
|
||||
sb_config.browser = browser
|
||||
if not hasattr(sb_config, "is_behave"):
|
||||
sb_config.is_behave = False
|
||||
if not hasattr(sb_config, "is_pytest"):
|
||||
sb_config.is_pytest = False
|
||||
if not hasattr(sb_config, "is_nosetest"):
|
||||
sb_config.is_nosetest = False
|
||||
sb_config.is_context_manager = True
|
||||
sb_config.headless = headless
|
||||
sb_config.headless2 = headless2
|
||||
sb_config.headed = headed
|
||||
sb_config.xvfb = xvfb
|
||||
sb_config.start_page = start_page
|
||||
sb_config.locale_code = locale_code
|
||||
sb_config.protocol = protocol
|
||||
sb_config.servername = servername
|
||||
sb_config.port = port
|
||||
sb_config.data = data
|
||||
sb_config.var1 = var1
|
||||
sb_config.var2 = var2
|
||||
sb_config.var3 = var3
|
||||
sb_config.variables = variables
|
||||
sb_config.account = account
|
||||
sb_config.environment = environment
|
||||
sb_config.env = environment
|
||||
sb_config.user_agent = user_agent
|
||||
sb_config.incognito = incognito
|
||||
sb_config.guest_mode = guest_mode
|
||||
sb_config.devtools = devtools
|
||||
sb_config.mobile_emulator = is_mobile
|
||||
sb_config.device_metrics = device_metrics
|
||||
sb_config.extension_zip = extension_zip
|
||||
sb_config.extension_dir = extension_dir
|
||||
sb_config.database_env = "test"
|
||||
sb_config.log_path = "latest_logs"
|
||||
sb_config.archive_logs = archive_logs
|
||||
sb_config.disable_csp = disable_csp
|
||||
sb_config.disable_ws = disable_ws
|
||||
sb_config.enable_ws = enable_ws
|
||||
sb_config.enable_sync = enable_sync
|
||||
sb_config.use_auto_ext = use_auto_ext
|
||||
sb_config.undetectable = undetectable
|
||||
sb_config.uc_subprocess = uc_subprocess
|
||||
sb_config.no_sandbox = None
|
||||
sb_config.disable_gpu = None
|
||||
sb_config.disable_js = disable_js
|
||||
sb_config._multithreaded = False
|
||||
sb_config.reuse_session = False
|
||||
sb_config.crumbs = False
|
||||
sb_config.final_debug = False
|
||||
sb_config.visual_baseline = False
|
||||
sb_config.window_size = None
|
||||
sb_config.maximize_option = maximize_option
|
||||
sb_config._disable_beforeunload = _disable_beforeunload
|
||||
sb_config.save_screenshot = save_screenshot
|
||||
sb_config.page_load_strategy = page_load_strategy
|
||||
sb_config.timeout_multiplier = timeout_multiplier
|
||||
sb_config.pytest_html_report = None
|
||||
sb_config.with_db_reporting = False
|
||||
sb_config.with_s3_logging = False
|
||||
sb_config.js_checking_on = js_checking_on
|
||||
sb_config.recorder_mode = recorder_mode
|
||||
sb_config.recorder_ext = recorder_ext
|
||||
sb_config.record_sleep = record_sleep
|
||||
sb_config.rec_behave = rec_behave
|
||||
sb_config.rec_print = rec_print
|
||||
sb_config.report_on = False
|
||||
sb_config.slow_mode = slow_mode
|
||||
sb_config.demo_mode = demo_mode
|
||||
sb_config._time_limit = time_limit
|
||||
sb_config.demo_sleep = demo_sleep
|
||||
sb_config.dashboard = False
|
||||
sb_config._dashboard_initialized = False
|
||||
sb_config.message_duration = message_duration
|
||||
sb_config.block_images = block_images
|
||||
sb_config.do_not_track = do_not_track
|
||||
sb_config.external_pdf = external_pdf
|
||||
sb_config.remote_debug = remote_debug
|
||||
sb_config.settings_file = settings_file
|
||||
sb_config.user_data_dir = user_data_dir
|
||||
sb_config.chromium_arg = chromium_arg
|
||||
sb_config.firefox_arg = firefox_arg
|
||||
sb_config.firefox_pref = firefox_pref
|
||||
sb_config.proxy_string = proxy_string
|
||||
sb_config.proxy_bypass_list = proxy_bypass_list
|
||||
sb_config.proxy_pac_url = proxy_pac_url
|
||||
sb_config.swiftshader = swiftshader
|
||||
sb_config.ad_block_on = ad_block_on
|
||||
sb_config.highlights = highlights
|
||||
sb_config.interval = interval
|
||||
sb_config.cap_file = cap_file
|
||||
sb_config.cap_string = cap_string
|
||||
|
||||
sb = BaseCase()
|
||||
sb.with_testing_base = sb_config.with_testing_base
|
||||
sb.browser = sb_config.browser
|
||||
sb.is_behave = False
|
||||
sb.is_pytest = False
|
||||
sb.is_nosetest = False
|
||||
sb.is_context_manager = sb_config.is_context_manager
|
||||
sb.headless = sb_config.headless
|
||||
sb.headless2 = sb_config.headless2
|
||||
sb.headed = sb_config.headed
|
||||
sb.xvfb = sb_config.xvfb
|
||||
sb.start_page = sb_config.start_page
|
||||
sb.locale_code = sb_config.locale_code
|
||||
sb.protocol = sb_config.protocol
|
||||
sb.servername = sb_config.servername
|
||||
sb.port = sb_config.port
|
||||
sb.data = sb_config.data
|
||||
sb.var1 = sb_config.var1
|
||||
sb.var2 = sb_config.var2
|
||||
sb.var3 = sb_config.var3
|
||||
sb.variables = sb_config.variables
|
||||
sb.account = sb_config.account
|
||||
sb.environment = sb_config.environment
|
||||
sb.env = sb_config.env
|
||||
sb.user_agent = sb_config.user_agent
|
||||
sb.incognito = sb_config.incognito
|
||||
sb.guest_mode = sb_config.guest_mode
|
||||
sb.devtools = sb_config.devtools
|
||||
sb.mobile_emulator = sb_config.mobile_emulator
|
||||
sb.device_metrics = sb_config.device_metrics
|
||||
sb.extension_zip = sb_config.extension_zip
|
||||
sb.extension_dir = sb_config.extension_dir
|
||||
sb.database_env = sb_config.database_env
|
||||
sb.log_path = sb_config.log_path
|
||||
sb.archive_logs = sb_config.archive_logs
|
||||
sb.disable_csp = sb_config.disable_csp
|
||||
sb.disable_ws = sb_config.disable_ws
|
||||
sb.enable_ws = sb_config.enable_ws
|
||||
sb.enable_sync = sb_config.enable_sync
|
||||
sb.use_auto_ext = sb_config.use_auto_ext
|
||||
sb.undetectable = sb_config.undetectable
|
||||
sb.uc_subprocess = sb_config.uc_subprocess
|
||||
sb.no_sandbox = sb_config.no_sandbox
|
||||
sb.disable_gpu = sb_config.disable_gpu
|
||||
sb.disable_js = sb_config.disable_js
|
||||
sb._multithreaded = sb_config._multithreaded
|
||||
sb._reuse_session = sb_config.reuse_session
|
||||
sb._crumbs = sb_config.crumbs
|
||||
sb._final_debug = sb_config.final_debug
|
||||
sb.visual_baseline = sb_config.visual_baseline
|
||||
sb.window_size = sb_config.window_size
|
||||
sb.maximize_option = sb_config.maximize_option
|
||||
sb._disable_beforeunload = sb_config._disable_beforeunload
|
||||
sb.save_screenshot_after_test = sb_config.save_screenshot
|
||||
sb.page_load_strategy = sb_config.page_load_strategy
|
||||
sb.timeout_multiplier = sb_config.timeout_multiplier
|
||||
sb.pytest_html_report = sb_config.pytest_html_report
|
||||
sb.with_db_reporting = sb_config.with_db_reporting
|
||||
sb.with_s3_logging = sb_config.with_s3_logging
|
||||
sb.js_checking_on = sb_config.js_checking_on
|
||||
sb.recorder_mode = sb_config.recorder_mode
|
||||
sb.recorder_ext = sb_config.recorder_ext
|
||||
sb.record_sleep = sb_config.record_sleep
|
||||
sb.rec_behave = sb_config.rec_behave
|
||||
sb.rec_print = sb_config.rec_print
|
||||
sb.report_on = sb_config.report_on
|
||||
sb.slow_mode = sb_config.slow_mode
|
||||
sb.demo_mode = sb_config.demo_mode
|
||||
sb.time_limit = sb_config._time_limit
|
||||
sb.demo_sleep = sb_config.demo_sleep
|
||||
sb.dashboard = sb_config.dashboard
|
||||
sb._dash_initialized = sb_config._dashboard_initialized
|
||||
sb.message_duration = sb_config.message_duration
|
||||
sb.block_images = sb_config.block_images
|
||||
sb.do_not_track = sb_config.do_not_track
|
||||
sb.external_pdf = sb_config.external_pdf
|
||||
sb.remote_debug = sb_config.remote_debug
|
||||
sb.settings_file = sb_config.settings_file
|
||||
sb.user_data_dir = sb_config.user_data_dir
|
||||
sb.chromium_arg = sb_config.chromium_arg
|
||||
sb.firefox_arg = sb_config.firefox_arg
|
||||
sb.firefox_pref = sb_config.firefox_pref
|
||||
sb.proxy_string = sb_config.proxy_string
|
||||
sb.proxy_bypass_list = sb_config.proxy_bypass_list
|
||||
sb.proxy_pac_url = sb_config.proxy_pac_url
|
||||
sb.swiftshader = sb_config.swiftshader
|
||||
sb.ad_block_on = sb_config.ad_block_on
|
||||
sb.highlights = sb_config.highlights
|
||||
sb.interval = sb_config.interval
|
||||
sb.cap_file = sb_config.cap_file
|
||||
sb.cap_string = sb_config.cap_string
|
||||
sb._has_failure = False # This may change
|
||||
if hasattr(sb_config, "headless_active"):
|
||||
sb.headless_active = sb_config.headless_active
|
||||
else:
|
||||
sb.headless_active = False
|
||||
test_name = None
|
||||
if test:
|
||||
import colorama
|
||||
import os
|
||||
|
||||
colorama.init(autoreset=True)
|
||||
c1 = colorama.Fore.GREEN
|
||||
b1 = colorama.Style.BRIGHT
|
||||
cr = colorama.Style.RESET_ALL
|
||||
stack_base = traceback.format_stack()[0].split(os.sep)[-1]
|
||||
test_name = stack_base.split(", in ")[0].replace('", line ', ":")
|
||||
test_name += ":SB"
|
||||
terminal_width = os.get_terminal_size()[0]
|
||||
start_text = "=== {%s} starts ===" % test_name
|
||||
remaining_spaces = terminal_width - len(start_text)
|
||||
left_space = ""
|
||||
right_space = ""
|
||||
if remaining_spaces > 0:
|
||||
left_spaces = int(remaining_spaces / 2)
|
||||
left_space = left_spaces * "="
|
||||
right_spaces = remaining_spaces - left_spaces
|
||||
right_space = right_spaces * "="
|
||||
if not test_name.startswith("runpy.py:"):
|
||||
print("%s%s%s%s%s" % (b1, left_space, start_text, right_space, cr))
|
||||
if do_log_folder_setup:
|
||||
from seleniumbase.core import log_helper
|
||||
from seleniumbase.core import download_helper
|
||||
from seleniumbase.core import proxy_helper
|
||||
|
||||
log_helper.log_folder_setup(sb_config.log_path)
|
||||
download_helper.reset_downloads_folder()
|
||||
proxy_helper.remove_proxy_zip_if_present()
|
||||
start_time = time.time()
|
||||
sb.setUp()
|
||||
test_passed = True # This can change later
|
||||
teardown_exception = None
|
||||
try:
|
||||
yield sb
|
||||
except Exception as e:
|
||||
sb._has_failure = True
|
||||
exception = e
|
||||
test_passed = False
|
||||
if not test_name:
|
||||
raise
|
||||
else:
|
||||
the_traceback = traceback.format_exc().strip()
|
||||
try:
|
||||
p2 = the_traceback.split(', in ')[1].split('", line ')[0]
|
||||
filename = p2.split("/")[-1]
|
||||
sb.cm_filename = filename
|
||||
except Exception:
|
||||
sb.cm_filename = None
|
||||
# Tests will raise an exception later if "raise_test_failure"
|
||||
finally:
|
||||
try:
|
||||
sb.tearDown()
|
||||
except Exception as t_e:
|
||||
teardown_exception = t_e
|
||||
print(traceback.format_exc().strip())
|
||||
if test and not test_passed:
|
||||
print("********** ERROR: The test AND the tearDown() FAILED!")
|
||||
end_time = time.time()
|
||||
run_time = end_time - start_time
|
||||
sb_config = sb_config_backup
|
||||
if test:
|
||||
sb_config._has_older_context = True
|
||||
if existing_runner:
|
||||
sb_config._context_of_runner = True
|
||||
if test_name:
|
||||
result = "passed"
|
||||
if not test_passed:
|
||||
result = "failed"
|
||||
c1 = colorama.Fore.RED
|
||||
terminal_width = os.get_terminal_size()[0]
|
||||
end_text = (
|
||||
"=== {%s} %s in %.2fs ==="
|
||||
% (test_name, result, run_time)
|
||||
)
|
||||
remaining_spaces = terminal_width - len(end_text)
|
||||
end_text = (
|
||||
"=== %s%s{%s} %s%s%s in %.2fs ==="
|
||||
% (b1, c1, test_name, result, cr, c1, run_time)
|
||||
)
|
||||
left_space = ""
|
||||
right_space = ""
|
||||
if remaining_spaces > 0:
|
||||
left_spaces = int(remaining_spaces / 2)
|
||||
left_space = left_spaces * "="
|
||||
right_spaces = remaining_spaces - left_spaces
|
||||
right_space = right_spaces * "="
|
||||
if not test_passed:
|
||||
print(the_traceback)
|
||||
if not test_name.startswith("runpy.py:"):
|
||||
print(
|
||||
"%s%s%s%s%s"
|
||||
% (c1, left_space, end_text, right_space, cr)
|
||||
)
|
||||
if test and test_name and not test_passed and raise_test_failure:
|
||||
raise exception
|
||||
elif (
|
||||
teardown_exception
|
||||
and (
|
||||
not test
|
||||
or (test_passed and raise_test_failure)
|
||||
)
|
||||
):
|
||||
raise teardown_exception
|
|
@ -68,7 +68,8 @@ class SeleniumBrowser(Plugin):
|
|||
--enable-ws (Enable Web Security on Chromium-based browsers.)
|
||||
--enable-sync (Enable "Chrome Sync" on websites.)
|
||||
--use-auto-ext (Use Chrome's automation extension.)
|
||||
--undetected | --uc (Use undetected-chromedriver to evade bot-detection.)
|
||||
--uc | --undetected (Use undetected-chromedriver to evade bot-detection.)
|
||||
--uc-sub | --uc-subprocess (Use undetected-chromedriver as a subprocess.)
|
||||
--remote-debug (Enable Chrome's Remote Debugger on http://localhost:9222)
|
||||
--final-debug (Enter Debug Mode after each test ends. Don't use with CI!)
|
||||
--swiftshader (Use Chrome's "--use-gl=swiftshader" feature.)
|
||||
|
@ -634,6 +635,17 @@ class SeleniumBrowser(Plugin):
|
|||
to websites that use anti-bot services to block
|
||||
automation tools from navigating them freely.""",
|
||||
)
|
||||
parser.add_option(
|
||||
"--uc_subprocess",
|
||||
"--uc-subprocess",
|
||||
"--uc-sub", # undetected-chromedriver subprocess mode
|
||||
action="store_true",
|
||||
dest="uc_subprocess",
|
||||
default=False,
|
||||
help="""Use undetectable-chromedriver as a subprocess,
|
||||
which can help avoid issues that might result.
|
||||
It may reduce UC's ability to avoid detection.""",
|
||||
)
|
||||
parser.add_option(
|
||||
"--no_sandbox",
|
||||
"--no-sandbox",
|
||||
|
@ -789,9 +801,12 @@ class SeleniumBrowser(Plugin):
|
|||
self.enabled = True # Used if test class inherits BaseCase
|
||||
self.options = options
|
||||
self.headless_active = False # Default setting
|
||||
sb_config.headless_active = False
|
||||
sb_config.is_nosetest = True
|
||||
proxy_helper.remove_proxy_zip_if_present()
|
||||
|
||||
def beforeTest(self, test):
|
||||
sb_config._context_of_runner = False # Context Manager Compatibility
|
||||
browser = self.options.browser
|
||||
if self.options.recorder_mode and browser not in ["chrome", "edge"]:
|
||||
message = (
|
||||
|
@ -824,12 +839,24 @@ class SeleniumBrowser(Plugin):
|
|||
settings.HEADLESS_START_WIDTH = width
|
||||
settings.HEADLESS_START_HEIGHT = height
|
||||
test.test.is_nosetest = True
|
||||
test.test.is_behave = False
|
||||
test.test.is_pytest = False
|
||||
test.test.is_context_manager = False
|
||||
sb_config.is_nosetest = True
|
||||
sb_config.is_behave = False
|
||||
sb_config.is_pytest = False
|
||||
sb_config.is_context_manager = False
|
||||
test.test.browser = self.options.browser
|
||||
test.test.cap_file = self.options.cap_file
|
||||
test.test.cap_string = self.options.cap_string
|
||||
test.test.headless = self.options.headless
|
||||
test.test.headless2 = self.options.headless2
|
||||
if test.test.browser not in ["chrome", "edge"]:
|
||||
if test.test.headless2 and test.test.browser == "firefox":
|
||||
test.test.headless2 = False # Only for Chromium browsers
|
||||
test.test.headless = True # Firefox has regular headless
|
||||
self.options.headless2 = False
|
||||
self.options.headless = True
|
||||
elif test.test.browser not in ["chrome", "edge"]:
|
||||
test.test.headless2 = False # Only for Chromium browsers
|
||||
self.options.headless2 = False
|
||||
test.test.headed = self.options.headed
|
||||
|
@ -889,6 +916,9 @@ class SeleniumBrowser(Plugin):
|
|||
test.test.enable_sync = self.options.enable_sync
|
||||
test.test.use_auto_ext = self.options.use_auto_ext
|
||||
test.test.undetectable = self.options.undetectable
|
||||
test.test.uc_subprocess = self.options.uc_subprocess
|
||||
if test.test.uc_subprocess and not test.test.undetectable:
|
||||
test.test.undetectable = True
|
||||
test.test.no_sandbox = self.options.no_sandbox
|
||||
test.test.disable_gpu = self.options.disable_gpu
|
||||
test.test.remote_debug = self.options.remote_debug
|
||||
|
@ -912,12 +942,6 @@ class SeleniumBrowser(Plugin):
|
|||
# (Set --server="127.0.0.1" for localhost Grid)
|
||||
if str(self.options.port) == "443":
|
||||
test.test.protocol = "https"
|
||||
# Recorder Mode can still optimize scripts in --headless2 mode.
|
||||
if self.options.recorder_mode and self.options.headless:
|
||||
self.options.headless = False
|
||||
self.options.headless2 = True
|
||||
test.test.headless = False
|
||||
test.test.headless2 = True
|
||||
if self.options.xvfb and "linux" not in sys.platform:
|
||||
# The Xvfb virtual display server is for Linux OS Only!
|
||||
self.options.xvfb = False
|
||||
|
@ -937,6 +961,12 @@ class SeleniumBrowser(Plugin):
|
|||
)
|
||||
self.options.headless = True
|
||||
test.test.headless = True
|
||||
# Recorder Mode can still optimize scripts in --headless2 mode.
|
||||
if self.options.recorder_mode and self.options.headless:
|
||||
self.options.headless = False
|
||||
self.options.headless2 = True
|
||||
test.test.headless = False
|
||||
test.test.headless2 = True
|
||||
if not self.options.headless and not self.options.headless2:
|
||||
self.options.headed = True
|
||||
test.test.headed = True
|
||||
|
@ -952,6 +982,7 @@ class SeleniumBrowser(Plugin):
|
|||
self.display = Display(visible=0, size=(1440, 1880))
|
||||
self.display.start()
|
||||
self.headless_active = True
|
||||
sb_config.headless_active = True
|
||||
except Exception:
|
||||
# pyvirtualdisplay might not be necessary anymore because
|
||||
# Chrome and Firefox now have built-in headless displays
|
||||
|
@ -983,6 +1014,8 @@ class SeleniumBrowser(Plugin):
|
|||
if self.options.headless or self.options.xvfb:
|
||||
if self.headless_active:
|
||||
try:
|
||||
self.headless_active = False
|
||||
sb_config.headless_active = False
|
||||
self.display.stop()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
|
Loading…
Reference in New Issue