Skip to content

Commit 4daea7a

Browse files
authored
Merge pull request #1015 from seleniumbase/recorder-mode-assertions
Recorder Mode assertions and more
2 parents c58eac1 + d131307 commit 4daea7a

File tree

12 files changed

+161
-38
lines changed

12 files changed

+161
-38
lines changed

docs/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ bleach==4.1.0
1919
lunr==0.6.0;python_version>="3.6"
2020
nltk==3.6.5;python_version>="3.6"
2121
watchdog==2.1.6;python_version>="3.6"
22-
mkdocs==1.2.2;python_version>="3.6"
22+
mkdocs==1.2.3;python_version>="3.6"
2323
mkdocs-material==7.3.3;python_version>="3.6"
2424
mkdocs-exclude-search==0.5.2;python_version>="3.6"
2525
mkdocs-simple-hooks==0.1.3

examples/translations/french_test_1.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def test_exemple_1(self):
1111
self.cliquer("#searchform button")
1212
self.vérifier_texte("Crème brûlée", "#firstHeading")
1313
self.vérifier_élément('img[alt*="Crème brûlée"]')
14-
self.taper("#searchform input", "Jardin des Tuileries")
14+
self.js_taper("#searchform input", "Jardin des Tuileries")
1515
self.cliquer("#searchform button")
1616
self.vérifier_texte("Jardin des Tuileries", "#firstHeading")
1717
self.vérifier_élément('img[alt*="Jardin des Tuileries"]')

help_docs/method_summary.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,10 @@ self.sleep(seconds)
247247

248248
self.install_addon(xpi_file)
249249

250+
self.activate_demo_mode()
251+
252+
self.deactivate_demo_mode()
253+
250254
self.activate_design_mode()
251255

252256
self.deactivate_design_mode()

help_docs/recorder_mode.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ class RecorderTest(BaseCase):
8484

8585
<p>🔴 SeleniumBase <code>1.66.12</code> adds the ability to instantly create a new test recording by running <code>sbase mkrec FILE.py</code>. Once the browser spins up, you can open a new web page and start performing actions that will get recorded and saved to the file you specified.</p>
8686

87+
<p>🔴 SeleniumBase <code>1.66.13</code> lets you add assertions for elements and text while making a recording. To add an element assertion, press <code>[^](SHIFT+6)</code>, (the border will become purple) then click on elements that you'd like to assert. To add a text assertion, press <code>[&](SHIFT+7)</code>, (the border will become orange) then click on text elements that you'd like to assert. To go back to the regular Record Mode, press any other key. While in the special assertion modes, certain actions such as clicking on links won't have any effect. This lets you make assertions on elements without certain actions getting in the way.</p>
88+
8789
--------
8890

8991
<div>To learn more about SeleniumBase, check out the Docs Site:</div>

requirements.txt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ setuptools-scm>=6.3.2;python_version>="3.6"
1111
tomli>=1.2.1;python_version>="3.6"
1212
wheel>=0.37.0
1313
attrs>=21.2.0
14-
PyYAML>=5.4.1;python_version>="3.6"
14+
PyYAML>=6.0;python_version>="3.6"
1515
sortedcontainers==2.4.0
1616
certifi>=2021.10.8
1717
six==1.16.0
@@ -23,10 +23,10 @@ parso==0.8.2;python_version>="3.6"
2323
jedi==0.17.2;python_version<"3.6"
2424
jedi==0.18.0;python_version>="3.6"
2525
idna==2.10;python_version<"3.6"
26-
idna==3.2;python_version>="3.6"
26+
idna==3.3;python_version>="3.6"
2727
chardet==3.0.4;python_version<"3.5"
2828
chardet==4.0.0;python_version>="3.5"
29-
charset-normalizer==2.0.6;python_version>="3.5"
29+
charset-normalizer==2.0.7;python_version>="3.5"
3030
urllib3==1.26.7
3131
requests==2.26.0;python_version<"3.5"
3232
requests==2.25.1;python_version>="3.5" and python_version<"3.6"
@@ -96,7 +96,7 @@ pymysql==0.10.1;python_version<"3.6"
9696
pymysql==1.0.2;python_version>="3.6"
9797
pyotp==2.6.0
9898
boto==2.49.0
99-
cffi==1.14.6
99+
cffi==1.15.0
100100
toml==0.10.2
101101
Pillow==6.2.2;python_version<"3.5"
102102
Pillow==7.2.0;python_version>="3.5" and python_version<"3.6"
@@ -105,13 +105,14 @@ rich==10.12.0;python_version>="3.6" and python_version<"4.0"
105105
tornado==5.1.1;python_version<"3.5"
106106
tornado==6.1;python_version>="3.5"
107107
pdfminer.six==20191110;python_version<"3.5"
108-
pdfminer.six==20201018;python_version>="3.5"
108+
pdfminer.six==20201018;python_version>="3.5" and python_version<"3.6"
109+
pdfminer.six==20211012;python_version>="3.6"
109110

110111
# --- Testing Requirements --- #
111112
# ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.)
112113

113114
coverage==5.5;python_version<"3.6"
114-
coverage==6.0.1;python_version>="3.6"
115+
coverage==6.0.2;python_version>="3.6"
115116
pytest-cov==2.12.1;python_version<"3.6"
116117
pytest-cov==3.0.0;python_version>="3.6"
117118
flake8==3.7.9;python_version<"3.5"

seleniumbase/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# seleniumbase package
2-
__version__ = "1.66.12"
2+
__version__ = "1.66.13"

seleniumbase/console_scripts/run.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
sbase options
1212
sbase mkdir ui_tests
1313
sbase mkfile new_test.py
14+
sbase mkrec new_test.py
1415
sbase mkpres new_presentation.py
1516
sbase mkchart new_chart.py
1617
sbase convert webdriver_unittest_file.py
@@ -74,6 +75,7 @@ def show_basic_usage():
7475
sc += " options (List common pytest options)\n"
7576
sc += " mkdir [DIRECTORY] [OPTIONS]\n"
7677
sc += " mkfile [FILE.py] [OPTIONS]\n"
78+
sc += " mkrec [FILE.py]\n"
7779
sc += " mkpres [FILE.py] [LANG]\n"
7880
sc += " mkchart [FILE.py] [LANG]\n"
7981
sc += " print [FILE] [OPTIONS]\n"

seleniumbase/extensions/recorder.zip

341 Bytes
Binary file not shown.

seleniumbase/fixtures/base_case.py

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def __init__(self, *args, **kwargs):
9797
self.__last_page_source = None
9898
self.__skip_reason = None
9999
self.__dont_record_js_click = False
100+
self.__new_window_on_rec_open = True
100101
self.__overrided_default_timeouts = False
101102
self.__added_pytest_html_extra = None
102103
self.__deferred_assert_count = 0
@@ -143,6 +144,11 @@ def open(self, url):
143144
# Convert URLs such as "://google.com" into "https://google.com"
144145
url = "https" + url
145146
if self.recorder_mode:
147+
time_stamp = self.execute_script("return Date.now();")
148+
origin = self.get_origin()
149+
action = ["_url_", origin, url, time_stamp]
150+
self.__extra_actions.append(action)
151+
if self.recorder_mode and self.__new_window_on_rec_open:
146152
c_url = self.driver.current_url
147153
if ("http:") in c_url or ("https:") in c_url or ("file:") in c_url:
148154
if self.get_domain_url(url) != self.get_domain_url(c_url):
@@ -3125,6 +3131,12 @@ def install_addon(self, xpi_file):
31253131
xpi_path = os.path.abspath(xpi_file)
31263132
self.driver.install_addon(xpi_path, temporary=True)
31273133

3134+
def activate_demo_mode(self):
3135+
self.demo_mode = True
3136+
3137+
def deactivate_demo_mode(self):
3138+
self.demo_mode = False
3139+
31283140
def activate_design_mode(self):
31293141
# Activate Chrome's Design Mode, which lets you edit a site directly.
31303142
# See: https://twitter.com/sulco/status/1177559150563344384
@@ -3267,6 +3279,16 @@ def __process_recorded_actions(self):
32673279
url2 = url2[:-1]
32683280
if url1 == url2:
32693281
srt_actions[n-1][0] = "_skip"
3282+
elif url2.startswith(url1):
3283+
srt_actions[n][0] = "f_url"
3284+
for n in range(len(srt_actions)):
3285+
if (
3286+
srt_actions[n][0] == "input"
3287+
and n > 0
3288+
and srt_actions[n-1][0] == "input"
3289+
and srt_actions[n-1][2] == ""
3290+
):
3291+
srt_actions[n-1][0] = "_skip"
32703292
for n in range(len(srt_actions)):
32713293
if (
32723294
(srt_actions[n][0] == "begin" or srt_actions[n][0] == "_url_")
@@ -3336,8 +3358,10 @@ def __process_recorded_actions(self):
33363358
):
33373359
srt_actions[n-1][0] = "_skip"
33383360
ext_actions = []
3361+
ext_actions.append("_url_")
33393362
ext_actions.append("js_cl")
33403363
ext_actions.append("js_ca")
3364+
ext_actions.append("js_ty")
33413365
ext_actions.append("as_el")
33423366
ext_actions.append("as_ep")
33433367
ext_actions.append("asenv")
@@ -3365,8 +3389,21 @@ def __process_recorded_actions(self):
33653389
origin = srt_actions[n][2][1]
33663390
if origin.endswith("/"):
33673391
origin = origin[0:-1]
3392+
if srt_actions[n][0] == "js_ty":
3393+
srt_actions[n][2] = srt_actions[n][1][1]
3394+
srt_actions[n][1] = srt_actions[n][1][0]
3395+
if srt_actions[n][0] == "_url_" and origin not in origins:
3396+
origins.append(origin)
33683397
if origin not in origins:
33693398
srt_actions[n][0] = "_skip"
3399+
for n in range(len(srt_actions)):
3400+
if (
3401+
srt_actions[n][0] == "input"
3402+
and n > 0
3403+
and srt_actions[n-1][0] == "js_ty"
3404+
and srt_actions[n][2] == srt_actions[n-1][2]
3405+
):
3406+
srt_actions[n][0] = "_skip"
33703407
for n in range(len(srt_actions)):
33713408
cleaned_actions.append(srt_actions[n])
33723409
for action in srt_actions:
@@ -3392,8 +3429,10 @@ def __process_recorded_actions(self):
33923429
sb_actions.append('self.%s("%s")' % (method, action[1]))
33933430
else:
33943431
sb_actions.append("self.%s('%s')" % (method, action[1]))
3395-
elif action[0] == "input":
3432+
elif action[0] == "input" or action[0] == "js_ty":
33963433
method = "type"
3434+
if action[0] == "js_ty":
3435+
method = "js_type"
33973436
text = action[2].replace("\n", "\\n")
33983437
if '"' not in action[1] and '"' not in text:
33993438
sb_actions.append('self.%s("%s", "%s")' % (
@@ -5233,6 +5272,7 @@ def set_value(
52335272
text = str(text)
52345273
value = re.escape(text)
52355274
value = self.__escape_quotes_if_needed(value)
5275+
pre_escape_css_selector = css_selector
52365276
css_selector = re.escape(css_selector) # Add "\\" to special chars
52375277
css_selector = self.__escape_quotes_if_needed(css_selector)
52385278
the_type = None
@@ -5247,6 +5287,12 @@ def set_value(
52475287
value,
52485288
)
52495289
self.execute_script(script)
5290+
if self.recorder_mode:
5291+
time_stamp = self.execute_script("return Date.now();")
5292+
origin = self.get_origin()
5293+
sel_tex = [pre_escape_css_selector, text]
5294+
action = ["js_ty", sel_tex, origin, time_stamp]
5295+
self.__extra_actions.append(action)
52505296
else:
52515297
script = """jQuery('%s')[0].value='%s';""" % (css_selector, value)
52525298
self.safe_execute_script(script)
@@ -10336,6 +10382,11 @@ def setUp(self, masterqa_mode=False):
1033610382
self._dash_initialized = True
1033710383
self.__process_dashboard(False, init=True)
1033810384

10385+
# Set the JS start time for Recorder Mode if reusing the session.
10386+
# Use this to skip saving recorded actions from previous tests.
10387+
if self.recorder_mode and self._reuse_session:
10388+
self.__js_start_time = int(time.time() * 1000.0)
10389+
1033910390
has_url = False
1034010391
if self._reuse_session:
1034110392
if not hasattr(sb_config, "shared_driver"):
@@ -10360,18 +10411,27 @@ def setUp(self, masterqa_mode=False):
1036010411
except Exception:
1036110412
pass
1036210413
if self._reuse_session and sb_config.shared_driver and has_url:
10414+
good_start_page = False
10415+
if self.recorder_ext:
10416+
self.__js_start_time = int(time.time() * 1000.0)
1036310417
if self.start_page and len(self.start_page) >= 4:
1036410418
if page_utils.is_valid_url(self.start_page):
10419+
good_start_page = True
10420+
self.__new_window_on_rec_open = False
1036510421
self.open(self.start_page)
10422+
self.__new_window_on_rec_open = True
1036610423
else:
1036710424
new_start_page = "http://" + self.start_page
1036810425
if page_utils.is_valid_url(new_start_page):
10426+
good_start_page = True
1036910427
self.open(new_start_page)
10370-
elif self._crumbs:
10428+
if self.recorder_ext or (self._crumbs and not good_start_page):
1037110429
if self.get_current_url() != "data:,":
10430+
self.__new_window_on_rec_open = False
1037210431
self.open("data:,")
10373-
else:
10374-
pass
10432+
self.__new_window_on_rec_open = True
10433+
if self.recorder_ext:
10434+
self.__js_start_time = int(time.time() * 1000.0)
1037510435
else:
1037610436
# Launch WebDriver for both Pytest and Nosetests
1037710437
self.driver = self.get_new_driver(
@@ -10431,11 +10491,6 @@ def setUp(self, masterqa_mode=False):
1043110491
# Call this once in case of multiple setUp() calls in the same test
1043210492
self.__start_time_ms = sb_config.start_time_ms
1043310493

10434-
# Set the JS start time for Recorder Mode if reusing the session.
10435-
# Use this to skip saving recorded actions from previous tests.
10436-
if self.recorder_mode and self._reuse_session:
10437-
self.__js_start_time = self.execute_script("return Date.now();")
10438-
1043910494
def __set_last_page_screenshot(self):
1044010495
"""self.__last_page_screenshot is only for pytest html report logs.
1044110496
self.__last_page_screenshot_png is for all screenshot log files."""

seleniumbase/fixtures/shared_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def __time_limit_exceeded(message):
6969

7070

7171
def check_if_time_limit_exceeded():
72-
if sb_config.time_limit:
72+
if sb_config.time_limit and not sb_config.recorder_mode:
7373
time_limit = sb_config.time_limit
7474
now_ms = int(time.time() * 1000)
7575
if now_ms > sb_config.start_time_ms + sb_config.time_limit_ms:

0 commit comments

Comments
 (0)