Skip to content

Commit c308389

Browse files
authored
Merge pull request #314 from seleniumbase/several-updates
Several minor updates
2 parents 629cdb5 + b5996f9 commit c308389

File tree

11 files changed

+170
-248
lines changed

11 files changed

+170
-248
lines changed

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ lib
1818
lib64
1919
__pycache__
2020

21+
# Python3 pyvenv
22+
pyvenv.cfg
23+
.Python
24+
include
25+
pip-delete-this-directory.txt
26+
pip-selfcheck.json
27+
ipython.1.gz
28+
nosetests.1
29+
2130
# Installer logs
2231
pip-log.txt
2332
.swp

README.md

Lines changed: 62 additions & 161 deletions
Large diffs are not rendered by default.

examples/raw_parameter_script.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
b.visual_baseline = False
4141
b.save_screenshot_after_test = False
4242
b.timeout_multiplier = None
43+
b.pytest_html_report = None
44+
b.report_on = False
4345
b.with_db_reporting = False
4446
b.with_s3_logging = False
4547
b.js_checking_on = False

examples/tour_examples/ReadMe.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
## SeleniumBase Website Tours
22

3-
SeleniumBase Tours utilize your choice of 4 different JavaScript libraries for creating & running tours, demos, and walkthroughs on any website: **[Shepherd](https://shipshapecode.github.io/shepherd/docs/welcome/)**, **[Bootstrap Tour](http://bootstraptour.com/)**, **[IntroJS](https://introjs.com/)**, and **[Hopscotch](http://linkedin.github.io/hopscotch/)**. Choose your favorite one to use!
3+
SeleniumBase Tours utilize your choice of 4 different JavaScript libraries for prototyping tours, demos, walkthroughs, and onboarding experiences on any website: **[Shepherd](https://shipshapecode.github.io/shepherd/docs/welcome/)**, **[Bootstrap Tour](http://bootstraptour.com/)**, **[IntroJS](https://introjs.com/)**, and **[Hopscotch](http://linkedin.github.io/hopscotch/)**. Choose your favorite one to use!
44

55
Example tour:
66

7+
```
8+
cd examples/tour_examples
9+
pytest google_tour.py
10+
```
11+
712
<img src="https://cdn2.hubspot.net/hubfs/100006/google_tour_3.gif" title="SeleniumBase Tour of Google" height="260"><br>
813

914

help_docs/features_list.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* Backwards-compatible with [WebDriver](http://www.seleniumhq.org/projects/webdriver/). (Use ``self.driver`` anywhere.)
1313
* Can run tests through a proxy server. (Use ``--proxy=IP_ADDRESS:PORT``)
1414
* Can use an authenticated proxy server. (``--proxy=USERNAME:PASSWORD@IP_ADDRESS:PORT``)
15+
* Can change the web browser's user agent string. (Use ``--agent=USER_AGENT_STRING``)
1516
* Can handle Google Authenticator logins by using the [Python one-time password library](https://pyotp.readthedocs.io/en/latest/).
1617
* Includes a hybrid-automation solution called **[MasterQA](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/masterqa/ReadMe.md)** to speed up manual testing.
1718
* Integrates with [MySQL](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/core/testcase_manager.py), [Selenium Grid](https://github.com/seleniumbase/SeleniumBase/tree/master/seleniumbase/utilities/selenium_grid), [Azure](https://github.com/seleniumbase/SeleniumBase/blob/master/integrations/azure/jenkins/ReadMe.md), [Google Cloud](https://github.com/seleniumbase/SeleniumBase/tree/master/integrations/google_cloud/ReadMe.md), [Amazon S3](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/plugins/s3_logging_plugin.py), and [Docker](https://github.com/seleniumbase/SeleniumBase/blob/master/integrations/docker/ReadMe.md).

help_docs/install_python_pip_git.md

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
## Installation instructions for Python, pip, brew, git, virtualenv, and virtualenvwrapper
1+
## Installation instructions for Git, Python, and Pip
2+
3+
### [Git](http://www.git-scm.com)
4+
5+
You can [download Git from here](http://git-scm.com/downloads).
6+
7+
(You can also download the SeleniumBase repository right from GitHub and skip all the git-related commands.)
28

39
### [Python 2.7 or 3.x](https://www.python.org/downloads/)
410

@@ -42,34 +48,3 @@ curl https://bootstrap.pypa.io/get-pip.py | python
4248
```
4349

4450
(If you get SSL errors while trying to install packages with pip, see [this Stackoverflow post](https://stackoverflow.com/questions/49768770/not-able-to-install-python-packages-ssl-tlsv1-alert-protocol-version), which tells you to run the above command.)
45-
46-
### [Homebrew](http://brew.sh/) (macOS-ONLY) (OPTIONAL)
47-
48-
The Homebrew package manager allows you to install things more easily on macOS, such as Git and Chromedriver.
49-
50-
Here's the command line script to install Homebrew (*from [https://brew.sh/](https://brew.sh/)*):
51-
```bash
52-
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
53-
```
54-
If you haven't updated Homebrew in awhile, you probably should. Here's how:
55-
```bash
56-
brew update
57-
```
58-
59-
### [Git](http://www.git-scm.com)
60-
61-
You can [download Git from here](http://git-scm.com/downloads).
62-
63-
macOS-ONLY shortcut: (This step only works if you installed Homebrew in the previous step)
64-
```bash
65-
brew install git
66-
```
67-
68-
(You can also download the SeleniumBase repository right from GitHub and skip all the git-related commands.)
69-
70-
<a id="virtual_environment"></a>
71-
### [VirtualEnv](http://virtualenv.readthedocs.org/en/latest/) and [VirtualEnvWrapper](http://virtualenvwrapper.readthedocs.org/en/latest/)
72-
73-
Virtual environments allow each your Python projects to have a unique set of packaged dependencies.
74-
75-
To learn how to create a Python virtual environment, [see this ReadMe](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/virtualenv_instructions.md).

help_docs/mysql_installation.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,6 @@ If you want a visual tool to help make your MySQL life easier, [try MySQL Workbe
2929

3030
You can use the [testcaserepository.sql](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/core/testcaserepository.sql) file to create the necessary tables for storing test data.
3131

32-
If you were able to successfully install MySQL, you can now install the remaining MySQL requirements:
33-
```bash
34-
pip install -r requirements.txt
35-
```
36-
(NOTE: This install uses Selenium 2.53.6 rather than the usual Selenium 3+ from the standard requirements file due to compatibility issues with running browser tests on headless server machines.)
37-
3832
#### Configure your MySQL DB for SeleniumBase
3933

4034
You'll want to update your [settings.py](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/config/settings.py) file with your MySQL DB credentials so that tests can write to the database when they run.
@@ -44,7 +38,7 @@ You'll want to update your [settings.py](https://github.com/seleniumbase/Seleniu
4438
Add the ``--with-db_reporting`` argument on the command line when you want tests to write to your MySQL database.
4539
Example:
4640
```bash
47-
nosetests my_first_test.py --with-db_reporting
41+
pytest my_first_test.py --with-db_reporting
4842
```
4943

5044
#### Windows mysql-python troubleshooting:

help_docs/virtualenv_instructions.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,28 @@ python -m pip install --upgrade virtualenv
2424
python -m pip install --upgrade virtualenvwrapper-win
2525
```
2626

27-
### **Step 2**: Now use VirtualEnv or VirtualEnvWrapper to create a virtual environment:
27+
### **Step 2**: Now create a virtual environment:
2828

2929
#### macOS / Linux / Windows:
3030

31+
* Using ``mkvirtualenv``:
3132
```bash
32-
mkvirtualenv seleniumbase
33+
mkvirtualenv seleniumbase_venv
3334
```
3435
(If you have multiple versions of Python installed on your machine, and you want your virtual environment to use a specific Python version, add ``--python=PATH_TO_PYTHON_EXE`` with the Python executable to use.)
3536

37+
* Using ``virtualenv``:
38+
```bash
39+
virtualenv seleniumbase_venv
40+
source seleniumbase_venv/bin/activate
41+
```
42+
43+
* (Python 3) Using ``mvenv``:
44+
```bash
45+
python3 -mvenv seleniumbase_venv
46+
source seleniumbase_venv/bin/activate
47+
```
48+
3649
---
3750

3851
If you ever need to leave your virtual environment, use the following command:
@@ -44,7 +57,7 @@ deactivate
4457
You can always jump back into your virtual environment later:
4558

4659
```bash
47-
workon seleniumbase
60+
workon seleniumbase_venv
4861
```
4962

5063
To list all existing virtual environments:

seleniumbase/fixtures/base_case.py

Lines changed: 61 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: utf-8 -*-
12
"""
23
The BaseCase class is the main gateway for using The SeleniumBase Framework.
34
It inherits Python's unittest.TestCase class, and runs with Pytest or Nose.
@@ -31,6 +32,13 @@ def test_anything(self):
3132
import time
3233
import unittest
3334
import uuid
35+
from selenium.common.exceptions import (StaleElementReferenceException,
36+
MoveTargetOutOfBoundsException,
37+
WebDriverException)
38+
from selenium.common import exceptions as selenium_exceptions
39+
from selenium.webdriver.common.by import By
40+
from selenium.webdriver.common.keys import Keys
41+
from selenium.webdriver.support.ui import Select
3442
from seleniumbase import config as sb_config
3543
from seleniumbase.common import decorators
3644
from seleniumbase.config import settings
@@ -45,19 +53,7 @@ def test_anything(self):
4553
from seleniumbase.fixtures import page_actions
4654
from seleniumbase.fixtures import page_utils
4755
from seleniumbase.fixtures import xpath_to_css
48-
from selenium.common.exceptions import (StaleElementReferenceException,
49-
MoveTargetOutOfBoundsException,
50-
WebDriverException)
51-
from selenium.common import exceptions as selenium_exceptions
52-
try:
53-
# Selenium 3 (ElementNotInteractableException does not exist in selenium 2)
54-
ENI_Exception = selenium_exceptions.ElementNotInteractableException
55-
except Exception:
56-
# Selenium 2 (Keep compatibility with seleneium 2.53.6 if still being used)
57-
ENI_Exception = selenium_exceptions.ElementNotSelectableException
58-
from selenium.webdriver.common.by import By
59-
from selenium.webdriver.common.keys import Keys
60-
from selenium.webdriver.support.ui import Select
56+
ENI_Exception = selenium_exceptions.ElementNotInteractableException
6157

6258

6359
class BaseCase(unittest.TestCase):
@@ -74,6 +70,7 @@ def __init__(self, *args, **kwargs):
7470
self.__last_url_of_delayed_assert = "data:,"
7571
self.__last_page_load_url = "data:,"
7672
self.__last_page_screenshot = None
73+
self.__last_page_screenshot_png = None
7774
self.__delayed_assert_count = 0
7875
self.__delayed_assert_failures = []
7976
# Requires self._* instead of self.__* for external class use
@@ -3118,6 +3115,10 @@ def setUp(self, masterqa_mode=False):
31183115
self.save_screenshot_after_test = sb_config.save_screenshot
31193116
self.visual_baseline = sb_config.visual_baseline
31203117
self.timeout_multiplier = sb_config.timeout_multiplier
3118+
self.pytest_html_report = sb_config.pytest_html_report
3119+
self.report_on = False
3120+
if self.pytest_html_report:
3121+
self.report_on = True
31213122
self.use_grid = False
31223123
if self.servername != "localhost":
31233124
# Use Selenium Grid (Use --server=127.0.0.1 for localhost Grid)
@@ -3188,15 +3189,32 @@ def setUp(self, masterqa_mode=False):
31883189
self._default_driver = self.driver
31893190

31903191
def __set_last_page_screenshot(self):
3191-
if not self.__last_page_screenshot:
3192+
""" self.__last_page_screenshot is only for pytest html report logs
3193+
self.__last_page_screenshot_png is for all screenshot log files """
3194+
if not self.__last_page_screenshot and (
3195+
not self.__last_page_screenshot_png):
31923196
try:
31933197
element = self.driver.find_element_by_tag_name('body')
3194-
if self.is_pytest:
3198+
if self.is_pytest and self.report_on:
3199+
self.__last_page_screenshot_png = (
3200+
self.driver.get_screenshot_as_png())
31953201
self.__last_page_screenshot = element.screenshot_as_base64
31963202
else:
3197-
self.__last_page_screenshot = element.screenshot_as_png
3203+
self.__last_page_screenshot_png = element.screenshot_as_png
31983204
except Exception:
3199-
pass
3205+
if not self.__last_page_screenshot:
3206+
if self.is_pytest and self.report_on:
3207+
try:
3208+
self.__last_page_screenshot = (
3209+
self.driver.get_screenshot_as_base64())
3210+
except Exception:
3211+
pass
3212+
if not self.__last_page_screenshot_png:
3213+
try:
3214+
self.__last_page_screenshot_png = (
3215+
self.driver.get_screenshot_as_png())
3216+
except Exception:
3217+
pass
32003218

32013219
def __insert_test_result(self, state, err):
32023220
data_payload = TestcaseDataPayload()
@@ -3223,20 +3241,21 @@ def __add_pytest_html_extra(self):
32233241
if self.with_selenium:
32243242
if not self.__last_page_screenshot:
32253243
self.__set_last_page_screenshot()
3226-
extra_url = {}
3227-
extra_url['name'] = 'URL'
3228-
extra_url['format'] = 'url'
3229-
extra_url['content'] = self.get_current_url()
3230-
extra_url['mime_type'] = None
3231-
extra_url['extension'] = None
3232-
extra_image = {}
3233-
extra_image['name'] = 'Screenshot'
3234-
extra_image['format'] = 'image'
3235-
extra_image['content'] = self.__last_page_screenshot
3236-
extra_image['mime_type'] = 'image/png'
3237-
extra_image['extension'] = 'png'
3238-
self._html_report_extra.append(extra_url)
3239-
self._html_report_extra.append(extra_image)
3244+
if self.report_on:
3245+
extra_url = {}
3246+
extra_url['name'] = 'URL'
3247+
extra_url['format'] = 'url'
3248+
extra_url['content'] = self.get_current_url()
3249+
extra_url['mime_type'] = None
3250+
extra_url['extension'] = None
3251+
extra_image = {}
3252+
extra_image['name'] = 'Screenshot'
3253+
extra_image['format'] = 'image'
3254+
extra_image['content'] = self.__last_page_screenshot
3255+
extra_image['mime_type'] = 'image/png'
3256+
extra_image['extension'] = 'png'
3257+
self._html_report_extra.append(extra_url)
3258+
self._html_report_extra.append(extra_image)
32403259
except Exception:
32413260
pass
32423261

@@ -3325,12 +3344,12 @@ def tearDown(self):
33253344
os.makedirs(test_logpath)
33263345
except Exception:
33273346
pass # Only reachable during multi-threaded runs
3328-
if not self.__last_page_screenshot:
3347+
if not self.__last_page_screenshot_png:
33293348
self.__set_last_page_screenshot()
33303349
log_helper.log_screenshot(
33313350
test_logpath,
33323351
self.driver,
3333-
self.__last_page_screenshot)
3352+
self.__last_page_screenshot_png)
33343353
self.__add_pytest_html_extra()
33353354
if self.with_testing_base and has_exception:
33363355
test_logpath = self.log_path + "/" + test_id
@@ -3343,23 +3362,23 @@ def tearDown(self):
33433362
not self.with_basic_test_info) and (
33443363
not self.with_page_source)):
33453364
# Log everything if nothing specified (if testing_base)
3346-
if not self.__last_page_screenshot:
3365+
if not self.__last_page_screenshot_png:
33473366
self.__set_last_page_screenshot()
33483367
log_helper.log_screenshot(
33493368
test_logpath,
33503369
self.driver,
3351-
self.__last_page_screenshot)
3370+
self.__last_page_screenshot_png)
33523371
log_helper.log_test_failure_data(
33533372
self, test_logpath, self.driver, self.browser)
33543373
log_helper.log_page_source(test_logpath, self.driver)
33553374
else:
33563375
if self.with_screen_shots:
3357-
if not self.__last_page_screenshot:
3376+
if not self.__last_page_screenshot_png:
33583377
self.__set_last_page_screenshot()
33593378
log_helper.log_screenshot(
33603379
test_logpath,
33613380
self.driver,
3362-
self.__last_page_screenshot)
3381+
self.__last_page_screenshot_png)
33633382
if self.with_basic_test_info:
33643383
log_helper.log_test_failure_data(
33653384
self, test_logpath, self.driver, self.browser)
@@ -3420,12 +3439,12 @@ def tearDown(self):
34203439
log_helper.log_test_failure_data(
34213440
self, test_logpath, self.driver, self.browser)
34223441
if len(self._drivers_list) > 0:
3423-
if not self.__last_page_screenshot:
3442+
if not self.__last_page_screenshot_png:
34243443
self.__set_last_page_screenshot()
34253444
log_helper.log_screenshot(
34263445
test_logpath,
34273446
self.driver,
3428-
self.__last_page_screenshot)
3447+
self.__last_page_screenshot_png)
34293448
log_helper.log_page_source(test_logpath, self.driver)
34303449
elif self.save_screenshot_after_test:
34313450
test_id = "%s.%s.%s" % (self.__class__.__module__,
@@ -3437,14 +3456,14 @@ def tearDown(self):
34373456
os.makedirs(test_logpath)
34383457
except Exception:
34393458
pass # Only reachable during multi-threaded runs
3440-
if not self.__last_page_screenshot:
3459+
if not self.__last_page_screenshot_png:
34413460
self.__set_last_page_screenshot()
34423461
log_helper.log_screenshot(
34433462
test_logpath,
34443463
self.driver,
3445-
self.__last_page_screenshot)
3464+
self.__last_page_screenshot_png)
34463465
if self.report_on:
3447-
self._last_page_screenshot = self.__last_page_screenshot
3466+
self._last_page_screenshot = self.__last_page_screenshot_png
34483467
try:
34493468
self._last_page_url = self.get_current_url()
34503469
except Exception:

seleniumbase/plugins/pytest_plugin.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: utf-8 -*-
12
""" This is the pytest configuration file """
23

34
import optparse
@@ -221,6 +222,7 @@ def pytest_configure(config):
221222
sb_config.save_screenshot = config.getoption('save_screenshot')
222223
sb_config.visual_baseline = config.getoption('visual_baseline')
223224
sb_config.timeout_multiplier = config.getoption('timeout_multiplier')
225+
sb_config.pytest_html_report = config.getoption("htmlpath") # --html=FILE
224226

225227
if sb_config.with_testing_base:
226228
log_helper.log_folder_setup(sb_config.log_path, sb_config.archive_logs)
@@ -268,6 +270,7 @@ def pytest_runtest_makereport(item, call):
268270
try:
269271
extra_report = item._testcase._html_report_extra
270272
extra = getattr(report, 'extra', [])
271-
report.extra = extra + extra_report
273+
if extra_report[1]["content"]:
274+
report.extra = extra + extra_report
272275
except Exception:
273276
pass

0 commit comments

Comments
 (0)