From a52e30a81a4f840db826eb771d0fb0f6607fe5d3 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Thu, 23 Dec 2021 16:05:51 -0500 Subject: [PATCH 1/5] Handle a Recorder edge case with duplicate actions --- seleniumbase/fixtures/base_case.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 220afe72edc..baecae1ed7c 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -3367,7 +3367,8 @@ def __process_recorded_actions(self): if ( url1 == url2 or url1 == url2.replace("www.", "") - or (len(url1) > 0 and url2.startswith(url1) + or (len(url1) > 0 + and (url2.startswith(url1) or "?search" in url1) and (int(srt_actions[n][3]) - int( srt_actions[n-1][3]) < 6500)) ): From f8b4d00383d595bcb4a0722c7403539c3006fcf9 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Thu, 23 Dec 2021 16:07:15 -0500 Subject: [PATCH 2/5] Refresh Python dependencies --- requirements.txt | 4 ++-- setup.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index dbb947a5703..679e4ac6c3e 100755 --- a/requirements.txt +++ b/requirements.txt @@ -4,12 +4,12 @@ packaging>=20.9;python_version<"3.6" packaging>=21.3;python_version>="3.6" setuptools>=44.1.1;python_version<"3.5" setuptools>=50.3.2;python_version>="3.5" and python_version<"3.6" -setuptools>=59.6.0;python_version>="3.6" +setuptools>=60.0.5;python_version>="3.6" setuptools-scm>=5.0.2;python_version<"3.6" setuptools-scm>=6.3.2;python_version>="3.6" tomli>=1.2.2;python_version>="3.6" and python_version<"3.7" tomli>=2.0.0;python_version>="3.7" -wheel>=0.37.0 +wheel>=0.37.1 attrs>=21.2.0 PyYAML>=6.0;python_version>="3.6" traitlets>=4.3.3;python_version<"3.7" diff --git a/setup.py b/setup.py index 9e122ee5764..7e235d29c32 100755 --- a/setup.py +++ b/setup.py @@ -106,6 +106,7 @@ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Topic :: Internet", + "Topic :: Internet :: WWW/HTTP :: Browsers", "Topic :: Scientific/Engineering", "Topic :: Software Development", "Topic :: Software Development :: Quality Assurance", @@ -123,12 +124,12 @@ 'packaging>=21.3;python_version>="3.6"', 'setuptools>=44.1.1;python_version<"3.5"', 'setuptools>=50.3.2;python_version>="3.5" and python_version<"3.6"', - 'setuptools>=59.6.0;python_version>="3.6"', + 'setuptools>=60.0.5;python_version>="3.6"', 'setuptools-scm>=5.0.2;python_version<"3.6"', 'setuptools-scm>=6.3.2;python_version>="3.6"', 'tomli>=1.2.2;python_version>="3.6" and python_version<"3.7"', 'tomli>=2.0.0;python_version>="3.7"', - "wheel>=0.37.0", + "wheel>=0.37.1", "attrs>=21.2.0", 'PyYAML>=6.0;python_version>="3.6"', 'traitlets>=4.3.3;python_version<"3.7"', From 66a0b9374e546cc5fa8938c0e8e8cf4228b757e7 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Thu, 23 Dec 2021 16:07:49 -0500 Subject: [PATCH 3/5] Update the Recorder docs --- help_docs/recorder_mode.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/help_docs/recorder_mode.md b/help_docs/recorder_mode.md index e738b1152a5..66bf3ec54db 100755 --- a/help_docs/recorder_mode.md +++ b/help_docs/recorder_mode.md @@ -7,7 +7,7 @@ -(For the latest Recorder improvements, use SeleniumBase version ``2.3.0`` or newer.) +(For the latest Recorder improvements, use SeleniumBase version ``2.3.2`` or newer.) 🔴 To make a new recording with Recorder Mode, you can use ``sbase mkrec`` or ``sbase codegen``): @@ -15,7 +15,7 @@ sbase mkrec TEST_NAME.py --url=URL ``` -If the file already exists, you'll get an error. If no URL is provided, you'll start on a blank page and will need to navigate somewhere for the Recorder to activate. (The Recorder captures events on URLs that start with ``https``, ``http``, or ``file``.) The command above runs an empty test that stops at a breakpoint so that you can perform manual browser actions for the Recorder. When you have finished recording, type "``c``" on the command-line and press ``[ENTER]`` to let the test continue from the breakpoint. The test will then complete and a file called ``TEST_NAME_rec.py`` will be automatically created in the ``./recordings`` folder. That file will get copied back to the original folder with the name you gave it. (You can run with Edge instead of Chrome by adding ``--edge`` to the command above. For headed Linux machines, add ``--gui`` to prevent the default headless mode on Linux.) +If the file already exists, you'll get an error. If no URL is provided, you'll start on a blank page and will need to navigate somewhere for the Recorder to activate. (The Recorder captures events on URLs that start with ``https``, ``http``, or ``file``.) The command above runs an empty test that stops at a breakpoint so that you can perform manual browser actions for the Recorder. When you have finished recording, type "``c``" on the command-line and press ``[ENTER]`` to continue from the breakpoint. The test will complete and a file called ``TEST_NAME_rec.py`` will be automatically created in the ``./recordings`` folder. That file will get copied back to the original folder with the name you gave it. (You can run with Edge instead of Chrome by adding ``--edge`` to the command above. For headed Linux machines, add ``--gui`` to prevent the default headless mode on Linux.) Example: @@ -50,7 +50,9 @@ sbase recorder 🔴 While a recording is in progress, you can press the ``[ESC]`` key to pause the Recorder. To resume the recording, you can hit the ``[~`]`` key, which is located directly below the ``[ESC]`` key on most keyboards. -🔴 From within Recorder Mode there are two additional modes: "Assert Element Mode" and "Assert Text Mode". To switch into "Assert Element Mode", press the {^}-key (SHIFT+6): 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 {&}-key (SHIFT+7): 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. +🔴 From within Recorder Mode there are two additional modes: "Assert Element Mode" and "Assert Text Mode". To switch into "Assert Element Mode", press the {^}-key (SHIFT+6): 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 {&}-key (SHIFT+7): 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 buttons without triggering default "click" behavior, mouse-down on the button and then mouse-up somewhere else. (This 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.). Press ESC once to leave the Assertion Modes, but it'll stop the Recorder if you press it again. 🔴 For extra flexibility, the ``sbase mkrec`` command can be split into four separate commands: @@ -66,7 +68,7 @@ cp ./recordings/TEST_NAME_rec.py ./TEST_NAME.py The first command creates a boilerplate test with a breakpoint; the second command runs the test with the Recorder activated; the third command prints the completed test to the console; and the fourth command replaces the initial boilerplate with the completed test. If you're just experimenting with the Recorder, you can run the second command as many times as you want, and it'll override previous recordings saved to ``./recordings/TEST_NAME_rec.py``. (Note that ``-s`` is needed to allow breakpoints, unless you already have a ``pytest.ini`` file present with ``addopts = --capture=no`` in it. The ``-q`` is optional, which shortens ``pytest`` console output.) -🔴 You can also use the Recorder to add code to an existing test. To do that, you'll first need to create a breakpoint in your code where you want to insert manual browser actions: +🔴 You can also use the Recorder to add code to an existing test. To do that, you'll first need to create a breakpoint in your code to insert manual browser actions: ```python import ipdb; ipdb.set_trace() @@ -100,13 +102,15 @@ pytest TEST_NAME.py --trace --rec -s *************************************************** ``` -🔴 Recorder Mode works by saving your recorded actions into the browser's sessionStorage. SeleniumBase then reads from the browser's sessionStorage to take the raw data and generate a full test from it. Keep in mind that sessionStorage is only present for a website while the browser tab remains on a web page of the same domain/origin. If you leave that domain/origin, the sessionStorage of that tab will no longer have the raw data that SeleniumBase needs to create a full recording. To compensate for this, all links to web pages of a different domain/origin will automatically open a new tab for you while in Recorder Mode. Additionally, the SeleniumBase self.open(URL) method will also open a new tab for you in Recorder Mode if the domain/origin is different from the current URL. If you need to navigate to a different domain/origin from within the same tab, call self.save_recorded_actions() first, which saves the recorded data for later. When the recorded test completes, SeleniumBase will scan the sessionStorage of all open browser tabs for the data it needs to generate the complete SeleniumBase automation script. +🔴 Recorder Mode works by saving your recorded actions into the browser's sessionStorage. SeleniumBase then reads from the browser's sessionStorage to take the raw data and generate a full test from it. Keep in mind that sessionStorage is only present while the browser tab remains in the same domain/origin. (The sessionStorage of that tab goes away if you leave that domain/origin.) To compensate, links to web pages of different domain/origin will automatically open a new tab for you in Recorder Mode. + +🔴 Additionally, the SeleniumBase self.open(URL) method will also open a new tab for you in Recorder Mode if the domain/origin is different from the current URL. If you need to navigate to a different domain/origin from within the same tab, call self.save_recorded_actions() first, which saves the recorded data for later. When a recorded test completes, SeleniumBase scans the sessionStorage data of all open browser tabs for generating the completed script. -🔴 As an alternative to activating Recorder Mode with the --rec command-line arg, you can also call self.activate_recorder() from your tests. This is only useful for tests that stay on the same URL because the Recorder will turn off when leaving the page where you activated the Recorder. The reason for this is because the standard Recorder Mode functions as a Chrome extension (and persists wherever the browser goes), whereas the method call version of Recorder Mode only lives in the page where it was called. +🔴 As an alternative to activating Recorder Mode with the --rec command-line arg, you can also call self.activate_recorder() from your tests. Using the Recorder this way is only useful for tests that stay on the same URL. This is because the standard Recorder Mode functions as a Chrome extension and persists wherever the browser goes. (This version only stays on the page where called.) -🔴 (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.) +🔴 (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 both URLs share the same sessionStorage, and that changes persist to different URLs of the same domain/origin. 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.) -🔴 Inside recorded tests, you might find the self.open_if_not_url(URL) method, which opens 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 browser action (such as a click) has brought the test to that page. This method not only prevents an extra page load if not needed, but it also lets people know what page the test went to after a browser action was performed. +🔴 Inside recorded tests, you might find the self.open_if_not_url(URL) method, which opens the URL given if the browser is not currently on that page. SeleniumBase uses this method in recorded scripts when the Recorder detects that a browser action changed the current URL. This method prevents an unnecessary page load and shows what page the test visited after a browser action. -------- From ed197ed69d04cb3df4b9798beb67c331bea13fd3 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Thu, 23 Dec 2021 16:08:10 -0500 Subject: [PATCH 4/5] Version 2.3.2 --- seleniumbase/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 9140bdffe80..cdebdc60882 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "2.3.1" +__version__ = "2.3.2" From d6b6e16c0684601ab326144367758c154f9619c2 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Thu, 23 Dec 2021 16:18:12 -0500 Subject: [PATCH 5/5] Refresh Python dependencies --- requirements.txt | 3 ++- setup.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 679e4ac6c3e..d6fa70bae8f 100755 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,8 @@ packaging>=20.9;python_version<"3.6" packaging>=21.3;python_version>="3.6" setuptools>=44.1.1;python_version<"3.5" setuptools>=50.3.2;python_version>="3.5" and python_version<"3.6" -setuptools>=60.0.5;python_version>="3.6" +setuptools>=59.6.0;python_version>="3.6" and python_version<"3.7" +setuptools>=60.0.5;python_version>="3.7" setuptools-scm>=5.0.2;python_version<"3.6" setuptools-scm>=6.3.2;python_version>="3.6" tomli>=1.2.2;python_version>="3.6" and python_version<"3.7" diff --git a/setup.py b/setup.py index 7e235d29c32..9165f92bbb4 100755 --- a/setup.py +++ b/setup.py @@ -124,7 +124,8 @@ 'packaging>=21.3;python_version>="3.6"', 'setuptools>=44.1.1;python_version<"3.5"', 'setuptools>=50.3.2;python_version>="3.5" and python_version<"3.6"', - 'setuptools>=60.0.5;python_version>="3.6"', + 'setuptools>=59.6.0;python_version>="3.6" and python_version<"3.7"', + 'setuptools>=60.0.5;python_version>="3.7"', 'setuptools-scm>=5.0.2;python_version<"3.6"', 'setuptools-scm>=6.3.2;python_version>="3.6"', 'tomli>=1.2.2;python_version>="3.6" and python_version<"3.7"',