SeleniumBase
SeleniumBase copied to clipboard
When is the function "def activate_recorder()"" in the base_case.py file called?
Hi author, I am very interested in your SeleniumBase project.I have a confusion and hope to get your answer.
When the web page URL is opened through the command, a prompt such as "SeleniumBase Recorder ACTIVE" will pop up in the lower right corner of the window for a few seconds. I am curious when this recorder is activated? By looking at the code in base_case.py there is a function called "activate_recorder"". But I don't know where this function is called?In browser_launch.py "_add_chrome_recorder_extension" This function loads a recorder_zip. Between this and activate_recorder Is there any connection?
Looking forward to your reply, thanks.
Hi @anlanone,
The self.activate_recorder() method is a second way of activating the recorder for situations when someone can't use the Chromium extension. It uses the same JavaScript that the Recorder extension uses. The only difference is that if you navigate to a different page, you have to call self.activate_recorder() again if you want to continue recording.
More details here: https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/recorder_mode.md
Hi @mdmintz , When I am using seleniumbase to open an electron desktop application, after activating the recorder and completing the recording action, I enter c in the command window, the program runs in the “_get_recorded_actions_on_active_tab“”function and keeps getting stuck, and then a timeout error is reported. Please help me to see what is the reason? The error message is as follows:
d:\seleniumproject2\seleniumbase-master\myrecorder.py(20)test_recording() 18 print(f"self.xvfb:{self.xvfb}") 19 if self.recorder_ext and not self.xvfb: ---> 20 import ipdb; ipdb.set_trace()
ipdb> c -------tearDown------- --------__process_recorded_actions--------- -----__process_recorded_actions------ ['CDwindow-2BC30BEA1F24EBF3B8A2BBB77EA0F35D', 'CDwindow-40399D9B2B78CD4339527598A523C698', 'CDwindow-65E6155690A712EFC77F6930F102A2E5', 'CDwindow-72D8E749AEBE008FE1C84879734B79D7'] ------ __get_recorded_actions_on_active_tab----- F ========================================================================================= FAILURES ========================================================================================= _______________________________________________________________________________ RecorderTests.test_recording _______________________________________________________________________________ seleniumbase\fixtures\base_case.py:13480: in tearDown self.__process_recorded_actions() seleniumbase\fixtures\base_case.py:3775: in __process_recorded_actions tab_actions = self.__get_recorded_actions_on_active_tab() seleniumbase\fixtures\base_case.py:3741: in __get_recorded_actions_on_active_tab actions = self.get_session_storage_item("recorded_actions") seleniumbase\fixtures\base_case.py:7381: in get_session_storage_item if not self.__is_valid_storage_url(): seleniumbase\fixtures\base_case.py:7305: in __is_valid_storage_url url = self.get_current_url() seleniumbase\fixtures\base_case.py:873: in get_current_url current_url = self.driver.current_url d:\users\xiaxm\appdata\local\programs\python\python37\lib\site-packages\selenium\webdriver\remote\webdriver.py:529: in current_url return self.execute(Command.GET_CURRENT_URL)['value'] d:\users\xiaxm\appdata\local\programs\python\python37\lib\site-packages\selenium\webdriver\remote\webdriver.py:435: in execute self.error_handler.check_response(response)
self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x000002B3DD3D73C8> response = {'status': 500, 'value': '{"value":{"error":"timeout","message":"timeout: Timed out receiving message from renderer: 3...\n\tRtlGetAppContainerNamedObjectPath [0x77B17A9E+286]\n\tRtlGetAppContainerNamedObjectPath [0x77B17A6E+238]\n"}}'}
def check_response(self, response: Dict[str, Any]) -> None:
"""
Checks that a JSON response from the WebDriver does not have an error.
:Args:
- response - The JSON response from the WebDriver server as a dictionary
object.
:Raises: If the response contains an error message.
"""
status = response.get('status', None)
if not status or status == ErrorCode.SUCCESS:
return
value = None
message = response.get("message", "")
screen: str = response.get("screen", "")
stacktrace = None
if isinstance(status, int):
value_json = response.get('value', None)
if value_json and isinstance(value_json, str):
import json
try:
value = json.loads(value_json)
if len(value.keys()) == 1:
value = value['value']
status = value.get('error', None)
if not status:
status = value.get("status", ErrorCode.UNKNOWN_ERROR)
message = value.get("value") or value.get("message")
if not isinstance(message, str):
value = message
message = message.get('message')
else:
message = value.get('message', None)
except ValueError:
pass
exception_class: Type[WebDriverException]
if status in ErrorCode.NO_SUCH_ELEMENT:
exception_class = NoSuchElementException
elif status in ErrorCode.NO_SUCH_FRAME:
exception_class = NoSuchFrameException
elif status in ErrorCode.NO_SUCH_SHADOW_ROOT:
exception_class = NoSuchShadowRootException
elif status in ErrorCode.NO_SUCH_WINDOW:
exception_class = NoSuchWindowException
elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
exception_class = StaleElementReferenceException
elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
exception_class = ElementNotVisibleException
elif status in ErrorCode.INVALID_ELEMENT_STATE:
exception_class = InvalidElementStateException
elif status in ErrorCode.INVALID_SELECTOR \
or status in ErrorCode.INVALID_XPATH_SELECTOR \
or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
exception_class = InvalidSelectorException
elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
exception_class = ElementNotSelectableException
elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
exception_class = ElementNotInteractableException
elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
exception_class = InvalidCookieDomainException
elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
exception_class = UnableToSetCookieException
elif status in ErrorCode.TIMEOUT:
exception_class = TimeoutException
elif status in ErrorCode.SCRIPT_TIMEOUT:
exception_class = TimeoutException
elif status in ErrorCode.UNKNOWN_ERROR:
exception_class = WebDriverException
elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
exception_class = UnexpectedAlertPresentException
elif status in ErrorCode.NO_ALERT_OPEN:
exception_class = NoAlertPresentException
elif status in ErrorCode.IME_NOT_AVAILABLE:
exception_class = ImeNotAvailableException
elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
exception_class = ImeActivationFailedException
elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
exception_class = MoveTargetOutOfBoundsException
elif status in ErrorCode.JAVASCRIPT_ERROR:
exception_class = JavascriptException
elif status in ErrorCode.SESSION_NOT_CREATED:
exception_class = SessionNotCreatedException
elif status in ErrorCode.INVALID_ARGUMENT:
exception_class = InvalidArgumentException
elif status in ErrorCode.NO_SUCH_COOKIE:
exception_class = NoSuchCookieException
elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:
exception_class = ScreenshotException
elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:
exception_class = ElementClickInterceptedException
elif status in ErrorCode.INSECURE_CERTIFICATE:
exception_class = InsecureCertificateException
elif status in ErrorCode.INVALID_COORDINATES:
exception_class = InvalidCoordinatesException
elif status in ErrorCode.INVALID_SESSION_ID:
exception_class = InvalidSessionIdException
elif status in ErrorCode.UNKNOWN_METHOD:
exception_class = UnknownMethodException
else:
exception_class = WebDriverException
if not value:
value = response['value']
if isinstance(value, str):
raise exception_class(value)
if message == "" and 'message' in value:
message = value['message']
screen = None # type: ignore[assignment]
if 'screen' in value:
screen = value['screen']
stacktrace = None
st_value = value.get('stackTrace') or value.get('stacktrace')
if st_value:
if isinstance(st_value, str):
stacktrace = st_value.split('\n')
else:
stacktrace = []
try:
for frame in st_value:
line = self._value_or_default(frame, 'lineNumber', '')
file = self._value_or_default(frame, 'fileName', '<anonymous>')
if line:
file = f"{file}:{line}"
meth = self._value_or_default(frame, 'methodName', '<anonymous>')
if 'className' in frame:
meth = "{}.{}".format(frame['className'], meth)
msg = " at %s (%s)"
msg = msg % (meth, file)
stacktrace.append(msg)
except TypeError:
pass
if exception_class == UnexpectedAlertPresentException:
alert_text = None
if 'data' in value:
alert_text = value['data'].get('text')
elif 'alert' in value:
alert_text = value['alert'].get('text')
raise exception_class(message, screen, stacktrace, alert_text) # type: ignore[call-arg] # mypy is not smart enough here
raise exception_class(message, screen, stacktrace)
E selenium.common.exceptions.TimeoutException: Message: timeout: Timed out receiving message from renderer: 300.000 E (Session info: chrome=89.0.4389.82) E Stacktrace: E Backtrace: E Ordinal0 [0x0012E7D3+124883] E Ordinal0 [0x0012E7B1+124849] E GetHandleVerifier [0x00378688+193832] E GetHandleVerifier [0x0036C079+143129] E GetHandleVerifier [0x0036B45E+140030] E GetHandleVerifier [0x0036B7F7+140951] E GetHandleVerifier [0x00373DEA+175242] E GetHandleVerifier [0x0037D549+213993] E GetHandleVerifier [0x0037F3DB+221819] E GetHandleVerifier [0x0036BA88+141608] E GetHandleVerifier [0x0037D49A+213818] E GetHandleVerifier [0x003BD673+476435] E GetHandleVerifier [0x003B154B+426987] E GetHandleVerifier [0x00394FFD+310941] E GetHandleVerifier [0x00395D8E+314414] E GetHandleVerifier [0x00395D19+314297] E GetHandleVerifier [0x004531EC+1089676] E GetHandleVerifier [0x004517C9+1082985] E GetHandleVerifier [0x004513A3+1081923] E GetHandleVerifier [0x0054D9FD+2115741] E Ordinal0 [0x0027B82E+1488942] E Ordinal0 [0x00215A7D+1071741] E Ordinal0 [0x0021559B+1070491] E Ordinal0 [0x002154B1+1070257] E Ordinal0 [0x0024FF53+1310547] E BaseThreadInitThunk [0x76ECFA29+25] E RtlGetAppContainerNamedObjectPath [0x77B17A9E+286] E RtlGetAppContainerNamedObjectPath [0x77B17A6E+238]
d:\users\xiaxm\appdata\local\programs\python\python37\lib\site-packages\selenium\webdriver\remote\errorhandler.py:247: TimeoutException ================================================================================= short test summary info ================================================================================== FAILED myrecorder.py::RecorderTests::test_recording - selenium.common.exceptions.TimeoutException: Message: timeout: Timed out receiving message from renderer: 300.000 1 failed in 404.81s (0:06:44)
Does the value of your Session Storage recorded_actions look similar to the following? (it's from a different web site, but it has the correct formatting)
[["begin","https://www.saucedemo.com","https://www.saucedemo.com/",1660265942357],["input","input#user-name","standard_user",1660265944538],["input","input#password","secret_sauce\n",1660265946398],["click","button#add-to-cart-sauce-labs-backpack","",1660265956561],["click","div#shopping_cart_container a","",1660265960456]]
You made modifications to the recorder for your local electron app build, which may have broken the functionality. It still needs the correct Session Storage data for the test generator to work.
Hi @mdmintz , When I am using seleniumbase to open an electron desktop application, after activating the recorder and completing the recording action, I enter c in the command window,the program runs into the __process_recorded_actions function. And I found that there is a function called "self.switch_to_window(window)". If read before switch_to_window ,self.get_session_storage_item('recorded_actions') has value as shown below.
[["begin","app://.","app://./index.html#/home",1660363291996],["click","button:contains("调整栏目顺序")","",1660363297095],["click","span.ant-modal-close-x i svg path","",1660363301355],["click","a[href="#/music_download"]","app://./index.html#/music_download",1660363305445],["click","a[href="#/music_cloud"]","app://./index.html#/music_cloud",1660363310345],["click","input#phone","",1660363313832],["click","input#password","",1660363316485]]
But if the read sessionStorage is executed after "switch_to_window" it will run and get stuck until it times out with an error. The error message is as follows.
self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x0000020AF39A9508> response = {'status': 500, 'value': '{"value":{"error":"timeout","message":"timeout: Timed out receiving message from renderer: 3...\n\tRtlGetAppContainerNamedObjectPath [0x77557A9E+286]\n\tRtlGetAppContainerNamedObjectPath [0x77557A6E+238]\n"}}'}
Try to comment out self.switch_to_window(window) if that's giving you issues. If the Electron App only has one window, then that line is not needed.
Thank you, mdmintz. I printed len(self.driver.window_handles) for a total of four windows. Can you tell me what is the mechanism by which self.driver.window_handles is produced? Does the recorded URL change generate a window?
self.driver.window_handles is a list of all open selenium windows/tabs. If your test opens a new window/tab, then a new entry is produced in self.driver.window_handles. If your test closes a window/tab, then an entry is removed from self.driver.window_handles. The Recorder will open a new window during the recording if you click on a link that takes you to a different origin.