SeleniumBase icon indicating copy to clipboard operation
SeleniumBase copied to clipboard

When is the function "def activate_recorder()"" in the base_case.py file called?

Open anlanone opened this issue 3 years ago • 1 comments

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.

anlanone avatar Aug 09 '22 13:08 anlanone

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

mdmintz avatar Aug 09 '22 14:08 mdmintz

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)

anlanone avatar Aug 12 '22 00:08 anlanone

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.

mdmintz avatar Aug 12 '22 01:08 mdmintz

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"}}'}

anlanone avatar Aug 13 '22 04:08 anlanone

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.

mdmintz avatar Aug 13 '22 04:08 mdmintz

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?

anlanone avatar Aug 14 '22 02:08 anlanone

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.

mdmintz avatar Aug 14 '22 02:08 mdmintz