Skip to content

Commit 727db02

Browse files
authored
Merge pull request #1044 from seleniumbase/recorder-asserts-without-full-clicks
Several updates to various areas
2 parents cc5d6cc + e7b202f commit 727db02

File tree

14 files changed

+114
-75
lines changed

14 files changed

+114
-75
lines changed

examples/hack_the_planet.py

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -179,30 +179,12 @@ def test_all_your_base_are_belong_to_us(self):
179179
self.highlight('button#live-engage-btn', loops=6, scroll=False)
180180

181181
self.open("https://www.snapchat.com/")
182-
self.set_text_content('a[href*="download"]', "ALL")
183-
self.set_text_content('a[href*="spotlight"]', "YOUR")
184-
self.set_text_content('a[href="https://story.snapchat.com"]', "BASE")
185-
self.set_text_content('a[href*="map"]', "ARE")
186-
self.set_text_content('a[href*="forbusiness"]', "BELONG")
187-
self.set_text_content('a[href*="spectacles"]', "TO")
188-
self.set_text_content('a[href="/create"]', "US")
189-
self.set_text_content('a[href*="lensstudio"]', ".")
190-
self.set_text_content('a[href*="kit"]', ".")
191-
self.set_text_content('a[href*="snapcodes"]', ".")
192182
self.set_text_content("h1", ayb)
193-
self.set_text_content("a.button-large span > span", abtu)
183+
self.set_text_content("form .button-large span span", abtu)
194184
zoom_in = 'a.button-large span{zoom: 1.2;-moz-transform: scale(1.2);}'
195185
self.add_css_style(zoom_in)
196-
self.highlight("header", loops=1)
197-
self.highlight('a[href*="download"]', loops=1)
198-
self.highlight('a[href*="spotlight"]', loops=1)
199-
self.highlight('a[href="https://story.snapchat.com"]', loops=2)
200-
self.highlight('a[href*="map"]', loops=1, scroll=False)
201-
self.highlight('a[href*="forbusiness"]', loops=1)
202-
self.highlight('a[href*="spectacles"]', loops=1)
203-
self.highlight('a[href="/create"]', loops=2)
204-
self.highlight("h1", loops=4, scroll=False)
205-
self.highlight("a.button-large span > span", loops=5, scroll=False)
186+
self.highlight("h1", loops=6, scroll=False)
187+
self.highlight("form .button-large span span", loops=8, scroll=False)
206188

207189
self.open("https://store.steampowered.com/")
208190
self.set_text_content('div.content a[href*="/about/"]', " ")

examples/test_mfa_login.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from seleniumbase import BaseCase
2+
3+
4+
class TestMFALogin(BaseCase):
5+
def test_mfa_login(self):
6+
self.open("https://seleniumbase.io/realworld/login")
7+
self.type("#username", "demo_user")
8+
self.type("#password", "secret_pass")
9+
totp_code = self.get_totp_code("GAXG2MTEOR3DMMDG")
10+
self.type("#totpcode", totp_code)
11+
self.click("#log-in")
12+
self.highlight("img#image1")
13+
self.assert_text("Welcome!", "h1")
14+
self.save_screenshot_to_logs()

help_docs/method_summary.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,16 @@ self.set_content_to_frame(frame, timeout=None)
202202
self.set_content_to_default(nested=True)
203203

204204
self.open_new_window(switch_to=True)
205+
# Duplicates: self.open_new_tab(switch_to=True)
205206

206207
self.switch_to_window(window, timeout=None)
208+
# Duplicates: self.switch_to_tab(tab, timeout=None)
207209

208210
self.switch_to_default_window()
211+
# Duplicates: self.switch_to_default_tab()
209212

210213
self.switch_to_newest_window()
214+
# Duplicates: self.switch_to_newest_tab()
211215

212216
self.get_new_driver(
213217
browser=None, headless=None, locale_code=None, protocol=None,
@@ -398,7 +402,9 @@ self.get_chromedriver_version()
398402

399403
self.is_chromedriver_too_old()
400404

401-
self.get_google_auth_password(totp_key=None)
405+
self.get_totp_code(totp_key=None)
406+
# Duplicates: self.get_google_auth_password(totp_key=None)
407+
# self.get_google_auth_code(totp_key=None)
402408

403409
self.convert_css_to_xpath(css)
404410

help_docs/recorder_mode.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<img src="https://seleniumbase.io/cdn/img/sb_recorder_notification.png" title="SeleniumBase" width="380">
88

9-
(This tutorial assumes you are using SeleniumBase version ``2.0.10`` or newer.)
9+
(This tutorial assumes that you are using SeleniumBase version ``2.1.0`` or newer.)
1010

1111
🔴 To make a new recording with Recorder Mode, you can use ``sbase mkrec`` or ``sbase codegen``):
1212

@@ -40,7 +40,7 @@ ipdb> c
4040
4141
🔴 While a recording is in progress, you can press the ``[ESC]`` key to pause the recording. To resume the recording, you can hit the ``[~`]`` key, which is located directly below the ``[ESC]`` key on most keyboards.
4242
43-
🔴 From within Recorder Mode there are two additional modes: "Assert Element Mode" and "Assert Text Mode". To switch into "Assert Element Mode", press the <code>{^}-key (SHIFT+6)</code>: The border will become purple, and you'll be able to click on elements to assert from your test. To switch into "Assert Text Mode", press the <code>{&}-key (SHIFT+7)</code>: The border will become teal, and you'll be able to click on elements for asserting text from your test. While using either of the two special Assertion Modes, certain actions such as clicking on links won't have any effect. This lets you make assertions on elements without navigating away from the page, etc. To return back to the original Recorder Mode, press any key other than SHIFT or BACKSPACE (Eg: Press ``CONTROL``, etc.). You can also press ESC once to leave the Assertion Modes, but if you press it again, it'll stop the Recorder.
43+
🔴 From within Recorder Mode there are two additional modes: "Assert Element Mode" and "Assert Text Mode". To switch into "Assert Element Mode", press the <code>{^}-key (SHIFT+6)</code>: The border will become purple, and you'll be able to click on elements to assert from your test. To switch into "Assert Text Mode", press the <code>{&}-key (SHIFT+7)</code>: The border will become teal, and you'll be able to click on elements for asserting text from your test. While using either of the two special Assertion Modes, certain actions such as clicking on links won't have any effect. This lets you make assertions on elements without navigating away from the page, etc. To add an assertion for a button without triggering its default behavior via a "click" action, mouse-down on the button and then mouse-up somewhere else, which prevents a detected click while still recording the assert. To return back to the original Recorder Mode, press any key other than SHIFT or BACKSPACE (Eg: Press ``CONTROL``, etc.). You can also press ESC once to leave the Assertion Modes, but if you press it again, it'll stop the Recorder.
4444
4545
🔴 For extra flexibility, you can break up the ``sbase mkrec`` command into three separate commands so that you can pick & choose how you use the Recorder:
4646

mkdocs.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ markdown_extensions:
2727
# Configuration
2828
theme:
2929
name: material
30-
logo: img/green_logo2.png
30+
logo: img/green_logo.png
3131
favicon: img/green_logo3.png
3232
language: en
3333
include_homepage_in_sidebar: true
@@ -49,7 +49,7 @@ theme:
4949
- navigation.instant
5050
palette:
5151
scheme: default
52-
primary: blue
52+
primary: teal
5353
accent: indigo
5454
font:
5555
text: Roboto
@@ -124,18 +124,19 @@ nav:
124124
- MySQL Instructions: help_docs/mysql_installation.md
125125
- Demo Pages:
126126
- Demo Page / Demo Site: https://seleniumbase.io/demo_page
127+
- MFA Login Demo Page: https://seleniumbase.io/realworld/login
127128
- TinyMCE Demo Page: https://seleniumbase.io/tinymce/
128-
- Drag & Drop Demo Page: https://seleniumbase.io/other/drag_and_drop
129129
- Virtual Device Farm: https://seleniumbase.io/devices/
130+
- Drag & Drop Demo Page: https://seleniumbase.io/other/drag_and_drop
131+
- HTML Playground Page: https://seleniumbase.io/w3schools/
132+
- SeleniumBase in iframe: https://seleniumbase.io/w3schools/sbase
130133
- Error Demo Page: https://seleniumbase.io/error_page/
131134
- Page with broken links: https://seleniumbase.io/other/broken_page
132135
- W3Schools iframes: https://seleniumbase.io/w3schools/iframes
133136
- W3Schools doubleclick: https://seleniumbase.io/w3schools/double_click
134137
- W3Schools checkboxes: https://seleniumbase.io/w3schools/checkboxes
135138
- W3Schools drag & drop: https://seleniumbase.io/w3schools/drag_drop
136139
- W3Schools radio buttons: https://seleniumbase.io/w3schools/radio_buttons
137-
- SeleniumBase in iframe: https://seleniumbase.io/w3schools/sbase
138-
- HTML Playground Page: https://seleniumbase.io/w3schools/
139140
- Presentations:
140141
- Presenter Demo: https://seleniumbase.io/other/presenter.html
141142
- Core Presentation: https://seleniumbase.io/other/core_presentation.html

mkdocs_build/requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ livereload==2.6.3;python_version>="3.6"
66
joblib==1.1.0;python_version>="3.6"
77
Markdown==3.3.4;python_version>="3.6"
88
MarkupSafe==2.0.1;python_version>="3.6"
9-
pyparsing==3.0.3;python_version>="3.6"
9+
pyparsing==2.4.7;python_version>="3.6"
1010
keyring==23.2.1;python_version>="3.6"
1111
pkginfo==1.7.1;python_version>="3.6"
1212
Jinja2==3.0.2;python_version>="3.6"
@@ -21,7 +21,7 @@ lunr==0.6.1;python_version>="3.6"
2121
nltk==3.6.5;python_version>="3.6"
2222
watchdog==2.1.6;python_version>="3.6"
2323
mkdocs==1.2.3;python_version>="3.6"
24-
mkdocs-material==7.3.5;python_version>="3.6"
24+
mkdocs-material==7.3.6;python_version>="3.6"
2525
mkdocs-exclude-search==0.5.2;python_version>="3.6"
2626
mkdocs-simple-hooks==0.1.3
2727
mkdocs-material-extensions==1.0.3;python_version>="3.6"

requirements.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pip>=20.3.4;python_version<"3.6"
22
pip>=21.3.1;python_version>="3.6"
33
packaging>=20.9;python_version<"3.6"
4-
packaging>=21.0;python_version>="3.6"
4+
packaging>=21.2;python_version>="3.6"
55
typing-extensions>=3.10.0.2
66
setuptools>=44.1.1;python_version<"3.5"
77
setuptools>=50.3.2;python_version>="3.5" and python_version<"3.6"
@@ -43,7 +43,7 @@ more-itertools==5.0.0;python_version<"3.5"
4343
more-itertools==8.10.0;python_version>="3.5"
4444
cssselect==1.1.0
4545
filelock==3.2.1;python_version<"3.6"
46-
filelock==3.3.1;python_version>="3.6"
46+
filelock==3.3.2;python_version>="3.6"
4747
fasteners==0.16;python_version<"3.5"
4848
fasteners==0.16.3;python_version>="3.5"
4949
execnet==1.9.0
@@ -89,7 +89,7 @@ decorator==5.1.0;python_version>="3.5"
8989
ipython==5.10.0;python_version<"3.5"
9090
ipython==7.9.0;python_version>="3.5" and python_version<"3.6"
9191
ipython==7.16.1;python_version>="3.6" and python_version<"3.7"
92-
ipython==7.28.0;python_version>="3.7"
92+
ipython==7.29.0;python_version>="3.7"
9393
matplotlib-inline==0.1.3;python_version>="3.7"
9494
colorama==0.4.4
9595
platformdirs==2.0.2;python_version<"3.6"
@@ -118,7 +118,7 @@ pdfminer.six==20211012;python_version>="3.6"
118118
# ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.)
119119

120120
coverage==5.5;python_version<"3.6"
121-
coverage==6.0.2;python_version>="3.6"
121+
coverage==6.1;python_version>="3.6"
122122
pytest-cov==2.12.1;python_version<"3.6"
123123
pytest-cov==3.0.0;python_version>="3.6"
124124
flake8==3.7.9;python_version<"3.5"

seleniumbase/extensions/recorder.zip

10 Bytes
Binary file not shown.

seleniumbase/fixtures/base_case.py

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2590,6 +2590,9 @@ def open_new_window(self, switch_to=True):
25902590
self.wait_for_ready_state_complete()
25912591

25922592
def switch_to_window(self, window, timeout=None):
2593+
""" Switches control of the browser to the specified window.
2594+
The window can be an integer: 0 -> 1st tab, 1 -> 2nd tab, etc...
2595+
Or it can be a list item from self.driver.window_handles """
25932596
self.__check_scope()
25942597
if not timeout:
25952598
timeout = settings.SMALL_TIMEOUT
@@ -2916,7 +2919,8 @@ def get_new_driver(
29162919
return new_driver
29172920

29182921
def switch_to_driver(self, driver):
2919-
"""Sets self.driver to the specified driver.
2922+
"""Switches control of the browser to the specified driver.
2923+
Also sets the self.driver variable to the specified driver.
29202924
You may need this if using self.get_new_driver() in your code."""
29212925
self.__check_scope()
29222926
self.driver = driver
@@ -5191,12 +5195,12 @@ def is_chromedriver_too_old(self):
51915195
return True # chromedriver is too old! Please upgrade!
51925196
return False
51935197

5194-
def get_google_auth_password(self, totp_key=None):
5198+
def get_totp_code(self, totp_key=None):
51955199
"""Returns a time-based one-time password based on the
5196-
Google Authenticator password algorithm. Works with Authy.
5197-
If "totp_key" is not specified, defaults to using the one
5198-
provided in seleniumbase/config/settings.py
5199-
Google Auth passwords expire and change at 30-second intervals.
5200+
Google Authenticator algorithm. Works with Authy and Okta.
5201+
If the "totp_key" is not specified, this method defaults
5202+
to using the one provided in [seleniumbase/config/settings.py].
5203+
Google Authenticator codes expire & change at 30-sec intervals.
52005204
If the fetched password expires in the next 1.5 seconds, waits
52015205
for a new one before returning it (may take up to 1.5 seconds).
52025206
See https://pyotp.readthedocs.io/en/latest/ for details."""
@@ -6023,6 +6027,25 @@ def reload_page(self):
60236027
""" Same as self.refresh_page() """
60246028
self.refresh_page()
60256029

6030+
def open_new_tab(self, switch_to=True):
6031+
""" Same as self.open_new_window() """
6032+
self.open_new_window(switch_to=switch_to)
6033+
6034+
def switch_to_tab(self, tab, timeout=None):
6035+
""" Same as self.switch_to_window()
6036+
Switches control of the browser to the specified window.
6037+
The window can be an integer: 0 -> 1st tab, 1 -> 2nd tab, etc...
6038+
Or it can be a list item from self.driver.window_handles """
6039+
self.switch_to_window(window=tab, timeout=timeout)
6040+
6041+
def switch_to_default_tab(self):
6042+
""" Same as self.switch_to_default_window() """
6043+
self.switch_to_default_window()
6044+
6045+
def switch_to_newest_tab(self):
6046+
""" Same as self.switch_to_newest_window() """
6047+
self.switch_to_newest_window()
6048+
60266049
def input(
60276050
self, selector, text, by=By.CSS_SELECTOR, timeout=None, retry=False
60286051
):
@@ -6140,6 +6163,14 @@ def assert_element_not_present(
61406163
self.wait_for_element_absent(selector, by=by, timeout=timeout)
61416164
return True
61426165

6166+
def get_google_auth_password(self, totp_key=None):
6167+
""" Same as self.get_totp_code() """
6168+
return self.get_totp_code(totp_key=totp_key)
6169+
6170+
def get_google_auth_code(self, totp_key=None):
6171+
""" Same as self.get_totp_code() """
6172+
return self.get_totp_code(totp_key=totp_key)
6173+
61436174
def assert_no_broken_links(self, multithreaded=True):
61446175
""" Same as self.assert_no_404_errors() """
61456176
self.assert_no_404_errors(multithreaded=multithreaded)
@@ -7276,17 +7307,15 @@ def extract_chart(self, chart_name=None):
72767307
############
72777308

72787309
def create_tour(self, name=None, theme=None):
7279-
"""Creates a tour for a website. By default, the Shepherd JavaScript
7280-
Library is used with the Shepherd "Light" / "Arrows" theme.
7310+
"""Creates a guided tour for any website.
7311+
The default theme is the IntroJS Library.
72817312
@Params
72827313
name - If creating multiple tours at the same time,
72837314
use this to select the tour you wish to add steps to.
7284-
theme - Sets the default theme for the tour.
7285-
Choose from "light"/"arrows", "dark", "default", "square",
7286-
and "square-dark". ("arrows" is used if None is selected.)
7287-
Alternatively, you may use a different JavaScript Library
7288-
as the theme. Those include "IntroJS", "DriverJS",
7289-
"Hopscotch", and "Bootstrap".
7315+
theme - Sets the default theme for the website tour. Available themes:
7316+
"Bootstrap", "DriverJS", "Hopscotch", "IntroJS", "Shepherd".
7317+
The "Shepherd" library also contains multiple variation themes:
7318+
"light"/"arrows", "dark", "default", "square", "square-dark".
72907319
"""
72917320
if not name:
72927321
name = "default"
@@ -7308,20 +7337,20 @@ def create_tour(self, name=None, theme=None):
73087337
self.create_shepherd_tour(name, theme="light")
73097338
elif theme.lower() == "light":
73107339
self.create_shepherd_tour(name, theme="light")
7311-
elif theme.lower() == "dark":
7312-
self.create_shepherd_tour(name, theme="dark")
73137340
elif theme.lower() == "arrows":
73147341
self.create_shepherd_tour(name, theme="light")
7342+
elif theme.lower() == "dark":
7343+
self.create_shepherd_tour(name, theme="dark")
73157344
elif theme.lower() == "square":
73167345
self.create_shepherd_tour(name, theme="square")
73177346
elif theme.lower() == "square-dark":
73187347
self.create_shepherd_tour(name, theme="square-dark")
73197348
elif theme.lower() == "default":
73207349
self.create_shepherd_tour(name, theme="default")
73217350
else:
7322-
self.create_shepherd_tour(name, theme)
7351+
self.create_introjs_tour(name)
73237352
else:
7324-
self.create_shepherd_tour(name, theme="light")
7353+
self.create_introjs_tour(name)
73257354

73267355
def create_shepherd_tour(self, name=None, theme=None):
73277356
"""Creates a Shepherd JS website tour.

seleniumbase/fixtures/js_utils.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from seleniumbase import config as sb_config
1111
from seleniumbase.config import settings
1212
from seleniumbase.fixtures import constants
13-
from seleniumbase.fixtures import shared_utils
1413

1514

1615
def wait_for_ready_state_complete(driver, timeout=settings.LARGE_TIMEOUT):
@@ -24,10 +23,14 @@ def wait_for_ready_state_complete(driver, timeout=settings.LARGE_TIMEOUT):
2423
because readyState == "interactive" may be good enough.
2524
(Previously, tests would fail immediately if exceeding the timeout.)
2625
"""
26+
if sb_config.time_limit and not sb_config.recorder_mode:
27+
from seleniumbase.fixtures import shared_utils
28+
2729
start_ms = time.time() * 1000.0
2830
stop_ms = start_ms + (timeout * 1000.0)
2931
for x in range(int(timeout * 10)):
30-
shared_utils.check_if_time_limit_exceeded()
32+
if sb_config.time_limit and not sb_config.recorder_mode:
33+
shared_utils.check_if_time_limit_exceeded()
3134
try:
3235
ready_state = driver.execute_script("return document.readyState")
3336
except WebDriverException:

0 commit comments

Comments
 (0)