Skip to content

Commit 63fdb24

Browse files
authored
Merge pull request #995 from seleniumbase/recorder-mode-choose-file-improvements
Recorder updates: Improve "Choose File" processing and more
2 parents aecc892 + b82c2e4 commit 63fdb24

File tree

11 files changed

+93
-21
lines changed

11 files changed

+93
-21
lines changed

docs/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ lunr==0.6.0;python_version>="3.6"
2020
nltk==3.6.4;python_version>="3.6"
2121
watchdog==2.1.6;python_version>="3.6"
2222
mkdocs==1.2.2;python_version>="3.6"
23-
mkdocs-material==7.3.0;python_version>="3.6"
23+
mkdocs-material==7.3.1;python_version>="3.6"
2424
mkdocs-exclude-search==0.5.2;python_version>="3.6"
2525
mkdocs-simple-hooks==0.1.3
2626
mkdocs-material-extensions==1.0.3;python_version>="3.6"

examples/ReadMe.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[<img src="https://seleniumbase.io/cdn/img/sb_logo_10t.png" title="SeleniumBase" width="220">](https://github.com/seleniumbase/SeleniumBase/)
1+
[<img src="https://seleniumbase.io/cdn/img/sb_logo_10t.png" title="SeleniumBase" width="240">](https://github.com/seleniumbase/SeleniumBase/)
22

33
<h2><img src="https://seleniumbase.io/img/logo6.png" title="SeleniumBase" width="32" /> Running Example Tests:</h2>
44

examples/test_show_file_choosers.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""
2+
self.show_file_choosers() is used to show hidden file-upload fields.
3+
Verify that one can choose a file after the hidden input is visible.
4+
"""
5+
import os
6+
from seleniumbase import BaseCase
7+
8+
9+
class FileUpload(BaseCase):
10+
def test_show_file_choosers(self):
11+
self.open("https://imgbb.com/upload")
12+
choose_file_selector = 'input[type="file"]'
13+
uploaded_image = "#anywhere-upload-queue li.queue-item"
14+
self.assert_element_not_visible(choose_file_selector)
15+
self.show_file_choosers()
16+
self.assert_element(choose_file_selector)
17+
self.assert_attribute(choose_file_selector, "value", "")
18+
self.assert_element_not_visible(uploaded_image)
19+
dir_name = os.path.dirname(os.path.abspath(__file__))
20+
my_file = "screenshot.png"
21+
file_path = os.path.join(dir_name, "example_logs/%s" % my_file)
22+
self.choose_file(choose_file_selector, file_path)
23+
seen_path = "%s\\%s" % ("C:\\fakepath", my_file)
24+
self.assert_attribute(choose_file_selector, "value", seen_path)
25+
self.demo_mode = True
26+
self.assert_element(uploaded_image)

help_docs/customizing_test_runs.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[<img src="https://seleniumbase.io/cdn/img/sb_logo_10t.png" title="SeleniumBase" width="220">](https://github.com/seleniumbase/SeleniumBase/)
1+
[<img src="https://seleniumbase.io/cdn/img/sb_logo_10t.png" title="SeleniumBase" width="240">](https://github.com/seleniumbase/SeleniumBase/)
22

33
## pytest options for SeleniumBase
44

help_docs/recorder_mode.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[<img src="https://seleniumbase.io/cdn/img/sb_logo_10t.png" title="SeleniumBase" width="220">](https://github.com/seleniumbase/SeleniumBase/)
1+
[<img src="https://seleniumbase.io/cdn/img/sb_logo_10t.png" title="SeleniumBase" width="240">](https://github.com/seleniumbase/SeleniumBase/)
22

33
<h2><img src="https://seleniumbase.io/img/logo6.png" title="SeleniumBase" width="32" /> Recorder Mode</h2>
44

@@ -12,12 +12,14 @@
1212
pytest TEST_NAME.py --recorder -s
1313
```
1414

15-
🔴 To add your own actions inside the test, you'll need to create a breakpoint inside your test to activate Debug Mode:
15+
🔴 To add manual actions, you'll need to create a breakpoint inside your test to activate "Debug Mode" while in "Recorder Mode": (For reference, "Debug Mode" is also known as the "ipdb debugger".)
1616

1717
```python
1818
import ipdb; ipdb.set_trace()
1919
```
2020

21+
🔴 The Recorder will capture browser actions on URLs that begin with ``https:``, ``http:``, and ``file:``. (The Recorder won't work on ``data:`` URLS.)
22+
2123
🔴 You can also activate Debug Mode at the start of your test by adding ``--trace`` as a ``pytest`` command-line option:
2224

2325
```bash
@@ -58,7 +60,7 @@ class RecorderTest(BaseCase):
5860

5961
<p>🔴 (Note that <b>same domain/origin</b> is not the same as <b>same URL</b>. Example: <code>https://xkcd.com/353/</code> and <code>https://xkcd.com/1537/</code> are two different URLs with the <b>same domain/origin</b>. That means that both URLs will share the same <code>sessionStorage</code> data, and that any changes to <code>sessionStorage</code> from one URL will carry on to the <code>sessionStorage</code> of a different URL when the domain/origin is the same. If you want to find out a website's origin during a test, just call: <code>self.get_origin()</code>, which returns the value of <code>window.location.origin</code> from the browser's console.)</p>
6062

61-
<p>🔴 The launch of Recorder Mode has brought a new SeleniumBase method along with it: <code>self.open_if_not_url(URL)</code>. This method will open the URL given if the browser is not currently on that page. This is used as a method in recorded scripts when SeleniumBase detects that a click action has already brought the test to the given page. This method not only prevents an extra page load if not needed, but it also lets people know the current page of the browser at that point in the test.</p>
63+
<p>🔴 The launch of Recorder Mode has brought a new SeleniumBase method along with it: <code>self.open_if_not_url(URL)</code>. This method will open the URL given if the browser is not currently on that page. This is used as a method in recorded scripts when SeleniumBase detects that a click action has already brought the test to the given page. This method not only prevents an extra page load if not needed, but it also lets people know the current page of the browser during that part of the test.</p>
6264

6365
<p>🔴 SeleniumBase <code>1.66.1</code> adds the ability to record changes to <i>"Choose File"</i> <code>input</code> fields. Sometimes the <i>"Choose File"</i> input field is hidden on websites, so <code>self.show_file_choosers()</code> was added to get around this edge case. Version <code>1.66.1</code> also adds <code>self.set_content_to_frame(frame)</code>, which lets you record actions inside of iframes.</p>
6466

@@ -72,6 +74,8 @@ class RecorderTest(BaseCase):
7274

7375
<p>🔴 SeleniumBase <code>1.66.6</code> adds more selector options and improves the algorithm for converting recorded actions into SeleniumBase code.</p>
7476

77+
<p>🔴 SeleniumBase <code>1.66.7</code> improves Recorder Mode post-processing and automatically adds <code>self.show_file_choosers()</code> if file-upload fields are hidden when calling <code>self.choose_file(selector, file_path)</code>.</p>
78+
7579
--------
7680

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

mkdocs.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ theme:
3232
language: en
3333
include_homepage_in_sidebar: true
3434
sticky_navigation: true
35-
# collapse_navigation: false
35+
collapse_navigation: true
3636
# titles_only: false
3737
include_search_page: false
3838
search_index_only: true
@@ -43,9 +43,10 @@ theme:
4343
- toc.integrate
4444
- navigation.indexes
4545
# - navigation.sections
46-
# - navigation.expand
46+
- navigation.expand
4747
# - navigation.tabs
48-
# - navigation.instant
48+
- navigation.tracking
49+
- navigation.instant
4950
palette:
5051
scheme: default
5152
primary: blue
@@ -59,7 +60,6 @@ theme:
5960
plugins:
6061
- search:
6162
separator: '[\s]+'
62-
prebuild_index: false
6363
lang: en
6464
- exclude-search:
6565
exclude:
@@ -107,9 +107,9 @@ nav:
107107
- MasterQA: examples/master_qa/ReadMe.md
108108
- Jenkins on Azure: integrations/azure/jenkins/ReadMe.md
109109
- Jenkins on Google Cloud: integrations/google_cloud/ReadMe.md
110-
- Katalon Recorder: integrations/katalon/ReadMe.md
111-
- Old Recorder / Export: seleniumbase/utilities/selenium_ide/ReadMe.md
112110
- NodeJS Test Runner: https://github.com/seleniumbase/SeleniumBase/tree/master/integrations/node_js
111+
- Katalon Recorder Export: integrations/katalon/ReadMe.md
112+
- Selenium IDE Export: seleniumbase/utilities/selenium_ide/ReadMe.md
113113
- Help Docs:
114114
- Table of Contents: help_docs/ReadMe.md
115115
- JS Package Manager: help_docs/js_package_manager.md

requirements.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ msedge-selenium-tools==3.141.3
3636
more-itertools==5.0.0;python_version<"3.5"
3737
more-itertools==8.10.0;python_version>="3.5"
3838
cssselect==1.1.0
39-
filelock==3.2.0
39+
filelock==3.2.1;python_version<"3.6"
40+
filelock==3.3.0;python_version>="3.6"
4041
fasteners==0.16;python_version<"3.5"
4142
fasteners==0.16.3;python_version>="3.5"
4243
execnet==1.9.0
@@ -108,7 +109,8 @@ pdfminer.six==20201018;python_version>="3.5"
108109
# --- Testing Requirements --- #
109110
# ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.)
110111

111-
coverage==5.5
112+
coverage==5.5;python_version<"3.6"
113+
coverage==6.0;python_version>="3.6"
112114
pytest-cov==2.12.1
113115
flake8==3.7.9;python_version<"3.5"
114116
flake8==3.9.2;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.6"
2+
__version__ = "1.66.7"

seleniumbase/console_scripts/ReadMe.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[<img src="https://seleniumbase.io/cdn/img/super_logo_sb.png" title="SeleniumBase" width="290">](https://github.com/seleniumbase/SeleniumBase/blob/master/README.md)
1+
[<img src="https://seleniumbase.io/cdn/img/sb_logo_10t.png" title="SeleniumBase" width="240">](https://github.com/seleniumbase/SeleniumBase/)
22

33
## Console Scripts
44

@@ -345,3 +345,7 @@ You can start, restart, or stop the Grid Hub server.
345345
Controls the Selenium Grid node, which serves as a
346346
worker machine for your Selenium Grid Hub server.
347347
You can start, restart, or stop the Grid node.
348+
349+
--------
350+
351+
[<img src="https://seleniumbase.io/cdn/img/super_logo_sb.png" title="SeleniumBase" width="290">](https://github.com/seleniumbase/SeleniumBase/blob/master/README.md)

seleniumbase/fixtures/base_case.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3273,7 +3273,7 @@ def __process_recorded_actions(self):
32733273
and srt_actions[n-1][0] == "chfil"
32743274
):
32753275
srt_actions[n-1][0] = "_skip"
3276-
srt_actions[n][2] = srt_actions[n-1][1]
3276+
srt_actions[n][2] = srt_actions[n-1][1][1]
32773277
origins = []
32783278
for n in range(len(srt_actions)):
32793279
if (
@@ -3297,6 +3297,18 @@ def __process_recorded_actions(self):
32973297
srt_actions[n][0] = "h_clk"
32983298
srt_actions[n][1] = srt_actions[n-1][1][0]
32993299
srt_actions[n][2] = srt_actions[n-1][1][1]
3300+
for n in range(len(srt_actions)):
3301+
if srt_actions[n][0] == "chfil" and srt_actions[n][2] in origins:
3302+
srt_actions[n][0] = "cho_f"
3303+
srt_actions[n][2] = srt_actions[n][1][1]
3304+
srt_actions[n][1] = srt_actions[n][1][0]
3305+
for n in range(len(srt_actions)):
3306+
if (
3307+
srt_actions[n][0] == "sh_fc"
3308+
and n > 0
3309+
and srt_actions[n-1][0] == "sh_fc"
3310+
):
3311+
srt_actions[n-1][0] = "_skip"
33003312
ext_actions = []
33013313
ext_actions.append("js_cl")
33023314
ext_actions.append("as_el")
@@ -3312,6 +3324,7 @@ def __process_recorded_actions(self):
33123324
ext_actions.append("sw_dc")
33133325
ext_actions.append("s_c_f")
33143326
ext_actions.append("s_c_d")
3327+
ext_actions.append("sh_fc")
33153328
for n in range(len(srt_actions)):
33163329
if srt_actions[n][0] in ext_actions:
33173330
origin = srt_actions[n][2]
@@ -3521,6 +3534,9 @@ def __process_recorded_actions(self):
35213534
else:
35223535
sb_actions.append("self.%s('%s')" % (
35233536
method, action[1][0]))
3537+
elif action[0] == "sh_fc":
3538+
cb_method = "show_file_choosers"
3539+
sb_actions.append('self.%s()' % cb_method)
35243540
elif action[0] == "c_box":
35253541
cb_method = "check_if_unchecked"
35263542
if action[2] == "no":
@@ -3546,7 +3562,6 @@ def __process_recorded_actions(self):
35463562
if len(sb_actions) > 0:
35473563
for action in sb_actions:
35483564
data.append(" " + action)
3549-
print(" " + action)
35503565
else:
35513566
data.append(" pass")
35523567
data.append("")
@@ -4120,6 +4135,15 @@ def show_file_choosers(self):
41204135
self.execute_script(script)
41214136
except Exception:
41224137
pass
4138+
if self.recorder_mode:
4139+
url = self.get_current_url()
4140+
if url and len(url) > 0:
4141+
if ("http:") in url or ("https:") in url or ("file:") in url:
4142+
if self.get_session_storage_item("pause_recorder") == "no":
4143+
time_stamp = self.execute_script("return Date.now();")
4144+
origin = self.get_origin()
4145+
action = ["sh_fc", "", origin, time_stamp]
4146+
self.__extra_actions.append(action)
41234147

41244148
def get_domain_url(self, url):
41254149
self.__check_scope()
@@ -4440,6 +4464,15 @@ def choose_file(
44404464
self.__demo_mode_highlight_if_active(selector, by)
44414465
if not self.demo_mode and not self.slow_mode:
44424466
self.__scroll_to_element(element, selector, by)
4467+
else:
4468+
choose_file_selector = 'input[type="file"]'
4469+
if self.is_element_present(choose_file_selector):
4470+
if not self.is_element_visible(choose_file_selector):
4471+
self.show_file_choosers()
4472+
if self.is_element_visible(selector, by=by):
4473+
self.__demo_mode_highlight_if_active(selector, by)
4474+
if not self.demo_mode and not self.slow_mode:
4475+
self.__scroll_to_element(element, selector, by)
44434476
pre_action_url = self.driver.current_url
44444477
if self.recorder_mode:
44454478
url = self.get_current_url()
@@ -4448,7 +4481,8 @@ def choose_file(
44484481
if self.get_session_storage_item("pause_recorder") == "no":
44494482
time_stamp = self.execute_script("return Date.now();")
44504483
origin = self.get_origin()
4451-
action = ["chfil", file_path, origin, time_stamp]
4484+
sele_file_path = [selector, file_path]
4485+
action = ["chfil", sele_file_path, origin, time_stamp]
44524486
self.__extra_actions.append(action)
44534487
if type(abs_path) is int or type(abs_path) is float:
44544488
abs_path = str(abs_path)

0 commit comments

Comments
 (0)