Esempio n. 1
0
    def configure_group_for_test(cls, metafunc):
        '''
            Configures **group** fixture for a test.

            Acts only if **group** fixture is present in the signature of a test function or signature(s) of any of its fixture(s) in its fixture hierarchy. 

            To be used in **pytest_generate_tests** hook in **conftest.py**.

            Args:
                metafunc: **pytest**'s MetaFunc object

            Note:
                The **group** fixture yields a **DataRecord** object containing the following keys:
                    - **name**: Group name
                    - **config**: **Configuration** object assigned to the group.
                    - **thread_name**: Thread name for the thread in which the Test Group is running.
        '''

        from arjuna import Arjuna, ArjunaOption, log_debug, C
        from arjuna.tpi.engine.data.markup import record
        log_debug("{} {}".format(metafunc.function, metafunc.fixturenames))

        group_params = Arjuna.get_group_params()
        conf = None
        m = metafunc.function.__module__
        group = record(**group_params).build(context='Group').all_records[0]
        log_debug(
            "Parameterizing distributor for module: {} with group: {}".format(
                m, group))
        metafunc.parametrize("group",
                             argvalues=[group],
                             ids=["G"],
                             indirect=True)
Esempio n. 2
0
 def wait(self, *, max_wait=60, poll_interval=0.5):
     from arjuna import log_debug
     log_debug(
         "Dynamic wait call triggered with max_wait: {}".format(max_wait))
     end_time = time.time() + max_wait
     e = None
     etrace = None
     while (True):
         try:
             if self.is_met():
                 return self.get_call_result()
         except ConditionException as ce:
             raise ce
         except WaitableError as we:
             e = we
             import traceback
             etrace = traceback.format_exc()
             pass
         except Exception as f:
             import traceback
             raise Exception(
                 "An unexpected exception occured in dynamic wait. Message: {}. Trace: {}"
                 .format(str(f), traceback.format_exc()))
         time.sleep(poll_interval)
         ctime = time.time()
         if (ctime > end_time):
             break
     raise ArjunaTimeoutError(self.__class__.__name__, str(e) + etrace)
Esempio n. 3
0
 def __getitem__(self, name):
     from arjuna import log_debug
     if self.has(name):
         return self.__mdict[name]
     else:
         log_debug(f"Meta dict does not have {name}. Returning None.")
         return None
Esempio n. 4
0
 def __getattr__(self, label):
     wmd = self._get_wmd_for_label(label)
     from arjuna import log_debug
     log_debug("Finding element with label: {} and wmd: {}".format(label, wmd))
     try:
         return self._locate_with_wmd(wmd)
     except ArjunaTimeoutError:
         raise GuiWidgetForLabelNotPresentError(self.__gui, label)
Esempio n. 5
0
 def add_element_meta_data(self, name, context, raw_locators, meta):
     wmd = GuiWidgetMetaData.create_wmd(*raw_locators, meta=meta)
     name = name.lower()
     if not self.has(name):
         self.__ns[name] = {}
     self.__ns[name][context] = wmd
     from arjuna import log_debug
     log_debug("Loaded {} label. EMD: {}".format(name, str(wmd)))
Esempio n. 6
0
 def _as_wmd(self):
     '''
         Convert this **GuiWidgetDefinition** to **GuiWidgetMetaData** object
     '''
     wmd = self._as_raw_wmd()
     from arjuna import log_debug
     log_debug("Unformatted Widget def is: " + str(wmd))
     fmt_wmd = wmd.create_formatted_wmd(**self.__fmt_args)
     return fmt_wmd
Esempio n. 7
0
 def find_element(cls, container, byType, byValue):
     from arjuna import log_debug
     log_debug(
         f"Finding element in container:{container} with wtype:{byType} and wvalue:{byValue}"
     )
     try:
         return container.find_element(cls.BY_MAP[byType.upper()], byValue)
     except Exception as e:
         raise GuiWidgetNotFoundError("By.{}={}".format(byType, byValue))
Esempio n. 8
0
 def __init__(self, mdict=None):
     from arjuna import log_debug
     temp_dict = not mdict and CIStringDict() or CIStringDict(mdict)
     self.__mdict = CIStringDict()
     self.__process_type(temp_dict)
     self.__process_relations(temp_dict)
     self.__process_filters(temp_dict)
     self.__process_settings(temp_dict)
     log_debug("Meta dictionary is: {}".format(repr_dict(self.__mdict)))
Esempio n. 9
0
 def __load(self):
     from arjuna import log_debug
     log_debug("Selecting mailbox: {}".format(self.name))
     if self._server._ready:
         MailBoxConditions(self).Select().wait(max_wait=30)
         _, data = self._server._imap.search(None, 'ALL')
         self.__count = sum(1 for num in data[0].split())
         log_debug("Selected mailbox: {}".format(self.name))
     else:
         raise Exception("A mailbox can be selected only with active connection to IMAP server.")
Esempio n. 10
0
    def _externalize(self):
        try:
            self.__guidef = GuiDef(self.__guimgr.name_store, self._automator,
                                   self.label, self.def_file_path)
        except Exception as e:
            import traceback
            raise GuiNamespaceLoadingError(self,
                                           str(e) + traceback.format_exc())

        from arjuna import log_debug
        log_debug("Gui Namespace loading completed for {}.".format(self.label))
Esempio n. 11
0
 def __create_relative_by(cls, byType, byValue, relations):
     from arjuna import log_debug
     relative_by = RelativeBy({byType: byValue})
     for k,v in relations.items():
         try:
             getattr(relative_by, cls.RELATION_MAP[k.lower()])(v)
         except:
             pass
     log_debug("Root" + str(relative_by.root))
     log_debug("Filters" + str(relative_by.filters))
     return relative_by
Esempio n. 12
0
    def locate(self, locator):
        from arjuna import log_debug
        from arjuna.core.error import ArjunaTimeoutError
        from arjuna.tpi.error import GuiWidgetNotPresentError

        wmd = locator._as_wmd()
        log_debug("Finding element with wmd: {}.".format(wmd))
        try:
            return getattr(self.__wmd_finder,
                           wmd.meta["type"].name.lower())(wmd)
        except ArjunaTimeoutError:
            raise GuiWidgetNotPresentError(self.__gui, wmd)
Esempio n. 13
0
 def email_at(self, ordinal, _reload=True):
     '''
     Email at an ordinal/position - human counted, 1 is the oldest email position.
     '''
     from arjuna import log_debug
     log_debug("Reading email at ordinal >{}< from mailbox {} at email server >{}<".format(
         ordinal, self.name, self._server.host
     ))
     if _reload:
         self.__load()
     _, data = self._server._imap.fetch(str(ordinal), '(RFC822)')
     return Email(pyemail.message_from_string(data[0][1].decode()))
Esempio n. 14
0
    def _load_anchor_element(self):
        label = self._gui_def.anchor_element_name

        from arjuna import log_debug
        log_debug(
            "Loading Anchor Element for {} Gui. anchor label in GNS: {}.".
            format(
                self.label,
                self._gui_def.anchor_element_name,
            ))

        if label is not None:
            getattr(self.gns, label)
Esempio n. 15
0
    def _create_firefox(cls,
                        config,
                        driver_path,
                        browser_bin_path,
                        svc_url,
                        proxy=None):
        from selenium.webdriver import Firefox
        from selenium.webdriver import FirefoxOptions
        from selenium.webdriver import FirefoxProfile

        profile = FirefoxProfile()
        # if config["arjuna_options"]["BROWSER_PROXY_ON"]:
        #     proxy = Proxy()
        #     proxy_string = "{}.{}".format(
        #         config["arjuna_options"]["BROWSER_PROXY_HOST"],
        #         config["arjuna_options"]["BROWSER_PROXY_PORT"]
        #     )
        #     proxy.http_proxy = proxy_string
        #     proxy.ssl_proxy = proxy_string
        #     profile.set_proxy(proxy)

        caps = DesiredCapabilities.FIREFOX
        caps.update(config["driverCapabilities"])

        from arjuna import log_debug
        log_debug("Is proxy set for Firefox?: {}".format(proxy is not None))
        if proxy is not None:
            proxy.add_to_capabilities(caps)
            caps['acceptInsecureCerts'] = True

        options = FirefoxOptions()

        if browser_bin_path.lower() != "not_set":
            options.binary_location = browser_bin_path

        if cls.are_browser_prefs_set(config):
            for pref, value in config["browserPreferences"].items():
                options.set_preference(pref, value)

        if config["arjuna_options"]["BROWSER_HEADLESS"]:
            options.add_argument("-headless")

        if cls.are_browser_args_set(config):
            for arg in config["browserArgs"]:
                options.add_argument(arg)

        from selenium import webdriver
        return webdriver.Remote(svc_url,
                                browser_profile=profile,
                                options=options)
Esempio n. 16
0
    def _create_chrome(cls,
                       config,
                       driver_path,
                       browser_bin_path,
                       svc_url,
                       proxy=None):
        from selenium.webdriver import Chrome, ChromeOptions

        caps = DesiredCapabilities.CHROME
        caps.update(config["driverCapabilities"])

        # if config["arjuna_options"]["BROWSER_PROXY_ON"]:
        #     proxy = Proxy()
        #     proxy_string = "{}.{}".format(
        #         config["arjuna_options"]["BROWSER_PROXY_HOST"],
        #         config["arjuna_options"]["BROWSER_PROXY_PORT"]
        #     )
        #     proxy.http_proxy = proxy_string
        #     proxy.ssl_proxy = proxy_string
        #     proxy.add_to_capabilities(caps)

        from arjuna import log_debug
        log_debug("Is proxy set for Chrome?: {}".format(proxy is not None))
        if proxy is not None:
            proxy.add_to_capabilities(caps)
            caps['acceptInsecureCerts'] = True

        options = ChromeOptions()

        if browser_bin_path.lower() != "not_set":
            options.binary_location = browser_bin_path

        if cls.are_browser_prefs_set(config):
            options.add_experimental_option("prefs",
                                            config["browserPreferences"])

        if config["arjuna_options"]["BROWSER_HEADLESS"]:
            options.add_argument("--headless")

        if cls.are_browser_args_set(config):
            for arg in config["browserArgs"]:
                options.add_argument(arg)

        if cls.are_extensions_set(config):
            for ext in config["browserExtensions"]:
                options.add_extension(ext)

        caps[ChromeOptions.KEY] = options.to_capabilities()[ChromeOptions.KEY]
        from selenium import webdriver
        return webdriver.Remote(svc_url, caps)
Esempio n. 17
0
 def find_elements(cls, container, byType, byValue, *, relations=None, filters=None):
     from arjuna import log_debug
     log_debug(f"Finding elements in container:{container} with wtype:{byType} and wvalue:{byValue} with relations: {relations} and filters: {filters}")
     sbyType = cls.BY_MAP[byType.upper()]
     if not relations:
         elements = container.find_elements(sbyType, byValue)
     else:
         # Currently Selenium supports Relative locator only for find_elements and at driver level
         # For nested element finding change to WebDriver instance if relations are defined.
         if isinstance(container, WebElement):
             container = container.parent
         rby = cls.__create_relative_by(sbyType, byValue, relations)
         log_debug("Selenium find_elements call made with RelativeBy: {}".format(rby.to_dict()))
         elements = container.find_elements(rby)         
     if len(elements) == 0:
         raise GuiWidgetNotFoundError("By.{}={}".format(byType, byValue), message="No element found for Selenium locator")   
     if filters is not None:
         if "pos" in filters:
             log_debug("Filtering elements with filter: {}".format(filters["pos"]))
             try:
                 extracted_elements = filters["pos"].extract(elements)
                 if type(extracted_elements) is not list:
                     return [extracted_elements]
                 else:
                     return extracted_elements
             except Exception as e:
                 log_debug("Exception in filters processing: {}".format(e))
                 raise GuiWidgetNotFoundError("By.{}={}".format(byType, byValue), message="No element found for Selenium locator after applying position filters.")   
     return elements
Esempio n. 18
0
 def __process_widgetdef_in_relations(self, wmd):
     from arjuna import log_debug
     from arjuna.core.error import ArjunaTimeoutError
     from arjuna.tpi.error import GuiWidgetNotPresentError
     log_debug(
         "Processing GuiWidgetDefinition relationships for GuiWidgetMetaData: {} in gui: {}"
         .format(wmd, self.__gui))
     for k, v in wmd.meta.relations.items():
         from arjuna import GuiWidgetDefinition
         if isinstance(v, GuiWidgetDefinition):
             log_debug(
                 "Triggering locating operation for GuiWidgetDefinition {} in relations dict."
                 .format(v))
             rwmd = v._as_wmd()
             rwmd = self.__process_widgetdef_in_relations(rwmd)
             log_debug("Finding element with wmd: {}.".format(rwmd))
             try:
                 wmd.meta.relations[k] = getattr(
                     self.__wmd_finder, rwmd.meta["type"].name.lower())(
                         rwmd).dispatcher.driver_element
             except ArjunaTimeoutError:
                 raise GuiWidgetNotPresentError(self.__gui, rwmd)
             #  = self.locate(v).dispatcher.driver_element
             log_debug(
                 "Replaced relation {} with corresponding GuiElement in relations dict."
                 .format(k))
     return wmd
Esempio n. 19
0
 def __init__(self, mdict=None):
     from arjuna import log_debug
     log_debug("Input Meta Dict for Meta creation: {}".format(
         repr_dict(mdict)))
     temp_dict = not mdict and CIStringDict() or CIStringDict(mdict)
     self.__mdict = CIStringDict()
     self.__process_type(temp_dict)
     self.__process_relations(temp_dict)
     self.__process_filters(temp_dict)
     self.__process_settings(temp_dict)
     self.__mdict.update({
         k: v
         for k, v in temp_dict.items()
         if k.lower() not in {"type", "relations", "settings", "filters"}
     })
     log_debug("Meta dictionary is: {}".format(repr_dict(self.__mdict)))
Esempio n. 20
0
 def translate(cls, locator):
     from arjuna import log_debug
     rltype = locator.ltype
     rlvalue = locator.lvalue
     glvalue = None
     try:
         gltype = GenericLocateWith[rltype.upper()]
     except Exception as e:
         raise Exception(
             "Invalid locator across all automators: {}={}. Error: {}".
             format(rltype, type(rlvalue), str(e)))
     else:
         log_debug("Processing locator: Type: {}; Value: {}".format(
             str(gltype), rlvalue))
         if gltype == GenericLocateWith.ELEMENT:
             glvalue = rlvalue
         elif gltype in cls.BASIC_LOCATORS:
             glvalue = rlvalue
         elif gltype in cls.NEED_TRANSLATION:
             glvalue = rlvalue
             gltype = cls.NEED_TRANSLATION[gltype]
         elif gltype in cls.XPATH_LOCATORS:
             glvalue = cls.XPATH_LOCATORS[gltype].format(rlvalue)
             gltype = GenericLocateWith.XPATH
         elif gltype == GenericLocateWith.POINT:
             glvalue = cls.NAMED_ARG_LOCATORS[gltype].format(**rlvalue)
         elif gltype in cls.NAMED_ARG_LOCATORS:
             glvalue = cls.NAMED_ARG_LOCATORS[gltype].format(**rlvalue)
             gltype = GenericLocateWith.CSS_SELECTOR
         elif gltype == GenericLocateWith.CLASSES:
             css_string = cls.__process_selector(rlvalue)
             glvalue = cls.__process_selector(rlvalue)
             gltype = GenericLocateWith.CSS_SELECTOR
         elif gltype == GenericLocateWith.TAGS:
             glvalue = " ".join(cls.__process_tags(rlvalue))
             gltype = GenericLocateWith.CSS_SELECTOR
         elif gltype in {
                 GenericLocateWith.NODE, GenericLocateWith.BNODE,
                 GenericLocateWith.FNODE
         }:
             gltype, glvalue = cls.__translate_node(gltype, rlvalue)
         elif gltype == GenericLocateWith.AXES:
             gltype, glvalue = cls.__translate_axes(gltype, rlvalue)
         else:
             raise Exception("Locator not supported yet by Arjuna: " +
                             rltype)
     return GuiGenericLocator(gltype, glvalue)
Esempio n. 21
0
 def __process_type(self, temp_dict):
     from arjuna import log_debug
     from arjuna.core.constant import GuiWidgetType
     if "type" in temp_dict:
         log_debug("Copying provided type from meta dict: {}".format(
             temp_dict["type"]))
         try:
             widget_type = temp_dict["type"]
             if not isinstance(widget_type, GuiWidgetType):
                 self.__mdict["type"] = GuiWidgetType[widget_type.upper()]
             else:
                 self.__mdict["type"] = temp_dict["type"]
         except Exception as e:
             raise Exception(
                 "{} is not a valid Gui widget type.".format(widget_type))
     else:
         self.__mdict["type"] = GuiWidgetType.ELEMENT
Esempio n. 22
0
    def _load_root_element(self):
        '''
            Loads root element for GuiSection.

            Root element is always loaded by using GuiPage. Rest of the elements are loaded as nested elements in root.
        '''
        if self.__root_meta:
            label, locator = self.__root_meta
            if self.__root_meta[0] != "anonymous":
                wmd = self._gui_def.get_wmd(label)
                from arjuna import log_debug
                log_debug("Loading Root Element {} for GuiSection: {}".format(
                    label, self.label))
                self.__root_element = self._wmd_finder.element(wmd)
            else:
                from arjuna import log_debug
                log_debug(
                    "Loading Root Element with Locator {} for GuiSection: {}".
                    format(str(locator), self.label))
                self.__root_element = self._finder.locate(locator)

            self.__container = self.__root_element
Esempio n. 23
0
    def __determine_root(self, root_init):
        from arjuna import GuiWidgetDefinition
        root_label = None
        root_gns = self._gui_def.root_element_name
        if root_init:
            # root in __init__ as a Locator instead of GNS Label
            if isinstance(root_init, GuiWidgetDefinition):
                root_label = "anonymous"
            else:
                root_label = root_init
        else:
            root_label = root_gns
        from arjuna import log_debug
        log_debug(
            "Setting Root Element for {} Gui. Label: {}. Root in GNS: {}. Root in __init__: {}."
            .format(self.label, root_label, root_gns, root_init))

        if root_label:
            root_label = root_label.lower().strip()
            return root_label, root_init
        else:
            return None
Esempio n. 24
0
    def find(self, dispatcher_call, wmd, context="ELEMENT"):
        from arjuna import log_debug
        log_debug("Finding with wmd: {}".format(str(wmd)))
        from arjuna import Arjuna
        found = False
        js_call_name = context == "ELEMENT" and "_find_element_with_js" or "_find_multielement_with_js"
        js_call = getattr(self.container, js_call_name)
        locators = wmd.locators
        if context != "ELEMENT":
            if "POINT" in {l.ltype.name for l in locators}:
                raise ConditionException(
                    "With.POINT can be used only with GuiElement.")

        we = None
        for locator in locators:
            try:
                if locator.ltype.name == "POINT":
                    # Assumption here is that this container is automator.
                    size, dispatcher = js_call(locator.lvalue)
                elif locator.ltype.name == "JS":
                    size, dispatcher = js_call(locator.lvalue)
                else:
                    lvalue = locator.lvalue
                    if locator.ltype.name == "XPATH":
                        if not lvalue.startswith("."):
                            lvalue = "." + lvalue
                    size, dispatcher = dispatcher_call(locator.ltype.name,
                                                       lvalue)
                return locator.ltype.name, locator.lvalue, size, dispatcher
            except WaitableError as e:
                we = e
            except Exception as f:
                raise f
            else:
                we = None
        if not found:
            raise GuiWidgetNotFoundError(*wmd.locators,
                                         container=self.__container)
Esempio n. 25
0
 def __getattr__(self, name):
     wmd = self.__gui_def.get_wmd(name)
     from arjuna import log_debug
     log_debug(
         "Finding element with label: {}, wmd: {} and fargs: {}".format(
             name, wmd, self.__fargs))
     fmt_wmd = wmd.create_formatted_wmd(**self.__fargs)
     for k, v in fmt_wmd.meta.relations.items():
         from arjuna.interact.gui.auto.finder.wmd import GuiWidgetMetaData
         if type(v) is str:
             log_debug(
                 "Formatting related label {} in relations dict.".format(k))
             rwmd = self.__gui_def.get_wmd(v)
             log_debug(
                 "Retrieved  GuiWidgetMetaData {} for label {} in relations dict."
                 .format(rwmd, k))
             log_debug("Formatting with args: {}".format(self.__fargs))
             frwmd = rwmd.create_formatted_wmd(**self.__fargs)
             fmt_wmd.meta.relations[k] = self.__gns._locate_with_wmd(
                 frwmd).dispatcher.driver_element
             log_debug(
                 "Replaced label {} with corresponding GuiElement in relations dict."
                 .format(k, frwmd))
     return self.__gns._locate_with_wmd(fmt_wmd)
Esempio n. 26
0
 def __process_labels_in_relations(self, wmd):
     from arjuna import log_debug
     log_debug("Processing relationship for GuiWidgetMetaData: {} in gui: {}".format(wmd, self.__gui))
     for k,v in wmd.meta.relations.items():
         from arjuna.interact.gui.auto.finder.wmd import GuiWidgetMetaData
         if type(v) is str:
             log_debug("Triggering locating operation for label {} in relations dict.".format(k))
             wmd.meta.relations[k] = getattr(self, v).dispatcher.driver_element
             log_debug("Replaced label {} with corresponding GuiElement in relations dict.".format(k))               
     return wmd
Esempio n. 27
0
 def find_element(cls, container, byType, byValue, *, relations=None, filters=None):
     from arjuna import log_debug
     log_debug(f"Finding element in container:{container} with wtype:{byType} and wvalue:{byValue} with relations: {relations} and filters: {filters}")
     elements = cls.find_elements(container, byType, byValue, relations=relations, filters=filters)
     return elements[0]
Esempio n. 28
0
 def execute_javascript(cls, driver, script, *args):
     from arjuna import log_debug
     log_debug("Executing JavaScript {} with args {}.".format(script, args))
     return driver.execute_script(script, *args)
Esempio n. 29
0
    def select_tests(cls, pytest_items, pytest_config):
        '''
            Select tests from items collected by pytest, based on Arjuna rules.

            Arguments:
                pytest_items: List of pytest `Item` objects. Each item represents a collected test function node.
                pytest_config: pytest Config object
        '''
        from arjuna import log_debug

        def process_nodename(item):
            return item.name.split("[")[0]

        from arjuna import Arjuna
        from arjuna.core.error import ExclusionRuleMet, NoInclusionRuleMet
        from arjuna import C
        selector = Arjuna.get_test_selector()
        final_selection = []
        deselected = []
        qual_names = set()

        for item in pytest_items:
            nid = item.nodeid
            log_debug(f"Processing {nid} as collected by pytest")
            # if item.name.split("[")[0] == "test":
            #     continue

            qual_name = None

            # For a test function
            # Root dir should be folder containing the module
            # E.g. check_config_03_create_conf.py::check_create_config[G]
            temp_full_path = os.path.join(pytest_config.rootdir,
                                          item.nodeid.split('::')[0])
            full_dotted_notation = temp_full_path.replace("/", ".").replace(
                '\\', ".").replace(".py", "")
            full_dotted_notation = full_dotted_notation.replace("..", ".")

            project_name = C("project.name")
            project_index = full_dotted_notation.find(project_name + "." +
                                                      "test")

            if project_index == -1:
                deselected.append(item)
                continue

            qual_name = full_dotted_notation[
                project_index:] + "." + process_nodename(item)

            # if os.path.exists(temp_full_path):
            #     if os.path.isfile(temp_full_path):
            #         test_path_index = temp_full_path.find(os.path.join(C("project.root.dir"), "test"))
            #         if test_path_index == -1:
            #             continue
            #         else:
            #             dotted_root = str(pytest_config.rootdir).replace("/",".").replace('\\',"")
            #             proj_suffix = dotted_root[dotted_root.find(project_name):]
            #             qual_name = proj_suffix + "." + process_nodeid(item) + "." + process_nodename(item)
            # else:
            #     qual_name = process_nodeid(item) + "." + process_nodename(item)
            #     start_index = qual_name.find(project_name + "." + "test")
            #     if start_index == -1:
            #         if qual_name.startswith("test."):
            #             qual_name = project_name + "." + qual_name
            #         else:
            #             deselected.append(item)
            #             continue
            #     else:
            #         qual_name = qual_name[start_index:]

            try:
                selector.validate(Arjuna.get_test_meta_data(qual_name))
            except (ExclusionRuleMet, NoInclusionRuleMet) as e:
                deselected.append(item)
            else:
                final_selection.append(item)

        if deselected:
            pytest_config.hook.pytest_deselected(items=deselected)
            pytest_items[:] = final_selection
Esempio n. 30
0
    def enhance_reports(cls, item, result):
        '''
            Automatically add screenshot to HTML Report File.

            To be used in **pytest_runtest_makereport** hook in **conftest.py**.

            Args:
                item: **pytest**'s Item object
                result: **pytest**'s TestReport object.

            Note:
                - For taking the screenshot, it does a look up for a **screen_shooter** attribute in the object spaces in following order:
                    - Function Space
                    - Module Space
                    - Session Space

                - The screen_shooter attribute should contain a **ScreenShooter** i.e. an object of a class that inherits from ScreenShooter class and completes its protocol.
                
                - This is a lenient hook. This means that if any exception happens in it, it ignores the exception and logs a warning message.
        '''

        try:
            from arjuna import Arjuna, ArjunaOption, log_debug
            ignore_passed_for_screenshots = not Arjuna.get_config().value(
                ArjunaOption.REPORT_SCREENSHOTS_ALWAYS)
            ignore_passed_for_network = not Arjuna.get_config().value(
                ArjunaOption.REPORT_NETWORK_ALWAYS)

            include_images = True
            include_network = True

            html_plugin = cls._get_html_report_plugin(item)
            pytest_html = html_plugin
            report = result.get_result()

            log_debug("Node ID: {}".format(report.nodeid), contexts="report")
            log_debug("Stage: {}".format(report.when), contexts="report")

            extra = getattr(report, 'extra', [])

            # if ignore_fixtures:
            #     if report.when == 'call':
            #         return

            xfail = hasattr(report, 'wasxfail')

            if ignore_passed_for_screenshots and report.passed:
                include_images = False
            else:
                # if (report.skipped and xfail) and (report.failed and not xfail):
                # extra.append(pytest_html.extras.url(app.url))
                try:
                    screen_shooter = cls._get_protocol_object(
                        item, "screen_shooter")
                except AttributeError:
                    pass
                else:
                    try:
                        screen_shooter.take_screenshot(prefix=report.nodeid)
                    except Exception:
                        # any error in auto-screen shot is ignored.
                        pass

            log_debug("Attempting to get network_recorder from request",
                      contexts="report")
            try:
                network_recorder = cls._get_protocol_object(
                    item, "network_recorder")
            except AttributeError as e:
                log_debug("No network_recorder", contexts="report")
            else:
                try:
                    log_debug("Registering traffic", contexts="report")
                    network_recorder.register()
                    log_debug("Traffic registered.", contexts="report")
                except Exception as e:
                    log_debug("Exception in registering network traffic: " +
                              str(e),
                              contexts="report")

            if ignore_passed_for_network and report.passed:
                include_network = False

            log_debug("Include images {}".format(include_images),
                      contexts="report")
            log_debug("Include network {}".format(include_network),
                      contexts="report")

            # When this place is reached by a resource that failed/erred or a test (irrespective of result)
            if (report.when in {"setup", "teardown"}
                    and not report.passed) or report.when == "call":
                test_container = Arjuna.get_report_metadata()
                if test_container.has_content():
                    log_debug("Extra Content Found for HTML Report",
                              contexts="report")
                    extra_html = test_container.as_report_html(
                        include_images=include_images,
                        include_network=include_network)
                    if extra_html:
                        extra.append(pytest_html.extras.html(extra_html))
                        report.extra = extra

            # For fixtures with errors, failures, clean the resources.
            if report.when in {"setup", "teardown"}:
                if not report.passed:
                    log_debug("Clearing report extras.", contexts="report")
                    Arjuna.get_report_metadata().clear()
            else:
                log_debug("Clearing report extras.", contexts="report")
                Arjuna.get_report_metadata().clear()

        except Exception as e:
            from arjuna import log_warning
            log_warning("Error in enhance_reports hook: " + str(e),
                        contexts="report")
            raise