diff --git a/docs/requirements.txt b/docs/requirements.txt
index 875139aee47..8f6c4a2fc4b 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -20,7 +20,7 @@ lunr==0.6.0;python_version>="3.6"
nltk==3.6.4;python_version>="3.6"
watchdog==2.1.6;python_version>="3.6"
mkdocs==1.2.2;python_version>="3.6"
-mkdocs-material==7.3.0;python_version>="3.6"
+mkdocs-material==7.3.1;python_version>="3.6"
mkdocs-exclude-search==0.5.2;python_version>="3.6"
mkdocs-simple-hooks==0.1.3
mkdocs-material-extensions==1.0.3;python_version>="3.6"
diff --git a/examples/ReadMe.md b/examples/ReadMe.md
index 2d75dbe0e60..01a98a19053 100755
--- a/examples/ReadMe.md
+++ b/examples/ReadMe.md
@@ -1,4 +1,4 @@
-[
](https://github.com/seleniumbase/SeleniumBase/)
+[
](https://github.com/seleniumbase/SeleniumBase/)
Running Example Tests:
diff --git a/examples/test_show_file_choosers.py b/examples/test_show_file_choosers.py
new file mode 100644
index 00000000000..b1339aa9790
--- /dev/null
+++ b/examples/test_show_file_choosers.py
@@ -0,0 +1,26 @@
+"""
+self.show_file_choosers() is used to show hidden file-upload fields.
+Verify that one can choose a file after the hidden input is visible.
+"""
+import os
+from seleniumbase import BaseCase
+
+
+class FileUpload(BaseCase):
+ def test_show_file_choosers(self):
+ self.open("https://imgbb.com/upload")
+ choose_file_selector = 'input[type="file"]'
+ uploaded_image = "#anywhere-upload-queue li.queue-item"
+ self.assert_element_not_visible(choose_file_selector)
+ self.show_file_choosers()
+ self.assert_element(choose_file_selector)
+ self.assert_attribute(choose_file_selector, "value", "")
+ self.assert_element_not_visible(uploaded_image)
+ dir_name = os.path.dirname(os.path.abspath(__file__))
+ my_file = "screenshot.png"
+ file_path = os.path.join(dir_name, "example_logs/%s" % my_file)
+ self.choose_file(choose_file_selector, file_path)
+ seen_path = "%s\\%s" % ("C:\\fakepath", my_file)
+ self.assert_attribute(choose_file_selector, "value", seen_path)
+ self.demo_mode = True
+ self.assert_element(uploaded_image)
diff --git a/help_docs/customizing_test_runs.md b/help_docs/customizing_test_runs.md
index 9b4075be6c0..6ca64a4accf 100755
--- a/help_docs/customizing_test_runs.md
+++ b/help_docs/customizing_test_runs.md
@@ -1,4 +1,4 @@
-[
](https://github.com/seleniumbase/SeleniumBase/)
+[
](https://github.com/seleniumbase/SeleniumBase/)
## pytest options for SeleniumBase
diff --git a/help_docs/recorder_mode.md b/help_docs/recorder_mode.md
index cbfb0f192b9..404b56a734a 100755
--- a/help_docs/recorder_mode.md
+++ b/help_docs/recorder_mode.md
@@ -1,4 +1,4 @@
-[
](https://github.com/seleniumbase/SeleniumBase/)
+[
](https://github.com/seleniumbase/SeleniumBase/)
Recorder Mode
@@ -12,12 +12,14 @@
pytest TEST_NAME.py --recorder -s
```
-🔴 To add your own actions inside the test, you'll need to create a breakpoint inside your test to activate Debug Mode:
+🔴 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".)
```python
import ipdb; ipdb.set_trace()
```
+🔴 The Recorder will capture browser actions on URLs that begin with ``https:``, ``http:``, and ``file:``. (The Recorder won't work on ``data:`` URLS.)
+
🔴 You can also activate Debug Mode at the start of your test by adding ``--trace`` as a ``pytest`` command-line option:
```bash
@@ -58,7 +60,7 @@ class RecorderTest(BaseCase):
🔴 (Note that same domain/origin is not the same as same URL. Example: https://xkcd.com/353/
and https://xkcd.com/1537/
are two different URLs with the same domain/origin. That means that both URLs will share the same sessionStorage
data, and that any changes to sessionStorage
from one URL will carry on to the sessionStorage
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: self.get_origin()
, which returns the value of window.location.origin
from the browser's console.)
-🔴 The launch of Recorder Mode has brought a new SeleniumBase method along with it: self.open_if_not_url(URL)
. 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.
+🔴 The launch of Recorder Mode has brought a new SeleniumBase method along with it: self.open_if_not_url(URL)
. 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.
🔴 SeleniumBase 1.66.1
adds the ability to record changes to "Choose File" input
fields. Sometimes the "Choose File" input field is hidden on websites, so self.show_file_choosers()
was added to get around this edge case. Version 1.66.1
also adds self.set_content_to_frame(frame)
, which lets you record actions inside of iframes.
@@ -72,6 +74,8 @@ class RecorderTest(BaseCase):
🔴 SeleniumBase 1.66.6
adds more selector options and improves the algorithm for converting recorded actions into SeleniumBase code.
+🔴 SeleniumBase 1.66.7
improves Recorder Mode post-processing and automatically adds self.show_file_choosers()
if file-upload fields are hidden when calling self.choose_file(selector, file_path)
.
+
--------
To learn more about SeleniumBase, check out the Docs Site:
diff --git a/mkdocs.yml b/mkdocs.yml
index ae6882ad6de..803b58e86b1 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -32,7 +32,7 @@ theme:
language: en
include_homepage_in_sidebar: true
sticky_navigation: true
- # collapse_navigation: false
+ collapse_navigation: true
# titles_only: false
include_search_page: false
search_index_only: true
@@ -43,9 +43,10 @@ theme:
- toc.integrate
- navigation.indexes
# - navigation.sections
- # - navigation.expand
+ - navigation.expand
# - navigation.tabs
- # - navigation.instant
+ - navigation.tracking
+ - navigation.instant
palette:
scheme: default
primary: blue
@@ -59,7 +60,6 @@ theme:
plugins:
- search:
separator: '[\s]+'
- prebuild_index: false
lang: en
- exclude-search:
exclude:
@@ -107,9 +107,9 @@ nav:
- MasterQA: examples/master_qa/ReadMe.md
- Jenkins on Azure: integrations/azure/jenkins/ReadMe.md
- Jenkins on Google Cloud: integrations/google_cloud/ReadMe.md
- - Katalon Recorder: integrations/katalon/ReadMe.md
- - Old Recorder / Export: seleniumbase/utilities/selenium_ide/ReadMe.md
- NodeJS Test Runner: https://github.com/seleniumbase/SeleniumBase/tree/master/integrations/node_js
+ - Katalon Recorder Export: integrations/katalon/ReadMe.md
+ - Selenium IDE Export: seleniumbase/utilities/selenium_ide/ReadMe.md
- Help Docs:
- Table of Contents: help_docs/ReadMe.md
- JS Package Manager: help_docs/js_package_manager.md
diff --git a/requirements.txt b/requirements.txt
index 48a845df116..14814d9ec67 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -36,7 +36,8 @@ msedge-selenium-tools==3.141.3
more-itertools==5.0.0;python_version<"3.5"
more-itertools==8.10.0;python_version>="3.5"
cssselect==1.1.0
-filelock==3.2.0
+filelock==3.2.1;python_version<"3.6"
+filelock==3.3.0;python_version>="3.6"
fasteners==0.16;python_version<"3.5"
fasteners==0.16.3;python_version>="3.5"
execnet==1.9.0
@@ -108,7 +109,8 @@ pdfminer.six==20201018;python_version>="3.5"
# --- Testing Requirements --- #
# ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.)
-coverage==5.5
+coverage==5.5;python_version<"3.6"
+coverage==6.0;python_version>="3.6"
pytest-cov==2.12.1
flake8==3.7.9;python_version<"3.5"
flake8==3.9.2;python_version>="3.5"
diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py
index 65294ffaa0a..9ed09eddf6e 100755
--- a/seleniumbase/__version__.py
+++ b/seleniumbase/__version__.py
@@ -1,2 +1,2 @@
# seleniumbase package
-__version__ = "1.66.6"
+__version__ = "1.66.7"
diff --git a/seleniumbase/console_scripts/ReadMe.md b/seleniumbase/console_scripts/ReadMe.md
index 48977bbf425..3a53b7a2c55 100755
--- a/seleniumbase/console_scripts/ReadMe.md
+++ b/seleniumbase/console_scripts/ReadMe.md
@@ -1,4 +1,4 @@
-[
](https://github.com/seleniumbase/SeleniumBase/blob/master/README.md)
+[
](https://github.com/seleniumbase/SeleniumBase/)
## Console Scripts
@@ -345,3 +345,7 @@ You can start, restart, or stop the Grid Hub server.
Controls the Selenium Grid node, which serves as a
worker machine for your Selenium Grid Hub server.
You can start, restart, or stop the Grid node.
+
+--------
+
+[
](https://github.com/seleniumbase/SeleniumBase/blob/master/README.md)
diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py
index c6b01ac9d49..52087fef1b2 100755
--- a/seleniumbase/fixtures/base_case.py
+++ b/seleniumbase/fixtures/base_case.py
@@ -3273,7 +3273,7 @@ def __process_recorded_actions(self):
and srt_actions[n-1][0] == "chfil"
):
srt_actions[n-1][0] = "_skip"
- srt_actions[n][2] = srt_actions[n-1][1]
+ srt_actions[n][2] = srt_actions[n-1][1][1]
origins = []
for n in range(len(srt_actions)):
if (
@@ -3297,6 +3297,18 @@ def __process_recorded_actions(self):
srt_actions[n][0] = "h_clk"
srt_actions[n][1] = srt_actions[n-1][1][0]
srt_actions[n][2] = srt_actions[n-1][1][1]
+ for n in range(len(srt_actions)):
+ if srt_actions[n][0] == "chfil" and srt_actions[n][2] in origins:
+ srt_actions[n][0] = "cho_f"
+ srt_actions[n][2] = srt_actions[n][1][1]
+ srt_actions[n][1] = srt_actions[n][1][0]
+ for n in range(len(srt_actions)):
+ if (
+ srt_actions[n][0] == "sh_fc"
+ and n > 0
+ and srt_actions[n-1][0] == "sh_fc"
+ ):
+ srt_actions[n-1][0] = "_skip"
ext_actions = []
ext_actions.append("js_cl")
ext_actions.append("as_el")
@@ -3312,6 +3324,7 @@ def __process_recorded_actions(self):
ext_actions.append("sw_dc")
ext_actions.append("s_c_f")
ext_actions.append("s_c_d")
+ ext_actions.append("sh_fc")
for n in range(len(srt_actions)):
if srt_actions[n][0] in ext_actions:
origin = srt_actions[n][2]
@@ -3521,6 +3534,9 @@ def __process_recorded_actions(self):
else:
sb_actions.append("self.%s('%s')" % (
method, action[1][0]))
+ elif action[0] == "sh_fc":
+ cb_method = "show_file_choosers"
+ sb_actions.append('self.%s()' % cb_method)
elif action[0] == "c_box":
cb_method = "check_if_unchecked"
if action[2] == "no":
@@ -3546,7 +3562,6 @@ def __process_recorded_actions(self):
if len(sb_actions) > 0:
for action in sb_actions:
data.append(" " + action)
- print(" " + action)
else:
data.append(" pass")
data.append("")
@@ -4120,6 +4135,15 @@ def show_file_choosers(self):
self.execute_script(script)
except Exception:
pass
+ if self.recorder_mode:
+ url = self.get_current_url()
+ if url and len(url) > 0:
+ if ("http:") in url or ("https:") in url or ("file:") in url:
+ if self.get_session_storage_item("pause_recorder") == "no":
+ time_stamp = self.execute_script("return Date.now();")
+ origin = self.get_origin()
+ action = ["sh_fc", "", origin, time_stamp]
+ self.__extra_actions.append(action)
def get_domain_url(self, url):
self.__check_scope()
@@ -4440,6 +4464,15 @@ def choose_file(
self.__demo_mode_highlight_if_active(selector, by)
if not self.demo_mode and not self.slow_mode:
self.__scroll_to_element(element, selector, by)
+ else:
+ choose_file_selector = 'input[type="file"]'
+ if self.is_element_present(choose_file_selector):
+ if not self.is_element_visible(choose_file_selector):
+ self.show_file_choosers()
+ if self.is_element_visible(selector, by=by):
+ self.__demo_mode_highlight_if_active(selector, by)
+ if not self.demo_mode and not self.slow_mode:
+ self.__scroll_to_element(element, selector, by)
pre_action_url = self.driver.current_url
if self.recorder_mode:
url = self.get_current_url()
@@ -4448,7 +4481,8 @@ def choose_file(
if self.get_session_storage_item("pause_recorder") == "no":
time_stamp = self.execute_script("return Date.now();")
origin = self.get_origin()
- action = ["chfil", file_path, origin, time_stamp]
+ sele_file_path = [selector, file_path]
+ action = ["chfil", sele_file_path, origin, time_stamp]
self.__extra_actions.append(action)
if type(abs_path) is int or type(abs_path) is float:
abs_path = str(abs_path)
diff --git a/setup.py b/setup.py
index 001826d114b..60faf65a915 100755
--- a/setup.py
+++ b/setup.py
@@ -152,7 +152,8 @@
'more-itertools==5.0.0;python_version<"3.5"',
'more-itertools==8.10.0;python_version>="3.5"',
"cssselect==1.1.0",
- "filelock==3.2.0",
+ 'filelock==3.2.1;python_version<"3.6"',
+ 'filelock==3.3.0;python_version>="3.6"',
'fasteners==0.16;python_version<"3.5"',
'fasteners==0.16.3;python_version>="3.5"',
"execnet==1.9.0",
@@ -224,7 +225,8 @@
extras_require={
# pip install -e .[coverage]
"coverage": [
- "coverage==5.5",
+ 'coverage==5.5;python_version<"3.6"',
+ 'coverage==6.0;python_version>="3.6"',
"pytest-cov==2.12.1",
],
# pip install -e .[flake]