
To Do
-----
    - Support for commons. Elements like spinners which have common defs.

GNS - Random raw ideas. Need careful thinking before implementation.

    - xgns format.
    - Concept of Template - can be thought of in many ways, but one needs to be chose. Let's say Table is a template.
        - Xgns can have a <table> element. Table as a template can define its mandatory and optional params.
        - xgns can be at a a page or widget level. Table loads its critical params by name association programmatically from the same definition.
        - Table has its own definition. It can be in a page or a widget.
        - Template elements can be included in commons and referred anywhere in a GNS:
            e.g. [books_table=table]
            in this case the section content will be treated as a dict of params to be passed to the table. e.g. header_id = abc will replace lets say [header]'s id = $header_id$ value.
            if any params directly match the requirements of template i.e. lets header_id itself is the need then it will be directly used in the context. i.e. [header_id] takes the content of the caller.

            Templates can be of various types:
                if not provided it is treated as an element. If used with a non-element call, special params are ignored or exception is thrown.
                dropdown
                radio_group
                multielement
        another idea is the .element .name call itself is a factory 
            which assumes element by default but can take 'template' 
            e.g. .element(As.DropDown, ). 
            Now the arguments are passed as per the template. 
            For GNS. the template is mentioned in the GNS file.
    - concept of commons.gns.
        - Can the App have a GNS which acts as the commons? 
        - These definitions are common to all pages but not repeated. 
        - Lookup done at a page level and then in commons.
        - any commonly used elements can be put here.
        E.g. [__root__ = abc] if in current format.

Learning, Could help in Arjuna Features
    - //button[contains(*//text(),'Yes')], a button whose child contains text - Yes

To Do
    - assertion methods for elements
        - Multielement - assert_not_empty, assert_size
        - While filtering, if the element count becomes zero an exception should be raised.
        - Filter should maintain the sequence of conditions to provide a chain of filters which led to the zero count.
    - Expansion of concept of GNS 
        - Can it contain more than identifiers.
        - E.g. state --> presence is default. clickable
        - Other checks like tag_check_off, click_check_off etc.

Project creation:
- Project name itself need not follow python convention.
- Arjuna project is a Python name and it is created *inside* the IDE project.
- The structure helps in importable names in IDEs for the core lib.
- Directories and files to be created -
    - project dir, __init__.py
     - config / project.conf (Add sections for arjunaOptions and userOptions)
     - data/sources / references
     - guiauto / drivers (/windows/mac/linux) /images /namespace
     - lib /__init__.py
     - fixtures.py in lib
     - enums.py in lib (enum for user options pre-created?)
     - scripts /arjuna_launcher.py
     - tests /modules __init__.py, conftest.py


- Other pytest switches of interest to be wrapped in alignment with Arjuna.
- Integrate Discovery module from earlier code to validate m/c/f/m

Next
----
- Clean-up With
- The config which is a part of context should be a simple RO proxy on top of the internal config. Reduce redundancy.
- See if you can introduce value_as_* methods in containers. This means one can do value.as_str() or container.value_as_str(name)
- See how difficult it is to integrate Allure reporting. Accordingly see screenshots possibility.
- For multi-element introduce an arguent min_length. It should be a part of waiting till number of elements are more than the min specified.
- For multi-element, see filter methods. .filter(attr_value(name=, value=))
- Create an attr() call. One should be able to supply any number of attrs to With.attr* methods
- One thing which can be done for With cleanup is that With can tranform itself based on who it is etc.
- Another thing which can be done is introduction, 
    With.conditions or Just Call it "Which"? which can take various args of type
        - value
        - title
        - attr
    Conditions can be 
    Different With share an OR relationship like earlier.
    Within a With.locators, they share an and relationship.
    With.conditions() -- Can take only condition arguments e.g. attr, text, value, etc. not xpath or this style. A subset of conditions supported.
        - Most likely will lead to an XPath generation.
    See how this and MultiElement Filters work together.

Action Chains (In progress)
---------------------------
- As of now introducing the following actions without explicit action chain creation:
    GuiElement methods
        - hover
        - hover_and_click

Fine Tuning
-----------
Done
- User defined options can be provided as any enum constant. 
- User defined options can be provided as any enum constant.
- Concept of lenient interaction introduced
    - It is observed that although selenium returns is clickable true, element may yet not be clickable.
    - Arjuna post checking clickability, also executes lenient clicking.
    - Lenient set text introduced.
Pending
- In example code introduce user defined option as enum
- Introduce 'hold' method in Gui interaction components. It should wait for enter key. input("Press enter to continue")

Next Features on Priority
-------------------------
- ActionChains
- WebDriverManager
- Support for loading conf from a file. E.g. env based multiple conf files.

GNS Desirables
---------------
- Extract with mechanism for pages and separate from the generic logic. It is getting too complicated.
- An identifier should explicitly look for parameter value:
    - $kw.abc$ -> This should directly come from With.format() provided keywords.
    - $dd.abc$ -> This should come from data that is provided to the test.
    - $l10n.abc$ -> This should come from localizer.
    - $conf.abc$ -> This should come from config attached to the automator for which this namespace is loaded.
    - $abc$ -> This will be the least performing but should work. 
        This should auto look up in the above sequence.

    - Introduce a configuration option where the lookup order can be configured.
    - There should be a provision where a certain lookup can be completely switched off.
        E.g. if there is no localizer then that should not be there in the lookup object.
    - One thought is that you can create a Intrapolator class for this.
        Each GuiDef can have an intrapolator object attached to it.

Check support for OR AND parameterized identifiers

Localizer
---------
Add localizer

Deferred and Reason
-------------------
Concept of Intent and Expression.
Intent is what a test wants to do -> typically it should talk business.
Expression is technical implementation -> e.g. ExpressViaWebUI. ExpressViaMobileUI. ExpressViaWebSvc. ExpressViaDB.

Notes for any needed fixes and changes
-------------------------------------
Names of CLI options to be changed to baseline and extended
CLI ->
aro
uro
aeo
ueo

1. Arjuna identifiers:
- Add support for new identifiers.

6. Test when different values in sample code are provided as Values rather than as_* conversion.
    The errors should tell -> expecting str/int etc instead of Value.
    OR those methods at the correct layer should convert it to the expected value type and use.

7. JS execution works and because of local exec can return objects as well. 
    - should evaluate whether return this object as Value makes sense?

8. Window handling logic needs to be checked for stability with content locator. 
    Wait time should be overall wait time. Needs to be checked.
    Also check open windows at any point in time.
    May be we should check for window readiness and page load when a new window is launched using JavaScript.

11. Text case insensitive? by default off. For on more processing is needed so expectation should be set accordingly.

Planned Features
Element Configuration (code and gns)
    - Support at automator level.
    - Support at configuration level
Advanced Frame related functionality - In Progress
    - Enumerating immediate frames at Dom Root and Frame level
    - Content based frame finding for immediate child frames
Action Chains - Named method for common interactions - In progress
    - Invoker-side interfaces and classes - Mostly done
    - Impl and dispatcher pending
    - Look for Pythonic opportunities in Invoker api
Nested Elements support
More waits
    wait for Absence, Invisible and Disabled

 - Create a a method in Gui and GuiAutomator, it should also be able to take a callable and its args. Possibly for recording option to be run in a second thread. launch a tool, whatever.

Map valid With options to tpye of component. Clear exceptions with troubleshooting to be coded.
Explicit wait in Arjuna Setu for Frames and Windows, which works under the total limit of gui max wait.
Classification of Errors and Exceptions
Single Context GNS
    Should be the default context
Element configuration support in GNS
AND relationship for code and gns
Option to enable proxy in Selenium dispatcher
Taking screenshot - automator level, rect, element, elements
Frame config: should be able to change the iframe to e.g. object. Enumerate frames should take an optional argument of With and do a multielement match instead of the default With.INDEX used internally.
File based configuration load_from_code_file
    coded
    pytest or unitee session file should support this
    CLI
Add support for envioronment variables to be consumed in configuration
Overridabiliy and visibility of configuration options ---> This needs to be implemented before CLI can be discussed: Following are the levels for which it should be clearly defined. Preferrably all configuration settings should be documented as matrix with the mapping:
    Project.conf
    Programmatic
    CLI - Reference
    CLI - Extended
Data Reference


Phase 3 - Additional Abstractions and Features for Selenium - 24 Dec, 2019 (Jan 1 2020 - 1.0 First production Release)
Navigation bar menu Abstraction
WebTable Abstraction
MultiElement filters
    ignore
    consider
WebDriver Manager
JavaScript
    Sending primititve args to Javascript
    Sending element to JavaScript
Support for Multi-select Dropdown list
Default type checking for enter/set text, check/unckeck, toggle operations etc.
Optimization of option level or radio button level state and attribute checking in DropDown and RadioButton abstractions

Phase 4 - March 31, 2019 (In Parallel to Next Feature GuiSection)
Documentation
    Configuration Options
    Bindings documentation
Documentation
    FaaST protocol
    Create a sharable Postman collection for FaaST

Extended Arjuna Features, Python Bindings and Corresponding Support in Arjuna
Phase 1 - March 31, 2019
    Completion of Python Bindings in alignment with Java Bindings
    Create a list and high level doc of what is expected from Bindings currently
    List the features here and track feature wise completion after critical testing
    Logger as Service
Visualization of requests & responses
UniTEE reporter
    Treeview
    Summary
    See whether html5.Treeview helps?

Phase 2 - Tentatively a 6 month schedule
    Arjuna Web Interface
    Need help from community contributor who knows web development
    Arjuna as a Remote Service
    Jenkins and GitHub integration
    Arjuna docker Image


What SetuSvc used to do:

    def __register_test_session(self, root_dir, cliConfig=None):
        handler = TestSessionHandler()

        config = handler.init(root_dir, cliConfig)
        SetuSvcObjectManager.register_testsession_handler(handler)
        out = {
            'testSessionSetuId': handler.setu_id,
            'configSetuId': config.setu_id,

        }

        out.update(config.as_json_dict())
        return out

    def _handle_configurator_action(self, ts_handler, action_type, json_args):
        return ts_handler.conf_handler.take_action(action_type.name, json_args)

    def _handle_data_source_action(self, ts_handler, action_type, json_args):
        return ts_handler.datasource_handler.take_action(action_type, json_args)

    def _handle_gui_automator_action(self, ts_handler, action_type, json_args):
        if action_type == GuiAutoActionType.LAUNCH:
            config = ts_handler.conf_handler.configurator.get_config(Handler.get_config_setuid(json_args))
            automator_handler = GuiAutomatorHandler(ts_handler.dispatcher)
            automator_handler.launch_automator(config, **json_args)
            ts_handler.register_gui_automator_handler(automator_handler)
            return {'automatorSetuId' : automator_handler.setu_id}
        elif action_type == GuiAutoActionType.QUIT:
            handler = ts_handler.get_automator_handler(json_args)
            handler.quit_automator()
            ts_handler.deregister_gui_automator_handler(handler) 
        else:
            gui_setu_id = json_args.get("guiSetuId", None)
            handler = None
            if gui_setu_id is not None:
                handler = ts_handler.get_gui_handler(json_args)
            else:
                gui_automator_setu_id = json_args.get("automatorSetuId", None)
                if gui_automator_setu_id is None:
                    raise Exception("For gui component action either guiSetuId or automatorSetuId must be provided.")
                handler = ts_handler.get_automator_handler(json_args)
            return handler.take_action(action_type, json_args)

    def _handle_gui_action(self, ts_handler, action_type, json_args):
        automator_handler = ts_handler.get_automator_handler(json_args)
        return ts_handler.gui_manager.take_action(automator_handler, action_type, json_args)


You need to see the following in relation to With object which is now directly used
in client API instead of a web service call:

    def define_element(self, locators):
        elem = self.automator.create_element(GuiElementMetaData.createEMD(locators))
        return {"guiComponentSetuId" : elem.setu_id}

    def define_element_with_emd(self, emd):
        elem = self.automator.create_element(emd)
        return {"guiComponentSetuId" : elem.setu_id}

Also look at the following take element action api:

    def take_element_action(self, action, json_dict):
        elem_setu_id = self.get_element_setuid(json_dict)
        self.automator.slomo()
        instance_action = False
        if "isInstanceAction" in json_dict:
            instance_action = json_dict["isInstanceAction"]
            del json_dict["isInstanceAction"]
        if instance_action:
            index = json_dict["instanceIndex"]
            del json_dict["instanceIndex"]
            multi_element =  self.automator.get_multielement_for_setu_id(elem_setu_id)
            element = multi_element.get_instance_at_index(index)
        else:
            element =  self.automator.get_element_for_setu_id(elem_setu_id)
        return getattr(ElementHandler, action)(element, **json_dict)

Evaluate the following drop down methods:
class DropdownHandler:
    @classmethod
    def configure(cls, dropdown, elementConfig):
        dropdown.configure(elementConfig)

    @classmethod
    def set_option_locators(cls, dropdown, locators):
        dropdown.set_option_locators(GuiElementMetaData.createEMD(locators))

    @classmethod
    def set_option_container(cls, dropdown, locators):
        dropdown.set_option_container(GuiElementMetaData.createEMD(locators))

Following window method:
    @classmethod
    def define_child_window(self, window, locators):
        print(locators)
        return {"guiComponentSetuId" : window.define_child_window(GuiElementMetaData.createEMD(locators)).setu_id}


Following Frame method:
    @classmethod
    def define_frame(cls, dom_root, locators):
        return {"guiComponentSetuId" : dom_root.create_frame(GuiElementMetaData.createEMD(locators)).setu_id}


Unitee Separatation
-------------------
New unitee will be built on top of python's unittest.
Separated from Arjuna on 24th Jan 2020.

Following CLI options removed from arjuna/interface/cli/parser.py
        self.parser.add_argument('-ar', '--active-reporters', dest="unitee.project.active.reporters",
                                 metavar=('R1','R2'), nargs='+',
                                 type=ustr,
                                 choices=[i for i in ActiveReporterNames.__members__],
                                 help='One or more valid active state names: ' + str([i for i in ActiveReporterNames.__members__]))
        self.parser.add_argument('-dr', '--deferred-reporters', dest="unitee.project.deferred.reporters",
                                 metavar=('R1','R2'), nargs='+',
                                 type=ustr,
                                 choices=[i for i in DeferredReporterNames.__members__],
                                 help='One or more valid deferred state names: ' + str([i for i in DeferredReporterNames.__members__]))


Parsers removed: arjuna/interface/cli/parser.py

class SessionParser(Parser):
    def __init__(self):
        super().__init__()
        self.parser = argparse.ArgumentParser(add_help=False)
        self.parser.add_argument('-s', '--session-name', dest="unitee.project.session.name", type=partial(lname_check, "Session"), help='Existing session template name.')

    def process(self, arg_dict):
        if arg_dict['unitee.project.session.name'] is None:
            print("Fatal Error in CLI processing. You must provide a valid session name using -s or --session-name switch", file=sys.stderr)
            sys.exit(1)


class GroupParser(Parser):
    def __init__(self):
        super().__init__()
        self.parser = argparse.ArgumentParser(add_help=False)
        self.parser.add_argument('-g', '--group-name', dest="group.name", type=partial(lname_check, "Group"), help='Existing group template name.')

    def process(self, arg_dict):
        pass

class NamesParser(Parser):
    def __init__(self):
        super().__init__()
        self.parser = argparse.ArgumentParser(add_help=False)
        self.parser.add_argument('-cm', '--cmodules', dest="cmodules", metavar=('M1','M2'), default=None, nargs='+', help='One or more names/patterns for considering test modules.')
        self.parser.add_argument('-im', '--imodules', dest="imodules", metavar=('M1','M2'), default=None, nargs='+',
                         help='One or more names/patterns for ignoring test modules.')
        self.parser.add_argument('-cf', '--cfunctions', dest="cfunctions", metavar=('F1','F2'), default=None, nargs='+', help='One or more names/patterns for considering test functions.')
        self.parser.add_argument('-if', '--ifunctions', dest="ifunctions", metavar=('F1','F2'), default=None, nargs='+',
                         help='One or more names/patterns for ignoring test functions.')

    def process(self, arg_dict):
        pass

Following content removed from arjuna/interface/cli/command.py:

class RunProject(__RunCommand):
    def __init__(self, subparsers, parents):
        super().__init__(subparsers, 'run-project', parents, "Run a project")

    def execute(self, arg_dict):
        super().execute(arg_dict)
        self.unitee.load_session_for_all()
        self.unitee.run()
        self.unitee.tear_down()


class RunSession(__RunCommand):
    def __init__(self, subparsers, parents):
        super().__init__(subparsers, 'run-session', parents, "Run a session")

    def execute(self, arg_dict):
        super().execute(arg_dict)
        self.unitee.load_session(arg_dict['unitee.project.session.name'])
        self.unitee.run()
        self.unitee.tear_down()


class RunGroup(__RunCommand):
    def __init__(self, subparsers, parents):
        super().__init__(subparsers, 'run-group', parents, "Run a group")

    def execute(self, arg_dict):
        group_name = arg_dict.pop('group.name')
        super().execute(arg_dict)
        self.unitee.load_session_for_group(group_name)
        self.unitee.run()
        self.unitee.tear_down()


class RunTests(__RunCommand):
    def __init__(self, subparsers, parents):
        super().__init__(subparsers, 'run-names', parents, "Run names (modules/functions)")

    def execute(self, arg_dict):
        picker_args = {
            'cm': arg_dict.pop('cmodules'),
            'im': arg_dict.pop('imodules'),
            'cf': arg_dict.pop('cfunctions'),
            'if': arg_dict.pop('ifunctions')
        }
        super().execute(arg_dict)
        self.unitee.load_session_for_name_pickers(**picker_args)
        self.unitee.run()
        self.unitee.tear_down()

Statements removed from __RunCommand.execute() method in arjuna/interface/cli/command.py
        self.unitee = Arjuna.get_unitee_instance()
        self.unitee.load_testdb()

Options removed from arjuna/res/arjuna.conf
unitee {
    project{
        dirs.files = [
                    archives,
                    config,
                    "config/sessions",
                    core,
                    "core/db",
                    "core/db/central",
                    "core/db/run",
                    fixtures,
                    "report",
                    tests,
                    "tests/modules",
                  ]


        sessions.dir = ${project.root.dir}"/config/sessions"
        groups.dir = ${project.root.dir}"/config/groups"

        tests.dir = ${project.root.dir}"/tests"
        test.module.import.prefix = "<TEST_MODULE_IMPORT_PREFIX>"
        fixtures.import.prefix = "<FIXTURES_IMPORT_PREFIX>"

        core {
            dir = ${project.root.dir}"/core"
            db.central.dir = ${project.root.dir}"/core/db/central"
            db.central.dbfile = ${project.root.dir}"/core/db/central.ads"
            db.allrun.dir = ${project.root.dir}"/core/db/run/"
            db.widget.dir = ${project.root.dir}"/core/db/template"
            db.widget.central.dbfile = ${project.root.dir}"/core/db/template/ctemp.ads"
            db.widget.run.dbfile = ${project.root.dir}"/core/db/template/rtemp.ads"
        }

        reporter.mode = str
        active.reporters = [MIN_CONSOLE]
        deferred.reporters = [EXCEL]

        failfast = false

        report {

                name {
                    format = ArjunaTestReport
                }

                headers {
                    tmeta = [stage, group, pkg, module, minst, mfrag, func, finst, test, thread]
                    igmeta = [pkg, module, func]
                    props = [mid, mname, midea, mpriority, fid, fname, fidea, fpriority]
                    reportable {
                        test = [result, code, desc, ttime, btstamp, etstamp, issue_id]
                        step = [num, purpose, result, ctext, cbench, cobserve, issue_id]
                        issue = [id, type, sub_type, ename, emsg, etrace, step_num, fname, dsname]
                        ignored = [status, reason]
                        fixture = [fixture_type, fixture_method, result, issue_id, exec_point]
                        event = [text, component, success, remarks, exc_msg, exc_trace]
                    }
                }
        }


        runid = "<runid>"

        irunid = "<IRUNID>"

        session {
            name = msession
        }

        core {
            db.run.dbfile = ${project.root.dir}"/core/db/run/<IRUNID>.ads"
        }

        screenshots.run.dir = ${project.root.dir}"/report/<IRUNID>/screenshots"

        run = {
            report = {
                dir = ${project.root.dir}"/report/<IRUNID>"
                jdb.dir = ${project.root.dir}"/report/<IRUNID>/jdb"
                json = {
                    dir = ${project.root.dir}"/report/<IRUNID>/json"
                    tests.dir = ${project.root.dir}"/report/<IRUNID>/json/tests"
                    ignoredtests.dir = ${project.root.dir}"/report/<IRUNID>/json/ignored_tests"
                    issues.dir = ${project.root.dir}"/report/<IRUNID>/json/issues"
                    events.dir = ${project.root.dir}"/report/<IRUNID>/json/events"
                    fixtures.dir = ${project.root.dir}"/report/<IRUNID>/json/fixtures"
                }
            }
        }
    }
}

From: arjuna/res/arjuna_conf_desc.conf

unitee {
    project{
        dirs.files = str_list

        sessions.dir = absolute_dir_path
        groups.dir = absolute_dir_path

        tests.dir = absolute_dir_path
        test.module.import.prefix = str
        fixtures.import.prefix = str

        core {
            dir = absolute_dir_path
            db.central.dir = absolute_dir_path
            db.central.dbfile = absolute_dir_path
            db.allrun.dir = absolute_dir_path
            db.widget.dir = absolute_dir_path
            db.widget.central.dbfile = absolute_dir_path
            db.widget.run.dbfile = absolute_dir_path
        }

        reporter.mode = str
        active.reporters = active_reporter_list
        deferred.reporters = deferred_reporter_list

        failfast =  bool

        report {

                name {
                    format = str
                }

                headers {
                    tmeta = str_list
                    igmeta = str_list
                    props = str_list
                    reportable {
                        test = str_list
                        step = str_list
                        issue = str_list
                        ignored = str_list
                        fixture = str_list
                        event = str_list
                    }
                }
        }


        runid = str

        irunid = str

        session {
            name = str
        }

        core {
            db.run.dbfile = absolute_dir_path
        }

        screenshots.run.dir = absolute_dir_path

        run = {
            report = {
                dir = absolute_dir_path
                jdb.dir = absolute_dir_path
                json = {
                    dir = absolute_dir_path
                    tests.dir = absolute_dir_path
                    ignoredtests.dir = absolute_dir_path
                    issues.dir = absolute_dir_path
                    events.dir = absolute_dir_path
                    fixtures.dir = absolute_dir_path
                }
            }
        }
    }
}

Removed From arjuna/arjuna/tpi/__init__.py:

Removed statements
    def __init__(self):
        # NAme of thread: Base configuration
        self.thread_map = {}
        # DefaultStringKeyValueContainer
        self.exec_var_map = {}
        # DefaultStringKeyValueContainer
        self.gns.user_options = {}

Removed statements
    def init(self, project_root_dir, cli_config, run_id):
        from arjuna.engine.unitee import Unitee
        project_name = self.__ref_config.arjuna_options.value(ArjunaOption.PROJECT_NAME).as_str()
        self.__unitee = Unitee(self.__test_session, self.__ref_config)

Removed method
    def get_unitee_instance(self):
        return self.__unitee

In: arjuna/tpi/__init__.py

Removed:

    @classmethod
    def get_unitee_instance(cls):
        '''
            Returns instance of Unitee singleton.
        '''
        return cls.ARJUNA_SINGLETON.get_unitee_instance()

Removed File: arjuna/tpi/unitee/markup.py arjuna/tpi/unitee/markup.py

Removed class from arjuna/configure/invoker/context.py:

# For Unitee
class UniteeTestContext(Context):

    def __init__(self, test_session, name, parent_config=None):
        super().__init__(test_session, name, parent_config)

    def add_config(self, config):
        self.__configs[config.get_name()] = config

    def clone(self):
        out_context = UniteeTestContext(self._get_test_session(), self.get_name())
        out_context._add_configs(self._get_configs())
        out_context._add_conf_trace(self._get_conf_trace())
        return out_context

    def clone_for_user(self):
        out_context = RunContext(self._get_test_session(), self.get_name())
        out_context._add_configs(self._get_configs())
        out_context._add_conf_trace(self._get_conf_trace())
        return out_context

    def update_from_context(self, context):
        self._add_configs(context._get_configs())

Removed res file conf_props.txt which contained onld prop reference code:
           CorePropertyTypeEnum.ARJUNA_ROOT_DIR: (
                self._handle_core_dir_path, "Arjuna Root Directory", False),
            CorePropertyTypeEnum.CONFIG_PROJECTS_DIR: (
                self._handle_core_dir_path, "Configuration Directory for Project Information", False),
            CorePropertyTypeEnum.WORKSPACE_DIR: (
                self._handle_core_dir_path, "Default Projects Directory", False),
            CorePropertyTypeEnum.PROJECT_DIRS_FILES: (
                self._handle_string_list_config, "Arjuna Project Directory Names", False),
            CorePropertyTypeEnum.PROG: (
                self._handle_string_config, "Arjuna Reference Name", False),
            CorePropertyTypeEnum.CONFIG_CENTRAL_FILE_NAME: (
            self._handle_string_config, "Central Configuration File", False),
            CorePropertyTypeEnum.CONFIG_DIR: (self._handle_core_dir_path, "Configuration Directory", False),
            CorePropertyTypeEnum.EXTERNAL_TOOLS_DIR: (self._handle_core_dir_path, "Tools Directory", False),
            CorePropertyTypeEnum.EXTERNAL_IMP_DIR: (self._handle_core_dir_path, "Tools Directory", False),
            CorePropertyTypeEnum.LOGGER_CONSOLE_LEVEL: (self._handle_log_level_config, "Minimum Logging Message Level for Console Display", True),
            CorePropertyTypeEnum.LOGGER_DIR: (self._handle_core_dir_path, "Central Log Directory", False),
            CorePropertyTypeEnum.LOGGER_FILE_LEVEL: (
            self._handle_log_level_config, "Minimum Logging Message Level for File Log", True),
            CorePropertyTypeEnum.LOGGER_NAME: (self._handle_string_config, "Log file name", False),



         def __cases(self):
        return {
            UniteePropertyEnum.PROJECT_NAME: (self._handle_string_config, "Project Name", False),
            UniteePropertyEnum.PROJECT_DIR: (self._handle_core_dir_path, "Project Root Directory", False),
            UniteePropertyEnum.PROJECT_CONFIG_DIR: (self._handle_core_dir_path, "Project Config Directory", False),
            UniteePropertyEnum.DATA_REFERENCES_DIR: (
                self._handle_project_dir_path, "Data References Directory", False),
            UniteePropertyEnum.DATA_DIR: (self._handle_project_dir_path, "Data Directory", False),
            UniteePropertyEnum.DATA_SOURCES_DIR: (
                self._handle_project_dir_path, "Data Sources Directory", False),
            UniteePropertyEnum.SCREENSHOTS_DIR: (
                self._handle_project_dir_path, "Screenshots Directory", False),
            UniteePropertyEnum.SESSION_NAME: (self._handle_string_config, "Test Session Name", False),
            UniteePropertyEnum.IRUNID: (self._handle_string_config, "Internal Run ID", False),
            UniteePropertyEnum.RUNID: (self._handle_string_config, "Test Run ID", True),
            UniteePropertyEnum.FAILFAST: (self._handle_boolean_config, "Stop on first failure/error?", False),
            UniteePropertyEnum.TEST_MODULE_IMPORT_PREFIX: (self._handle_string_config, "Prefix for Test Module Import", False),
            UniteePropertyEnum.CONF_FIXTURES_IMPORT_PREFIX: (
            self._handle_string_config, "Prefix for Configuration Level Test Fixtures Import", False),
            UniteePropertyEnum.TESTS_DIR: (self._handle_project_dir_path, "Test Directory", True),
            UniteePropertyEnum.REPORT_DIR: (self._handle_project_dir_path, "Report Directory", False),
            UniteePropertyEnum.ARCHIVES_DIR: (self._handle_project_dir_path, "Report Archives directory", False),
            UniteePropertyEnum.SESSIOgns_dir: (self._handle_project_dir_path, "Session Templates directory", False),
            UniteePropertyEnum.GROUPS_DIR: (self._handle_project_dir_path, "Group Templates directory", False),
            UniteePropertyEnum.RUN_REPORT_DIR: (self._handle_string_config, "Report Directory for the Run ID", False),
            UniteePropertyEnum.RUN_REPORT_JDB_DIR: (
                self._handle_string_config, "Report Directory for the Run ID for JDB", False),
            UniteePropertyEnum.RUN_REPORT_JSON_DIR: (
                self._handle_string_config, "Root Raw Report Directory for JSON.", False),
            UniteePropertyEnum.RUN_REPORT_JSON_TESTS_DIR: (
                self._handle_string_config, "Raw Report Directory for JSON Test Execution results.", False),
            UniteePropertyEnum.RUN_REPORT_JSON_ISSUES_DIR: (
                self._handle_string_config, "Report Directory for JSON Fixture results.", False),
            UniteePropertyEnum.RUN_REPORT_JSON_IGNOREDTESTS_DIR: (
                self._handle_string_config, "Report Directory for JSON Ignored Test results.", False),
            UniteePropertyEnum.RUN_REPORT_JSON_EVENTS_DIR: (
                self._handle_string_config, "Report Directory for JSON Event results.", False),
            UniteePropertyEnum.RUN_REPORT_JSON_FIXTURES_DIR: (
                self._handle_string_config, "Report Directory for JSON Fixture results.", False),
            UniteePropertyEnum.REPORT_NAME_FORMAT: (self._handle_string_config, "Report Name Format", False),
            UniteePropertyEnum.ACTIVE_REPORTERS: (
                self._handle_active_reporter_names, "Chosen Built-in Report Generators", True),
            UniteePropertyEnum.DEFERRED_REPORTERS: (
                self._handle_deferred_reporter_names, "Chosen Built-in Report Listeners", True),
            UniteePropertyEnum.CORE_DIR: (self._handle_string_config, "Core Root Directory.", False),
            UniteePropertyEnum.CORE_DB_CENTRAL_DIR: (self._handle_string_config, "Core Central DB Directory.", False),
            UniteePropertyEnum.CORE_DB_CENTRAL_DBFILE: (self._handle_string_config, "Core Central DB File.", False),
            UniteePropertyEnum.CORE_DB_RUN_DIR: (self._handle_string_config, "Core Run DB Directory.", False),
            UniteePropertyEnum.CORE_DB_RUN_DBFILE: (self._handle_string_config, "Core Current Run DB File.", False),
            UniteePropertyEnum.CORE_DB_TEMPLATE_DIR: (self._handle_string_config, "Core Template DB Directory.", False),
            UniteePropertyEnum.CORE_DB_TEMPLATE_CENTRAL_DBFILE: (
                self._handle_string_config, "Core DB Template for Central DB.", False),
            UniteePropertyEnum.CORE_DB_TEMPLATE_RUN_DBFILE: (
                self._handle_string_config, "Core DB Template for Run DB.", False),
        }


def path_to_core_absolute_path(configured_dir):
    from arjuna import ArjunaCore
    ret_path = None
    if configured_dir.startswith("*"):
        if configured_dir.startswith("*/") or configured_dir.startswith("*\\"):
            ret_path = file_utils.get_canonical_path(ARJUNA_ROOT + configured_dir[1:])
        else:
            ret_path = file_utils.get_canonical_path(ARJUNA_ROOT + os.path.sep + configured_dir[1:])
    else:
        ret_path = configured_dir
    return file_utils.normalize_path(ret_path)


def path_to_project_absolute_path(project_dir, configured_dir):
    from arjuna import ArjunaCore
    ret_path = None
    if file_utils.is_absolute_path(configured_dir):
        ret_path = configured_dir
    else:
        ret_path = file_utils.get_canonical_path(project_dir + os.path.sep + configured_dir)
    return file_utils.normalize_path(ret_path)


Notes on Test Session
---------------------
1. Concept of test session in its existing form needs to go away.
2. One execution of arjuna will be one test session.
3. Only when master-slave mode is introduced, master will have concept of multiple
test sessions that run on multiple nodes each running one arjuna execution and hence one session.
Master acts as a collector of such sessions.
4. 




Tests to be conducted
---------------------
1. Create a new project and verify that structure are created as epected.
2. tests should be put in modules and new unittest should be enforced to pick them from only there.
3. 


GOM
---
The default model for Gui automation in Arjuna.
- Done with App, pages and widgets.
- Elements are loaded in a greedy manner. Lazy is too much of state checking.
- Tentative: Create NestedElement. Nestedlement can not have find feature.
- PartialElement can not have find feature.
- A widget is found using automator.
- Custom controls like tabgroup will be found using automator. Then its root element for further finding.
- config should be a keyword arg.
- Move to greedy instead of lazy loading.
- To remove complex state management, introduce redundancy, but implemenet separate flows:
    - nested vs direct element finding
    - first time find (parent finds it), and refinding (element asks for it from parent)

Explore Py-Needle
-----------------
Visual Testing 
