diff --git a/module/testtask/control.php b/module/testtask/control.php index 6057dc98b6..6ecd39c93b 100644 --- a/module/testtask/control.php +++ b/module/testtask/control.php @@ -1288,6 +1288,7 @@ class testtask extends control $nextCase['version'] = $preAndNext->next->version; } + $this->view->title = $this->lang->testtask->lblRunCase; $this->view->run = $run; $this->view->preCase = $preCase; $this->view->nextCase = $nextCase; @@ -1441,6 +1442,7 @@ class testtask extends control $results = $this->testtask->getResults(0, $caseID, $status); } + if(empty($this->testcase)) $this->app->loadLang('testcase'); $this->view->case = $case; $this->view->runID = $runID; $this->view->results = $results; diff --git a/module/testtask/js/common.ui.js b/module/testtask/js/common.ui.js index c9d8cd6618..87fb8df9d2 100644 --- a/module/testtask/js/common.ui.js +++ b/module/testtask/js/common.ui.js @@ -64,3 +64,89 @@ function suitEndDate() endDate = $.zui.formatDate(convertStringToDate(beginDate).addDays(1), 'yyyy-MM-dd'); $('#end').val(endDate); } + +/** + * Create bug from fail case. + * + * @param event $event + * @access public + * @return void + */ +function createBug(event) +{ + var $form = $(event.target).closest('form'); + var stepIdList = ''; + $form.find('.step .step-id input[type="checkbox"]:checked').each(function() + { + if($(this).prop('checked')) stepIdList += $(this).val() + '_'; + }); + + $form.attr('action', $.createLink('bug', 'create', bugCreateParams + ',stepIdList=' + stepIdList)); +} + +/** + * Toggle results show or hide. + * + * @param event $event + * @access public + * @return void + */ +function toggleShowResults(event) +{ + var $target = $(event.target).closest('tr'); + if($target.data('status') == 'running') return; + $target.toggleClass('show-detail'); + var show = $target.hasClass('show-detail'); + $target.next('.result-detail').toggleClass('hidden', !show); + $target.find('.collapse-handle').toggleClass('icon-angle-down', !show).toggleClass('icon-angle-top', show);; +} + +/** + * Toggle check all. + * + * @param event $event + * @access public + * @return void + */ +function toggleCheckAll(event) +{ + var $checkAll = $(event.target).closest('td').find("input[type='checkbox']"); + var isChecked = !$checkAll.prop('checked'); + $checkAll.prop('checked', isChecked); + + $checkAll.closest('tbody').children('tr').find('input[type=checkbox]').prop('checked', isChecked); +} + +/** + * Toggle child item check status. + * + * @param event $event + * @access public + * @return void + */ +function toggleCheckChildItem(event) +{ + var $target = $(event.target).closest('td').find("input[type='checkbox']"); + var isChecked = !$target.prop('checked'); + $target.prop('checked', isChecked); + + var $next = $target.closest('tr').next(); + + while($target.closest('tr').hasClass('step-group') && $next.length && $next.hasClass('step-item')) + { + $next.find("input[type='checkbox']").prop('checked', isChecked); + $next = $next.next(); + } + + if($target.closest('tr').hasClass('step-item')) + { + var parentStepKey = $target.closest('tr').data('parent'); + var allSiblings = $target.closest('tbody').find('.step-item.group-' + parentStepKey).length + var checkedSiblings = $target.closest('tbody').find('.step-item.group-' + parentStepKey + ' input[type=checkbox]:checked').length + + $target.closest('tr').prevAll('.step-group').first().find('input[type=checkbox]').prop('checked', allSiblings == checkedSiblings); + } + + var $tbody = $target.closest('tbody'); + $tbody.find('.check-all input[type=checkbox]').prop('checked', $tbody.find('.check-item input[type=checkbox]').length == $tbody.find('.check-item input[type=checkbox]:checked').length); +} diff --git a/module/testtask/js/results.ui.js b/module/testtask/js/results.ui.js new file mode 100644 index 0000000000..f50e423c31 --- /dev/null +++ b/module/testtask/js/results.ui.js @@ -0,0 +1,34 @@ +$(function() +{ + if($('tr').length == 0) return false; + + if($('tr').first().data('status') == 'ready') + { + $('tr').first().trigger('click'); + } + else + { + var times = 0; + var id = $('tr').first().data('id') + var link = $.createLink('testtask', 'ajaxGetResult', 'resultID=' + id); + + var resultInterval = setInterval(() => { + times++; + if(times > 600) + { + clearInterval(resultInterval); + } + + $.get(link, function(task) + { + task = JSON.parse(task); + task = task.data; + if(task.ZTFResult != '') + { + clearInterval(resultInterval); + loadPage(); + } + }); + }, 1000); + } +}); diff --git a/module/testtask/lang/de.php b/module/testtask/lang/de.php index 07cf75743f..a60f4edc00 100644 --- a/module/testtask/lang/de.php +++ b/module/testtask/lang/de.php @@ -140,7 +140,7 @@ $lang->testtask->browseBySuite = 'Browse by Suite'; $lang->testtask->passAll = 'Alle erfolgreich'; $lang->testtask->pass = 'Erfolgreich'; $lang->testtask->fail = 'Fehlgeschlagen'; -$lang->testtask->showResult = 'Ausführungen %s'; +$lang->testtask->showResult = 'Ausführungen %s'; $lang->testtask->showFail = 'Fehlgeschlagen %s'; $lang->testtask->confirmDelete = 'Möchten Sie dieses Build löschen?'; diff --git a/module/testtask/lang/en.php b/module/testtask/lang/en.php index 6b49eb1388..f8eba755e4 100644 --- a/module/testtask/lang/en.php +++ b/module/testtask/lang/en.php @@ -140,7 +140,7 @@ $lang->testtask->browseBySuite = 'Browse by Suite'; $lang->testtask->passAll = 'Pass All'; $lang->testtask->pass = 'Pass'; $lang->testtask->fail = 'Failed'; -$lang->testtask->showResult = 'Run %s times'; +$lang->testtask->showResult = 'Run %s times'; $lang->testtask->showFail = 'Failed %s times'; $lang->testtask->confirmDelete = 'Do you want to delete this build?'; diff --git a/module/testtask/lang/fr.php b/module/testtask/lang/fr.php index a052dbf563..86a147de48 100644 --- a/module/testtask/lang/fr.php +++ b/module/testtask/lang/fr.php @@ -140,7 +140,7 @@ $lang->testtask->browseBySuite = 'Browse by Suite'; $lang->testtask->passAll = 'Tout Réussir'; $lang->testtask->pass = 'Réussite'; $lang->testtask->fail = 'Echec'; -$lang->testtask->showResult = 'Jouée %s fois'; +$lang->testtask->showResult = 'Jouée %s fois'; $lang->testtask->showFail = 'Echouée %s fois'; $lang->testtask->confirmDelete = 'Voulez-vous supprimer ce build ?'; diff --git a/module/testtask/lang/zh-cn.php b/module/testtask/lang/zh-cn.php index b0988f2808..8112270692 100644 --- a/module/testtask/lang/zh-cn.php +++ b/module/testtask/lang/zh-cn.php @@ -140,7 +140,7 @@ $lang->testtask->browseBySuite = '按套件查看'; $lang->testtask->passAll = '全部通过'; $lang->testtask->pass = '通过'; $lang->testtask->fail = '失败'; -$lang->testtask->showResult = '共执行%s次'; +$lang->testtask->showResult = '共执行%s次'; $lang->testtask->showFail = '失败%s次'; $lang->testtask->confirmDelete = '您确认要删除该测试单吗?'; @@ -162,7 +162,7 @@ $lang->testtask->allCases = '全部用例'; $lang->testtask->lblCases = '用例列表'; $lang->testtask->lblUnlinkCase = '移除用例'; $lang->testtask->lblRunCase = '执行用例'; -$lang->testtask->lblResults = '执行结果'; +$lang->testtask->lblResults = '用例执行结果'; $lang->testtask->placeholder = new stdclass(); $lang->testtask->placeholder->begin = '开始日期'; diff --git a/module/testtask/ui/results.html.php b/module/testtask/ui/results.html.php new file mode 100644 index 0000000000..cfc86d5bb5 --- /dev/null +++ b/module/testtask/ui/results.html.php @@ -0,0 +1,364 @@ + + * @package testcase + * @link https://www.zentao.net + */ +namespace zin; + +jsVar('tab', $app->tab); + +modalHeader +( + set::title($lang->testtask->lblResults), + set::entityText($case->title), + set::entityID($case->id), +); + +div +( + setClass('border-b'), + div + ( + h::strong($lang->testcase->precondition), + ), + div + ( + setClass('leading-6 h-6 my-2'), + nl2br($case->precondition), + ), +); + +$count = count($results); +$trs = array(); +$trCount = 1; +$failCount = 0; +foreach($results as $i => $result) +{ + $class = ($result->caseResult == 'pass' ? 'success' : ($result->caseResult == 'fail' ? 'danger' : ($result->caseResult == 'blocked' ? 'warning' : ''))); + $fileCount = '(' . count($result->files) . ')'; + if($class != 'success') $failCount ++; + $trs[] = h::tr + ( + setClass("result-item result{$class}"), + on::click('toggleShowResults'), + set('data-id', $result->id), + set('data-status', $result->node > 0 && empty($result->ZTFResult) ? 'running': 'ready'), + h::td + ( + width('120px'), + "#{$result->id}" + ), + h::td + ( + width('180px'), + $result->date + ), + $result->node > 0 ? h::td + ( + sprintf($lang->testtask->runNode, zget($users, $result->lastRunner), $result->nodeName, $lang->testtask->runCase), + span + ( + setClass('label'), + $lang->testtask->auto + ), + ) : h::td + ( + zget($users, $result->lastRunner) . ' ' . $lang->testtask->runCase, + ), + h::td + ( + width('150px'), + zget($builds, $result->build, ''), + ), + h::td + ( + setClass('text-right'), + width('60px'), + $result->node == 0 || !empty($result->ZTFResult) ? h::strong + ( + setClass("result-testcase status-{$result->caseResult}"), + $lang->testcase->resultList[$result->caseResult], + ) : h::strong + ( + setClass('text-waring'), + $lang->testtask->running, + ), + ), + h::td + ( + width('60px'), + !empty($result->files) ? h::a + ( + set::href("#caseResult{$result->id}"), + set('data-toggle', 'modal'), + $lang->files . $fileCount, + ) : '', + ), + h::td + ( + setClass('text-center'), + width('50px'), + icon + ( + setClass('collapse-handle'), + 'angle-down' + ), + ), + ); + + $stepID = $childID = 0; + $stepResultTrs = array(); + foreach($result->stepResults as $key => $stepResult) + { + if(empty($stepResult['type'])) $stepResult['type'] = 'step'; + if(empty($stepResult['parent'])) $stepResult['parent'] = 0; + if($stepResult['type'] == 'group' || $stepResult['type'] == 'step') + { + $stepID ++; + $childID = 0; + } + + $stepClass = $stepResult['type'] == 'item' ? "step-item group-{$stepResult['parent']}" : "step-group"; + $inputName = $stepResult['type'] != 'group' ? 'stepIdList[]' : ''; + + $itemTds = array(); + if($stepResult['type'] != 'group') + { + $modalID = $result->id . '-' . $key; + $fileCount = '(' . count($stepResult['files']) . ')'; + + $itemTds[] = h::td + ( + setClass('text-left'), + isset($stepResult['expect']) ? html(nl2br($stepResult['expect'])) : '', + ); + $itemTds[] = h::td(isset($result->version) ? html($result->version) : ''); + $itemTds[] = !empty($stepResult['result']) ? h::td + ( + setClass("status-{$stepResult['result']} text-center"), + $lang->testcase->resultList[$stepResult['result']], + ) : h::td(); + $itemTds[] = !empty($stepResult['result']) ? h::td + ( + nl2br($stepResult['real']), + ) : h::td(); + $itemTds[] = !empty($stepResult['result']) ? h::td + ( + setClass('text-center'), + !empty($stepResult['files']) ? h::a + ( + set::href("#caseResult{$modalID}"), + set('data-toggle', 'modal'), + $lang->files . $fileCount, + ) : '', + ) : h::td(); + } + + $stepResultTrs[] = h::tr + ( + setClass("step {$stepClass}"), + set('data-parent', $stepResult['parent']), + set('data-id', $key), + h::td + ( + setClass('step-id'), + $result->caseResult == 'fail' ? div + ( + setClass('checkbox-primary check-item'), + on::click('toggleCheckChildItem'), + h::input + ( + set::id($inputName), + set('type', 'checkbox'), + set('name', $inputName), + set('value', $key), + ), + h::label($stepClass == 'step-group' ? $stepID : ''), + ) : $stepID, + ), + h::td + ( + setClass('text-left'), + $stepResult['type'] == 'group' ? set('colspan', '6') : '', + div + ( + setClass('inputGroup'), + $stepResult['type'] == 'item' ? h::span + ( + setClass('step-item-id mr-2'), + "{$stepID}.{$childID}", + ) : '', + isset($stepResult['desc']) ? html(nl2br($stepResult['desc'])) : '', + ), + ), + $itemTds, + ); + $childID ++; + } + $stepResultTrs[] = $result->caseResult == 'fail' && common::hasPriv('testcase', 'createBug') ? h::tr + ( + h::td + ( + set('colspan', '2'), + div + ( + setClass('checkbox-primary check-all'), + on::click('toggleCheckAll'), + h::input + ( + set::id("checkAll[{$i}]"), + set('type', 'checkbox'), + set('name', 'checkAll'), + ), + h::label($lang->selectAll), + ), + ), + h::td + ( + set('colspan', '5'), + ), + h::td + ( + setClass('to-bug-button'), + btn + ( + setClass('btn'), + set::type('primary'), + set::btnType('btnType'), + on::click('createBug'), + set('data-target', '_blank'), + set('data-close-modal', true), + $lang->testcase->createBug + ), + ), + ) : ''; + $stepResultTrs[] = !empty($result->ZTFResult) && $result->node > 0 ? h::td + ( + set('colspan', '6'), + h::p($lang->testtask->runningLog), + h::p($result->ZTFResult), + ) : ''; + + $projectParam = $this->app->tab == 'project' ? "projectID={$this->session->project}," : ''; + $executionParam = $this->app->tab == 'execution' ? "executionID={$this->session->execution}" : ""; + $executionParam = isset($testtask) ? "executionID={$testtask->execution}" : $executionParam; + $params = isset($testtask) ? ",testtask={$testtask->id}" : ""; + $params = $params . ',buildID=' . (isset($testtask->build) ? $testtask->build : $result->build); + $linkParams = "product={$case->product}&branch={$case->branch}&extras={$projectParam}caseID={$case->id},version={$case->version},resultID={$result->id},runID={$result->run}{$params}"; + if($executionParam) $params .= ',' . $executionParam; + $trs[] = h::tr + ( + set::id('tr-detail_' . $trCount ++), + setClass('result-detail hidden'), + h::td + ( + setClass('pd-0'), + set('colspan', '7'), + h::form + ( + setClass('form load-indicator form-ajax form-grid'), + set('data-params', $linkParams), + set('action', createLink('bug', 'create', $linkParams)), + h::table + ( + setClass('table condensed resultSteps'), + h::thead + ( + h::tr + ( + h::td + ( + width('60px'), + $lang->testcase->stepID, + ), + h::td + ( + setClass('text-left'), + $lang->testcase->stepDesc, + ), + h::td + ( + width('25%'), + setClass('text-left'), + $lang->testcase->stepExpect, + ), + h::td + ( + width('5%'), + setClass('text-left'), + $lang->testcase->stepVersion, + ), + h::td + ( + width('80px'), + setClass('text-center'), + $lang->testcase->result, + ), + h::td + ( + width('20%'), + setClass('text-left'), + $lang->testcase->real, + ), + h::td + ( + width('80px'), + ), + ), + ), + h::tbody + ( + $stepResultTrs, + ), + ), + modal + ( + set::id("stepResult{$result->id}-{$stepID}"), + set::title($lang->files), + !empty($stepResult['files']) ? fileList(set::files($stepResult['files'])) : '', + ), + ), + ), + ); +} + +div +( + div + ( + setClass('main'), + set::id('casesResults'), + h::table + ( + setClass('table condensed table-hover border'), + $case->auto != 'unit' ? h::caption + ( + setClass('text-left bg-lighter leading-8 px-3 border'), + h::strong + ( + $lang->testcase->result, + h::span + ( + setClass('ml-4'), + html(sprintf($lang->testtask->showResult, $count)), + ), + h::span + ( + setClass('ml-2'), + html(sprintf($lang->testtask->showFail, $failCount)), + ), + ), + ) : '', + $trs, + ), + ), +); +jsVar('bugCreateParams', $linkParams); + +render(); +