Beispiel #1
0
def checkbox(element, instance: wx.CheckBox):
    props = element['props']
    set_basic_props(instance, props)
    instance.Unbind(wx.EVT_CHECKBOX)
    if props.get('on_change'):
        instance.Bind(wx.EVT_CHECKBOX, props['on_change'])
    return instance
class TestRunnerTab(Panel):
    def __init__(self, *args, **kwargs):
        Panel.__init__(self, *args, **kwargs)
        sizer = GridBagSizer(5, 5)

        row = 0
        col = 0
        self.cb_html_output = CheckBox(self, label=u'Report in HTML')
        self.cb_html_output.Bind(EVT_CHECKBOX, self.__on_check)
        sizer.Add(self.cb_html_output,
                  pos=(row, col),
                  flag=FLAG_ALL_AND_EXPAND)

        col += 1
        self.txt_html_report = TextCtrl(self, style=TE_READONLY)
        self.txt_html_report.Disable()
        sizer.Add(self.txt_html_report,
                  pos=(row, col),
                  span=(1, 3),
                  flag=FLAG_ALL_AND_EXPAND)

        col += 3
        self.btn_select_html = Button(self, label=u'Select HTML file')
        self.btn_select_html.Disable()
        self.btn_select_html.Bind(EVT_BUTTON, self.__on_select_file)
        sizer.Add(self.btn_select_html,
                  pos=(row, col),
                  flag=FLAG_ALL_AND_EXPAND)

        row += 1
        col = 0
        self.cb_xml_output = CheckBox(self, label=u'Report in XML')
        self.cb_xml_output.Bind(EVT_CHECKBOX, self.__on_check)
        sizer.Add(self.cb_xml_output, pos=(row, col), flag=FLAG_ALL_AND_EXPAND)

        col += 1
        self.txt_xml_report = TextCtrl(self, style=TE_READONLY)
        self.txt_xml_report.Disable()
        sizer.Add(self.txt_xml_report,
                  pos=(row, col),
                  span=(1, 3),
                  flag=FLAG_ALL_AND_EXPAND)

        col += 3
        self.btn_select_xml = Button(self, label=u'Select XML file')
        self.btn_select_xml.Disable()
        self.btn_select_xml.Bind(EVT_BUTTON, self.__on_select_file)
        sizer.Add(self.btn_select_xml,
                  pos=(row, col),
                  flag=FLAG_ALL_AND_EXPAND)

        row += 1
        col = 0
        self.cb_options = CheckBox(self, label=u'Additional options')
        self.cb_options.Bind(EVT_CHECKBOX, self.__on_check)
        sizer.Add(self.cb_options, pos=(row, col), flag=FLAG_ALL_AND_EXPAND)

        col += 1
        self.txt_options = TextCtrl(self)
        self.txt_options.Disable()
        sizer.Add(self.txt_options,
                  pos=(row, col),
                  span=(1, 3),
                  flag=FLAG_ALL_AND_EXPAND)

        col += 3
        self.btn_nose_help = Button(self, label=u'Show help')
        self.btn_nose_help.Bind(EVT_BUTTON, self.__on_show_help)
        sizer.Add(self.btn_nose_help, pos=(row, col), flag=FLAG_ALL_AND_EXPAND)

        row += 1
        col = 0
        self.btn_load_tests_from_files = Button(self,
                                                label=u'Load tests from files')
        self.btn_load_tests_from_files.Bind(EVT_BUTTON,
                                            self.__load_tests_from_files)
        sizer.Add(self.btn_load_tests_from_files,
                  pos=(row, col),
                  flag=FLAG_ALL_AND_EXPAND)

        col += 1
        self.btn_load_tests_from_dir = Button(
            self, label=u'Load tests from directory')
        self.btn_load_tests_from_dir.Bind(EVT_BUTTON,
                                          self.__load_tests_from_directory)
        sizer.Add(self.btn_load_tests_from_dir,
                  pos=(row, col),
                  flag=FLAG_ALL_AND_EXPAND)

        col += 1
        dummy_label = StaticText(self)
        sizer.Add(dummy_label, pos=(row, col), flag=FLAG_ALL_AND_EXPAND)

        col += 1
        self.cb_browser = Choice(self,
                                 choices=Browser.get_supported_browsers())
        self.cb_browser.Select(0)
        sizer.Add(self.cb_browser, pos=(row, col), flag=FLAG_ALL_AND_EXPAND)

        col += 1
        self.btn_run = Button(self, label=u'Run test cases')
        self.btn_run.Bind(EVT_BUTTON, self.__run_tests)
        sizer.Add(self.btn_run, pos=(row, col), flag=FLAG_ALL_AND_EXPAND)

        row += 1
        col = 0
        window = SplitterWindow(self, style=SP_3D | SP_LIVE_UPDATE)
        self.tree_ctrl = CustomTreeCtrl(
            window,
            style=TR_SINGLE | TR_HAS_BUTTONS | TR_AUTO_CHECK_CHILD
            | TR_AUTO_CHECK_PARENT | TR_AUTO_TOGGLE_CHILD)
        self.tree_ctrl.SetBackgroundColour(self.GetBackgroundColour())
        self.tree_ctrl.SetForegroundColour(self.GetForegroundColour())
        self.tree_ctrl.Bind(EVT_TREE_ITEM_CHECKED, self.__on_tree_check)

        self.txt_ctrl = TextCtrl(window,
                                 style=TE_MULTILINE | TE_READONLY | HSCROLL
                                 | VSCROLL)
        font_size = self.txt_ctrl.GetFont().GetPointSize()
        self.txt_ctrl.SetFont(
            Font(font_size, FONTFAMILY_TELETYPE, NORMAL, NORMAL))

        window.SplitVertically(self.tree_ctrl, self.txt_ctrl)
        sizer.Add(window,
                  pos=(row, col),
                  span=(1, 5),
                  flag=FLAG_ALL_AND_EXPAND)

        sizer.AddGrowableCol(2, 1)
        sizer.AddGrowableRow(row, 1)
        self.SetSizerAndFit(sizer)

    def __on_show_help(self, evt):
        text = check_output(['nosetests', '--help'])
        DialogWithText(self, u'Help for nosetests', text).ShowModal()

    def __on_select_file(self, evt):
        folder = self.__get_safe_path_from_root_folder(RootFolder.REPORTS)
        obj = evt.GetEventObject()
        txt_ctrl = None
        if obj == self.btn_select_html:
            wildcard = u'*.html'
            txt_ctrl = self.txt_html_report
        elif obj == self.btn_select_xml:
            wildcard = u'*.xml'
            txt_ctrl = self.txt_xml_report
        else:
            wildcard = u'*.*'
        dialog = FileDialog(self,
                            defaultDir=folder,
                            style=FD_SAVE | FD_OVERWRITE_PROMPT,
                            wildcard=wildcard)
        if dialog.ShowModal() == ID_OK and txt_ctrl:
            txt_ctrl.SetValue(dialog.GetPath())

    def __on_check(self, evt):
        cb_obj = evt.GetEventObject()
        checkboxes_and_txt_ctrls = {
            self.cb_html_output: self.txt_html_report,
            self.cb_options: self.txt_options,
            self.cb_xml_output: self.txt_xml_report
        }
        checkboxes_and_btns = {
            self.cb_html_output: self.btn_select_html,
            self.cb_xml_output: self.btn_select_xml
        }
        txt_ctrl = checkboxes_and_txt_ctrls[cb_obj]
        btn = checkboxes_and_btns.get(cb_obj)
        if txt_ctrl.IsEnabled():
            txt_ctrl.Disable()
            if btn:
                btn.Disable()
        else:
            txt_ctrl.Enable()
            if btn:
                btn.Enable()

    def __on_tree_check(self, evt):
        # styles doesn't work: TR_AUTO_CHECK_CHILD | TR_AUTO_CHECK_PARENT | TR_AUTO_TOGGLE_CHILD
        # TODO: fix if all children are check then one child is uncheck - parent is checked
        item = evt.GetItem()
        checked = item.IsChecked()
        parent = item.GetParent()

        def all_children_are_checked(_parent):
            states = [child.IsChecked() for child in _parent.GetChildren()]
            uniq_states = list(set(states))
            return len(uniq_states) == 1 and uniq_states[0] is True

        self.tree_ctrl.AutoCheckChild(item, checked)
        if parent:
            self.tree_ctrl.AutoCheckParent(item,
                                           all_children_are_checked(parent))

    def __get_safe_path_from_root_folder(self, subfolder=None):
        folder = self.GetTopLevelParent().get_root_folder()
        if subfolder and folder:
            path_for_subfolder = os.path.join(folder, subfolder)
            if os.path.exists(path_for_subfolder):
                return path_for_subfolder

        return folder if folder else '.'

    def __load_tests_to_tree(self, file_paths=None, dir_path=None):
        if file_paths:
            python_files = file_paths
        elif dir_path:
            python_files = [f for f in get_list_of_files(dir_path, True)]
        else:
            python_files = []

        python_files = [
            f for f in python_files if 'test' in os.path.basename(f)
            and os.path.splitext(f)[-1] == '.py'
        ]
        if len(python_files) > 0:
            syspath = list(os.sys.path)
            try:
                root_folder = self.__get_safe_path_from_root_folder()

                if root_folder not in os.sys.path:
                    os.sys.path.append(root_folder)

                checkbox_type = 1
                self.tree_ctrl.DeleteAllItems()
                root = self.tree_ctrl.AddRoot('All test cases', checkbox_type)

                for python_file in python_files:
                    top_item = self.tree_ctrl.AppendItem(
                        root, os.path.abspath(python_file), checkbox_type)

                    parsed_classes = ParsedClass.get_parsed_classes(
                        python_file)
                    for parsed_class in parsed_classes:
                        item = self.tree_ctrl.AppendItem(
                            top_item, parsed_class.name, checkbox_type)

                        test_methods = [
                            k for k in parsed_class.methods.keys()
                            if k.startswith('test_')
                        ]
                        for tc_name in test_methods:
                            self.tree_ctrl.AppendItem(item, tc_name,
                                                      checkbox_type)

                self.tree_ctrl.ExpandAll()
            except Exception:
                show_error_dialog(self, traceback.format_exc(),
                                  'Cannot add test cases')
            finally:
                os.sys.path = syspath

    def __load_tests_from_directory(self, evt):
        folder = self.__get_safe_path_from_root_folder(RootFolder.TESTS_FOLDER)
        if folder:
            dialog = DirDialog(self,
                               defaultPath=folder,
                               style=DD_DIR_MUST_EXIST)
            if dialog.ShowModal() == ID_OK:
                self.__load_tests_to_tree(dir_path=dialog.GetPath())
        else:
            show_dialog_path_doesnt_exist(self, folder)

    def __load_tests_from_files(self, evt):
        folder = self.__get_safe_path_from_root_folder(RootFolder.TESTS_FOLDER)
        if folder:
            dialog = FileDialog(self,
                                defaultDir=folder,
                                style=FD_OPEN | FD_FILE_MUST_EXIST
                                | FD_MULTIPLE,
                                wildcard=u'*.py')
            if dialog.ShowModal() == ID_OK:
                self.__load_tests_to_tree(file_paths=dialog.GetPaths())
        else:
            show_dialog_path_doesnt_exist(self, folder)

    def __get_nose_command(self):
        root = self.tree_ctrl.GetRootItem()
        tests = []
        for _file in root.GetChildren():
            for _class in _file.GetChildren():
                for test_case in _class.GetChildren():
                    if test_case.IsChecked():
                        # TODO: fix for files that contain spaces
                        tests.append(u'%s:%s.%s' %
                                     (_file.GetText(), _class.GetText(),
                                      test_case.GetText()))
        args = [
            '--with-path="%s"' % self.__get_safe_path_from_root_folder(),
            '--logging-level=INFO'
        ]

        use_html_report = (self.cb_html_output.IsChecked()
                           and len(self.txt_html_report.GetValue()) > 0)
        if use_html_report:
            report_path = self.txt_html_report.GetValue()
            args.append('--with-html --html-file="%s"' % report_path)

        use_xml_report = (self.cb_xml_output.IsChecked()
                          and len(self.txt_xml_report.GetValue()) > 0)
        if use_xml_report:
            report_path = self.txt_xml_report.GetValue()
            args.append('--with-xunit --xunit-file="%s"' % report_path)

        use_options = (self.cb_options.IsChecked()
                       and len(self.txt_options.GetValue()) > 0)
        if use_options:
            report_path = self.txt_options.GetValue()
            args.append(report_path)

        nose_cmd = [u'nosetests'] + args + tests
        return nose_cmd

    def __run_tests(self, evt):
        # TODO: do not run if root folder is not selected
        self.txt_ctrl.Clear()

        dialog = InfiniteProgressBarDialog(
            self, u'Running test cases',
            u'Running selected test cases... Please wait...')

        def wrap_func():
            stdout = os.sys.stdout
            stderr = os.sys.stderr
            redirected = RedirectText(self.txt_ctrl)
            os.sys.stdout = redirected
            os.sys.stderr = redirected
            try:
                nose_cmd = self.__get_nose_command()
                browser_name = self.cb_browser.GetStringSelection()
                Browser.DEFAULT_BROWSER = browser_name
                report_folder = self.__get_safe_path_from_root_folder(
                    RootFolder.REPORTS)
                BaseTest.FAILED_SCREENSHOT_FOLDER = report_folder

                easy_selenium_cmd = u" ".join(nose_cmd).replace(
                    "nosetests", "easy_selenium_cli.py -b " + browser_name)
                print(u"Executing command:\n%s" % easy_selenium_cmd)
                print(u"Nose output:")

                run(argv=nose_cmd[1:])
            finally:
                dialog.close_event.set()
                os.sys.stdout = stdout
                os.sys.stderr = stderr

        run_in_separate_thread(wrap_func)
        dialog.ShowModal()