diff --git a/module/testcase/control.php b/module/testcase/control.php index bc2d1287ae..4e98c59fb5 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -192,6 +192,9 @@ class testcase extends control $this->view->groupBy = $groupBy; $this->view->groupByList = $groupByList; $this->view->cases = $groupCases; + $this->view->suiteList = $this->loadModel('testsuite')->getSuites($productID); + $this->view->suiteID = 0; + $this->view->moduleID = 0; $this->display(); } @@ -343,6 +346,7 @@ class testcase extends control { $paddingCount = $this->config->testcase->defaultSteps - count($steps); $step = new stdclass(); + $step->type = 'item'; $step->desc = ''; $step->expect = ''; for($i = 1; $i <= $paddingCount; $i ++) $steps[] = $step; @@ -596,6 +600,7 @@ class testcase extends control if(empty($case->steps)) { $step = new stdclass(); + $step->type = 'item'; $step->desc = ''; $step->expect = ''; $case->steps[] = $step; @@ -1103,7 +1108,7 @@ class testcase extends control $relatedModules = $this->dao->select('id, name')->from(TABLE_MODULE)->where('id')->in($relatedModuleIdList)->fetchPairs(); $relatedStories = $this->dao->select('id,title')->from(TABLE_STORY) ->where('id')->in($relatedStoryIdList)->fetchPairs(); $relatedCases = $this->dao->select('id, title')->from(TABLE_CASE)->where('id')->in($relatedCaseIdList)->fetchPairs(); - $relatedSteps = $this->dao->select('`case`, version, `desc`, expect')->from(TABLE_CASESTEP)->where('`case`')->in(@array_keys($cases))->orderBy('version desc,id')->fetchGroup('case'); + $relatedSteps = $this->dao->select('parent,`case`,version,type,`desc`,expect')->from(TABLE_CASESTEP)->where('`case`')->in(@array_keys($cases))->orderBy('version desc,id')->fetchGroup('case'); $relatedModules = array('0' => '/') + $relatedModules; foreach($cases as $case) @@ -1112,14 +1117,25 @@ class testcase extends control $case->stepExpect = ''; if(isset($relatedSteps[$case->id])) { - $i = 1; + $i = $childId = 0; foreach($relatedSteps[$case->id] as $step) { + $stepId = 0; + if($step->type == 'group' or ($step->type == 'item' and $step->parent == 0)) + { + $i++; + $childId = 0; + $stepId = $i; + } + else + { + $stepId = $i . '.' . $childId; + } if($step->version != $case->version) continue; $sign = (in_array($this->post->fileType, array('html', 'xml'))) ? '
' : "\n"; - $case->stepDesc .= $i . ". " . htmlspecialchars_decode($step->desc) . $sign; - $case->stepExpect .= $i . ". " . htmlspecialchars_decode($step->expect) . $sign; - $i ++; + $case->stepDesc .= $stepId . ". " . htmlspecialchars_decode($step->desc) . $sign; + $case->stepExpect .= $stepId . ". " . htmlspecialchars_decode($step->expect) . $sign; + $childId ++; } } @@ -1390,30 +1406,43 @@ class testcase extends control { $step = trim($step); if(empty($step)) continue; - if(preg_match('/^([0-9]+)([.、]{1})/U', $step, $out)) + if(preg_match('/^(([0-9]+)\.[0-9]+)([.、]{1})/U', $step, $out)) + { + $num = $out[1]; + $parent = $out[2]; + $sign = $out[3]; + $signbit = $sign == '.' ? 1 : 3; + $step = trim(substr($step, strlen($num) + $signbit)); + if(!empty($step)) $caseStep[$num]['content'] = $step; + $caseStep[$num]['type'] = 'item'; + $caseStep[$parent]['type'] = 'group'; + } + elseif(preg_match('/^([0-9]+)([.、]{1})/U', $step, $out)) { $num = $out[1]; $sign = $out[2]; $signbit = $sign == '.' ? 1 : 3; - $step = trim(substr($step, strpos($step, $sign) + $signbit)); - if(!empty($step)) $caseStep[$num] = $step; + $step = trim(substr($step, strlen($num) + $signbit)); + if(!empty($step)) $caseStep[$num]['content'] = $step; + $caseStep[$num]['type'] = 'item'; } elseif(isset($num)) { - $caseStep[$num] .= "\n" . $step; + $caseStep[$num]['content'] .= "\n" . $step; } else { if($field == 'stepDesc') { $num = 1; - $caseStep[$num] = $step; + $caseStep[$num]['content'] = $step; + $caseStep[$num]['type'] = 'item'; } if($field == 'stepExpect' and isset($stepData[$row]['desc'])) { end($stepData[$row]['desc']); $num = key($stepData[$row]['desc']); - $caseStep[$num] = $step; + $caseStep[$num]['content'] = $step; } } } diff --git a/module/testcase/css/common.css b/module/testcase/css/common.css index f747704ac4..49fce99311 100644 --- a/module/testcase/css/common.css +++ b/module/testcase/css/common.css @@ -1,15 +1,15 @@ .table-form > tbody > tr > td .btn-group-vertical > .btn {margin-left: 0!important; padding: 2px 8px} #steps .step-id {text-align: right} -#steps .step-child-id {background-color: transparent; border: none; display: none; width: 30px; padding-left: 0; padding-right: 0; text-align: right; padding-right: 8px} +#steps .step-item-id {background-color: transparent; border: none; display: none; width: 30px; padding-left: 0; padding-right: 0; text-align: right; padding-right: 8px} #steps .checkbox-inline input[type="checkbox"] {top: -2px} #steps .btn-group .btn {padding-left: 0; padding-right: 0; min-width: 30px;} .step-actions {width: 100px;} #steps .active td {transition: background-color .5s;} #steps .step-group .step-steps {resize: none; max-height: 30px;} #steps .step-group .step-expects {display: none;} -#steps .step-child .step-child-id {display: table-cell; min-width: 40px;} -#steps .step-child .step-id {color: transparent} +#steps .step-item .step-item-id {display: table-cell; min-width: 40px;} +#steps .step-item .step-id {color: transparent} #steps .step-actions {width: 90px; text-align: center;} #steps .btn-step-move {cursor: move} diff --git a/module/testcase/js/common.js b/module/testcase/js/common.js index 1700bdd404..d144ad21af 100644 --- a/module/testcase/js/common.js +++ b/module/testcase/js/common.js @@ -152,7 +152,7 @@ function initSteps(selector) var stepID; if(isGroup || !childId) { - $step.removeClass('step-child'); + $step.removeClass('step-item'); stepID = parentId++; $step.find('.step-id').text(stepID); if(isGroup) childId = 1; @@ -160,9 +160,11 @@ function initSteps(selector) else { stepID = (parentId - 1) + '.' + (childId++); - $step.addClass('step-child').find('.step-child-id').text(stepID); + $step.addClass('step-item').find('.step-item-id').text(stepID); } - $step.find('.step-id-control').val(stepID); + $step.find('[name^="steps["]').attr('name', "steps[" +stepID + ']'); + $step.find('[name^="stepType["]').attr('name', "stepType[" +stepID + ']'); + $step.find('[name^="expects["]').attr('name', "expects[" +stepID + ']'); }); }; var initSortable = function() @@ -210,6 +212,7 @@ function initSteps(selector) refreshStepsID(); }).on('click', '.btn-step-delete', function() { + if($('tbody#steps tr.step').size() == 1) return false; $(this).closest('.step').remove(); refreshStepsID(); }).on('change', '.step-type', function() diff --git a/module/testcase/lang/zh-cn.php b/module/testcase/lang/zh-cn.php index 6673adae56..e092da619d 100644 --- a/module/testcase/lang/zh-cn.php +++ b/module/testcase/lang/zh-cn.php @@ -13,6 +13,7 @@ $lang->testcase->id = '用例编号'; $lang->testcase->product = "所属{$lang->productCommon}"; $lang->testcase->module = '所属模块'; $lang->testcase->lib = "所属库"; +$lang->testcase->branch = "分支/平台"; $lang->testcase->moduleAB = '模块'; $lang->testcase->story = '相关需求'; $lang->testcase->title = '用例标题'; diff --git a/module/testcase/model.php b/module/testcase/model.php index 1c022837fd..b3b24de23a 100644 --- a/module/testcase/model.php +++ b/module/testcase/model.php @@ -49,7 +49,7 @@ class testcaseModel extends model ->add('version', 1) ->add('fromBug', $bugID) ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion((int)$this->post->story)) - ->remove('steps,expects,files,labels') + ->remove('steps,expects,files,labels,stepType') ->setDefault('story', 0) ->join('stage', ',') ->get(); @@ -67,15 +67,20 @@ class testcaseModel extends model { $caseID = $this->dao->lastInsertID(); $this->loadModel('file')->saveUpload('testcase', $caseID); + $parentStepID = 0; foreach($this->post->steps as $stepID => $stepDesc) { if(empty($stepDesc)) continue; + $isGroup = isset($_POST['stepType'][$stepID]); $step = new stdClass(); + $step->parent = $isGroup ? 0 : $parentStepID; $step->case = $caseID; $step->version = 1; + $step->type = $isGroup ? 'group' : 'item'; $step->desc = htmlspecialchars($stepDesc); $step->expect = htmlspecialchars($this->post->expects[$stepID]); $this->dao->insert(TABLE_CASESTEP)->data($step)->autoCheck()->exec(); + if($isGroup) $parentStepID = $this->dao->lastInsertID(); } return array('status' => 'created', 'id' => $caseID); } @@ -510,7 +515,7 @@ class testcaseModel extends model ->setIF($this->post->story != false and $this->post->story != $oldCase->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) ->setDefault('story,branch', 0) ->join('stage', ',') - ->remove('comment,steps,expects,files,labels') + ->remove('comment,steps,expects,files,labels,stepType') ->get(); if($this->isForceReview() and $stepChanged) $case->status = 'wait'; $this->dao->update(TABLE_CASE)->data($case)->autoCheck()->batchCheck($this->config->testcase->edit->requiredFields, 'notempty')->where('id')->eq((int)$caseID)->exec(); @@ -518,15 +523,20 @@ class testcaseModel extends model { if($stepChanged) { + $parentStepID = 0; foreach($this->post->steps as $stepID => $stepDesc) { if(empty($stepDesc)) continue; + $isGroup = isset($_POST['stepType'][$stepID]); $step = new stdclass(); + $step->parent = $isGroup ? 0 : $parentStepID; $step->case = $caseID; $step->version = $version; + $step->type = $isGroup ? 'group' : 'item'; $step->desc = htmlspecialchars($stepDesc); $step->expect = htmlspecialchars($this->post->expects[$stepID]); $this->dao->insert(TABLE_CASESTEP)->data($step)->autoCheck()->exec(); + if($isGroup) $parentStepID = $this->dao->lastInsertID(); } } @@ -931,13 +941,14 @@ class testcaseModel extends model $steps = array(); if(isset($_POST['desc'][$key])) { - foreach($this->post->desc[$key] as $id => $desc) + foreach($data->desc[$key] as $id => $desc) { $desc = trim($desc); if(empty($desc))continue; $step = new stdclass(); + $step->type = $data->stepType[$key][$id]; $step->desc = $desc; - $step->expect = trim($this->post->expect[$key][$id]); + $step->expect = trim($data->expect[$key][$id]); $steps[] = $step; } @@ -974,16 +985,21 @@ class testcaseModel extends model $this->dao->update(TABLE_CASE)->data($caseData)->where('id')->eq($caseID)->autoCheck()->exec(); if($stepChanged) { + $parentStepID = 0; foreach($steps as $id => $step) { $step = (array)$step; if(empty($step['desc'])) continue; + $isGroup = $step['type'] == 'group'; $stepData = new stdclass(); + $stepData->parent = $isGroup ? 0 : $parentStepID; $stepData->case = $caseID; $stepData->version = $version; + $stepData->type = $step['type']; $stepData->desc = htmlspecialchars($step['desc']); $stepData->expect = htmlspecialchars($step['expect']); $this->dao->insert(TABLE_CASESTEP)->data($stepData)->autoCheck()->exec(); + if($isGroup) $parentStepID = $this->dao->lastInsertID(); } } $oldCase->steps = $this->joinStep($oldStep); @@ -1004,17 +1020,22 @@ class testcaseModel extends model if(!dao::isError()) { - $caseID = $this->dao->lastInsertID(); - foreach($this->post->desc[$key] as $id => $desc) + $caseID = $this->dao->lastInsertID(); + $parentStepID = 0; + foreach($data->desc[$key] as $id => $desc) { $desc = trim($desc); if(empty($desc)) continue; + $isGroup = $data->stepType[$key][$id] == 'group'; $stepData = new stdclass(); + $stepData->parent = $isGroup ? 0 : $parentStepID; $stepData->case = $caseID; $stepData->version = 1; + $stepData->type = $isGroup ? 'group' : 'item'; $stepData->desc = htmlspecialchars($desc); - $stepData->expect = htmlspecialchars($this->post->expect[$key][$id]); + $stepData->expect = htmlspecialchars($data->expect[$key][$id]); $this->dao->insert(TABLE_CASESTEP)->data($stepData)->autoCheck()->exec(); + if($isGroup) $parentStepID = $this->dao->lastInsertID(); } $this->action->create('case', $caseID, 'Opened'); } diff --git a/module/testcase/view/caseheader.html.php b/module/testcase/view/caseheader.html.php index a291f6bc09..5d95bd624d 100644 --- a/module/testcase/view/caseheader.html.php +++ b/module/testcase/view/caseheader.html.php @@ -111,7 +111,7 @@ ?> - + moduleName == 'story' and $this->methodName == 'zerocase')) common::printIcon('testcase', 'report', "productID=$productID&browseType=$browseType&branchID=$branch&moduleID=$moduleID"); ?>
diff --git a/module/testcase/view/create.html.php b/module/testcase/view/create.html.php index f679e61642..785855f8dc 100644 --- a/module/testcase/view/create.html.php +++ b/module/testcase/view/create.html.php @@ -140,10 +140,10 @@ - +
- +
- - - +
@@ -165,21 +163,19 @@ $step):?> - +
- + desc, "rows='1' class='form-control autosize step-steps'") ?>
- - expect, "rows='1' class='form-control autosize step-expects'") ?> - + expect, "rows='1' class='form-control autosize step-expects'") ?>
diff --git a/module/testcase/view/edit.html.php b/module/testcase/view/edit.html.php index 625df93e96..acbe3e5060 100644 --- a/module/testcase/view/edit.html.php +++ b/module/testcase/view/edit.html.php @@ -53,10 +53,10 @@ - +
- +
- - - +
@@ -78,21 +76,19 @@ steps as $stepID => $step):?> - +
- + desc, "rows='1' class='form-control autosize step-steps'") ?>
- - expect, "rows='1' class='form-control autosize step-expects'") ?> - + expect, "rows='1' class='form-control autosize step-expects'") ?>
diff --git a/module/testcase/view/showimport.html.php b/module/testcase/view/showimport.html.php index e67d28473b..f34c22b13e 100644 --- a/module/testcase/view/showimport.html.php +++ b/module/testcase/view/showimport.html.php @@ -64,9 +64,10 @@ $desc):?> - - - + + + +
diff --git a/module/testcase/view/view.html.php b/module/testcase/view/view.html.php index 8178ea60f8..b13ab220f7 100644 --- a/module/testcase/view/view.html.php +++ b/module/testcase/view/view.html.php @@ -92,13 +92,24 @@ steps as $stepID => $step) { - $stepID += 1; - echo "$stepID"; - echo "" . nl2br($step->desc) . ""; - echo "" . nl2br($step->expect) . ""; + $stepClass = "step-{$step->type}"; + if($step->type == 'group' or ($step->type == 'item' and $step->parent == 0)) + { + $stepId++; + $childId = 0; + } + if($step->type == 'item' and $step->parent == 0) $stepClass = 'step-group'; + echo ""; + echo "$stepId"; + echo "
"; + if($step->type == 'item' and $step->parent != 0) echo "{$stepId}.{$childId}"; + echo nl2br($step->desc) . ""; + echo "" . nl2br($step->expect) . "
"; echo ""; + $childId ++; } ?> diff --git a/module/testsuite/control.php b/module/testsuite/control.php index d86528816a..0e7a55d24d 100644 --- a/module/testsuite/control.php +++ b/module/testsuite/control.php @@ -523,6 +523,7 @@ class testsuite extends control { $paddingCount = $this->config->testcase->defaultSteps - count($steps); $step = new stdclass(); + $step->type = 'item'; $step->desc = ''; $step->expect = ''; for($i = 1; $i <= $paddingCount; $i ++) $steps[] = $step; diff --git a/module/testsuite/css/createcase.css b/module/testsuite/css/createcase.css new file mode 100644 index 0000000000..9334cd7f46 --- /dev/null +++ b/module/testsuite/css/createcase.css @@ -0,0 +1,32 @@ +#steps .step-id {text-align: right} +#steps .step-item-id {background-color: transparent; border: none; display: none; width: 30px; padding-left: 0; padding-right: 0; text-align: right; padding-right: 8px} +#steps .checkbox-inline input[type="checkbox"] {top: -2px} +#steps .btn-group .btn {padding-left: 0; padding-right: 0; min-width: 30px;} +.step-actions {width: 100px;} +#steps .active td {transition: background-color .5s;} +#steps .step-group .step-steps {resize: none; max-height: 30px;} +#steps .step-group .step-expects {display: none;} +#steps .step-item .step-item-id {display: table-cell; min-width: 40px;} +#steps .step-item .step-id {color: transparent} +#steps .step-actions {width: 90px; text-align: center;} + +#steps .btn-step-move {cursor: move} +#steps.sortable > tr.drag-shadow {display: none} +#steps.sortable-sorting > tr {transition: all .2s; position: relative; z-index: 5; opacity: .3;} +#steps.sortable-sorting {cursor: move;} +#steps.sortable-sorting > tr.drag-row {opacity: 1; z-index: 10; box-shadow: 0 2px 4px red} +#steps.sortable-sorting > tr.drag-row + tr > td {box-shadow: inset 0 4px 2px rgba(0,0,0,.2)} +#steps.sortable-sorting > tr.drag-row > td {background-color: #edf3fe!important} +#steps.sortable > tr.drop-success > td {background-color: #cfe0ff; transition: background-color 2s;} + +.table-bordered .step-actions {width: 98px;} +.table-bordered > #steps > tr > td {padding: 0; background-color: #fafafa; border: 1px solid #ddd!important; border-left-style: dotted!important; border-right-style: dotted!important;} +.table-bordered > #steps > tr > td.step-id { padding-right: 8px;} +.table-bordered > #steps > tr > td .btn {border-color: transparent; background-color: transparent} +.table-bordered > #steps > tr > td .btn:hover, +.table-bordered > #steps > tr > td .btn:focus {background-color: #ddd} +.table-bordered > #steps .input-group-addon {border: none; background-color: transparent; border-left: 1px dotted #e5e5e5} +.table-bordered > #steps > tr > td textarea {border-color: #fff; box-shadow: none} +.table-bordered > #steps > tr > td textarea:hover {border-color: #808080;} +.table-bordered > #steps > tr > td textarea:focus {border-color: #4d90fe;} +.table-bordered > #steps .step-child .step-child-id {border-right: 1px dotted #ddd; border-left: none} diff --git a/module/testsuite/js/createcase.js b/module/testsuite/js/createcase.js index a8d4ed1747..5941fc3bbc 100644 --- a/module/testsuite/js/createcase.js +++ b/module/testsuite/js/createcase.js @@ -1,19 +1,4 @@ var newRowID = 0; -function createRow() -{ - if(newRowID == 0) newRowID = $('.stepID').size(); - newRowID ++; - var newRow = ""; - newRow += ""; - newRow += ""; - newRow += ""; - newRow += ""; - newRow += ""; - newRow += ""; - newRow += ""; - newRow += ""; - return newRow; -} function loadLibModules(libID) { @@ -26,43 +11,125 @@ function loadLibModules(libID) } /** - * Delete a step row. + * Init testcase steps in form * - * @param int $rowID + * @param string selector * @access public * @return void */ -function deleteRow(rowID) +function initSteps(selector) { - if($('.stepID').size() == 1) return; - $('#row' + rowID).remove(); - updateStepID(); -} + if(navigator.userAgent.indexOf("Firefox") < 0) + { + $(document).on('input keyup paste change', 'textarea.autosize', function() + { + this.style.height = 'auto'; + this.style.height = (this.scrollHeight + 2) + "px"; + }); + } + var $steps = $(selector || '#steps'); + var $stepTemplate = $('#stepTemplate').detach().removeClass('template').attr('id', null); + var initSortableCallTask = null; + var groupNameText = $steps.data('groupName'); + var insertStepRow = function($row, count) + { + if(count === undefined) count = 1; + for(var i = 0; i < count; ++i) + { + var $step = $stepTemplate.clone(); + if($row) $row.after($step); + else $steps.append($step); + $step.addClass('step-new'); + setTimeout(function(){$step.find('.step-steps').focus();}, 10); -/** - * Insert before the step. - * - * @param int $rowID - * @access public - * @return void - */ -function preInsert(rowID) -{ - $('#row' + rowID).before(createRow()); - updateStepID(); -} - -/** - * Insert after the step. - * - * @param int $rowID - * @access public - * @return void - */ -function postInsert(rowID) -{ - $('#row' + rowID).after(createRow()); - updateStepID(); + } + }; + var toggleStepRowType = function($row, toggleisGroup) + { + if(toggleisGroup === undefined) targetIsGroup = $row.find('.step-type').is(':checked'); + $row.toggleClass('step-group', targetIsGroup); + $row.find('.step-steps').toggleClass('autosize', !targetIsGroup).attr('placeholder', targetIsGroup ? groupNameText : null).focus(); + }; + var refreshStepsID = function() + { + var parentId = 1, childId = 0; + $steps.children('.step:not(.drag-shadow)').each(function(idx) + { + var $step = $(this); + var isGroup = $step.find('.step-type').is(':checked'); + var stepID; + if(isGroup || !childId) + { + $step.removeClass('step-item'); + stepID = parentId++; + $step.find('.step-id').text(stepID); + if(isGroup) childId = 1; + } + else + { + stepID = (parentId - 1) + '.' + (childId++); + $step.addClass('step-item').find('.step-item-id').text(stepID); + } + $step.find('[name^="steps["]').attr('name', "steps[" +stepID + ']'); + $step.find('[name^="stepType["]').attr('name', "stepType[" +stepID + ']'); + $step.find('[name^="expects["]').attr('name', "expects[" +stepID + ']'); + }); + }; + var initSortable = function() + { + var isMouseDown = false; + var $moveStep = null, moveOrder = 0; + $steps.on('mousedown', '.btn-step-move', function() + { + isMouseDown = true; + $moveStep = $(this).closest('.step').addClass('drag-row'); + + $(document).off('.sortable').one('mouseup.sortable', function() + { + isMouseDown = false; + $moveStep.removeClass('drag-row'); + $steps.removeClass('sortable-sorting'); + $moveStep = null; + }); + $steps.addClass('sortable-sorting'); + }).on('mouseenter', '.step:not(.drag-row)', function() + { + if(!isMouseDown) return; + var $targetStep = $(this); + $steps.children('.step').each(function(idx) + { + $(this).data('order', idx); + }); + moveOrder = $moveStep.data('order'); + var targetOrder = $targetStep.data('order'); + if(moveOrder === targetOrder) return; + else if(targetOrder > moveOrder) + { + $targetStep.after($moveStep); + } + else if(targetOrder < moveOrder) + { + $targetStep.before($moveStep); + } + refreshStepsID(); + }); + } + $steps.on('click', '.btn-step-add', function() + { + insertStepRow($(this).closest('.step')); + refreshStepsID(); + }).on('click', '.btn-step-delete', function() + { + if($('tbody#steps tr.step').size() == 1) return false; + $(this).closest('.step').remove(); + refreshStepsID(); + }).on('change', '.step-type', function() + { + toggleStepRowType($(this).closest('.step')); + refreshStepsID(); + }); + initSortable(); + refreshStepsID(); } /** @@ -80,4 +147,5 @@ function updateStepID() $(function() { $('[data-toggle=tooltip]').tooltip(); + initSteps(); }) diff --git a/module/testsuite/view/createcase.html.php b/module/testsuite/view/createcase.html.php index 036287d87e..aed3e03533 100644 --- a/module/testsuite/view/createcase.html.php +++ b/module/testsuite/view/createcase.html.php @@ -105,31 +105,63 @@ testcase->steps;?> - +
- + - $step) - { - $stepID += 1; - echo ""; - echo ""; - echo ''; - echo ''; - echo ""; - echo ''; - } - ?> + + + + + + + + $step):?> + + + + + + + +
testcase->stepID;?> testcase->stepDesc;?> testcase->stepExpect;?>actions;?>actions;?>
$stepID' . html::textarea('steps[]', $step->desc, "rows='1' class='form-control'") . '' . html::textarea('expects[]', $step->expect, "rows='1' class='form-control'") . '"; - echo ""; - echo ""; - echo ""; - echo "
+
+ + + + + +
+
+
+ + + +
+
+
+ + desc, "rows='1' class='form-control autosize step-steps'") ?> + + + +
+
expect, "rows='1' class='form-control autosize step-expects'") ?> +
+ + + +
+
diff --git a/module/testtask/css/results.css b/module/testtask/css/results.css index 56eaca379d..51574128d9 100644 --- a/module/testtask/css/results.css +++ b/module/testtask/css/results.css @@ -1 +1,12 @@ body{background:white;} + +.resultSteps .step-id {text-align: right} +.resultSteps .step-item-id {background-color: transparent; border: none; display: none; width: 30px; padding-left: 0; padding-right: 0; text-align: right; padding-right: 8px} +.resultSteps .checkbox-inline input[type="checkbox"] {top: -2px} +.resultSteps .btn-group .btn {padding-left: 0; padding-right: 0; min-width: 30px;} +.resultSteps .step-actions {width: 98px;} +.resultSteps .active td {transition: background-color .5s;} +.resultSteps .step-group .step-steps {resize: none; max-height: 30px;} +.resultSteps .step-group .step-expects {display: none;} +.resultSteps .step-item .step-item-id {display: table-cell;} +.resultSteps .step-item .step-id {color: transparent} diff --git a/module/testtask/css/runcase.css b/module/testtask/css/runcase.css index 0956a05876..da268222e9 100644 --- a/module/testtask/css/runcase.css +++ b/module/testtask/css/runcase.css @@ -7,3 +7,25 @@ #filesName {float: right;} .nav > li {margin-right: 5px; display: inline-block; margin-top: 5px;} + +#steps .step-id {text-align: right} +#steps .step-item-id {background-color: transparent; border: none; display: none; width: 30px; padding-left: 0; padding-right: 0; text-align: right; padding-right: 8px} +#steps .checkbox-inline input[type="checkbox"] {top: -2px} +#steps .btn-group .btn {padding-left: 0; padding-right: 0; min-width: 30px;} +#steps .step-actions {width: 98px;} +#steps .active td {transition: background-color .5s;} +#steps .step-group .step-steps {resize: none; max-height: 30px;} +#steps .step-group .step-expects {display: none;} +#steps .step-item .step-item-id {display: table-cell;} +#steps .step-item .step-id {color: transparent} + +.resultSteps .step-id {text-align: right} +.resultSteps .step-item-id {background-color: transparent; border: none; display: none; width: 30px; padding-left: 0; padding-right: 0; text-align: right; padding-right: 8px} +.resultSteps .checkbox-inline input[type="checkbox"] {top: -2px} +.resultSteps .btn-group .btn {padding-left: 0; padding-right: 0; min-width: 30px;} +.resultSteps .step-actions {width: 98px;} +.resultSteps .active td {transition: background-color .5s;} +.resultSteps .step-group .step-steps {resize: none; max-height: 30px;} +.resultSteps .step-group .step-expects {display: none;} +.resultSteps .step-item .step-item-id {display: table-cell;} +.resultSteps .step-item .step-id {color: transparent} diff --git a/module/testtask/model.php b/module/testtask/model.php index f00360f992..a993eb678d 100644 --- a/module/testtask/model.php +++ b/module/testtask/model.php @@ -594,33 +594,57 @@ class testtaskModel extends model $relatedSteps = $this->dao->select('*')->from(TABLE_CASESTEP) ->where('`case`')->eq($runCaseID) ->andWhere('version')->in($relatedVersions) - ->fetchAll(); + ->orderBy('id') + ->fetchGroup('version', 'id'); $runs = $this->dao->select('t1.id,t2.build')->from(TABLE_TESTRUN)->alias('t1') ->leftJoin(TABLE_TESTTASK)->alias('t2')->on('t1.task=t2.id') ->where('t1.id')->in($runIdList) ->fetchPairs(); + $this->loadModel('file'); + $files = $this->dao->select('*')->from(TABLE_FILE) + ->where("(objectType = 'caseResult' or objectType = 'stepResult')") + ->andWhere('objectID')->in(array_keys($results)) + ->andWhere('extra')->ne('editor') + ->orderBy('id') + ->fetchAll(); + $resultFiles = array(); + $stepFiles = array(); + foreach($files as $file) + { + $file->webPath = $this->file->webPath . $file->pathname; + $file->realPath = $this->app->getAppRoot() . "www/data/upload/{$this->app->company->id}/" . $file->pathname; + if($file->objectType == 'caseResult') + { + $resultFiles[$file->objectID][$file->id] = $file; + } + elseif($file->objectType == 'stepResult' and $file->extra !== '') + { + $stepFiles[$file->objectID][(int)$file->extra][$file->id] = $file; + } + } foreach($results as $resultID => $result) { $result->stepResults = unserialize($result->stepResults); $result->build = $result->run ? zget($runs, $result->run, 0) : 0; - $result->files = $this->loadModel('file')->getByObject('caseResult', $resultID);//Get files of case result. - $results[$resultID] = $result; - - foreach($relatedSteps as $key => $step) + $result->files = zget($resultFiles, $resultID, array()); //Get files of case result. + if(isset($relatedSteps[$result->version])) { - if($result->version == $step->version) + $relatedStep = $relatedSteps[$result->version]; + foreach($relatedStep as $stepID => $step) { - $result->stepResults[$step->id]['desc'] = $step->desc; - $result->stepResults[$step->id]['expect'] = $step->expect; + $relatedStep[$stepID] = (array)$step; + if(isset($result->stepResults[$stepID])) + { + $relatedStep[$stepID]['result'] = $result->stepResults[$stepID]['result']; + $relatedStep[$stepID]['real'] = $result->stepResults[$stepID]['real']; + } } + $result->stepResults = $relatedStep; } /* Get files of step result. */ - foreach($result->stepResults as $stepID => $stepResult) - { - $result->stepResults[$stepID]['files'] = $this->loadModel('file')->getByObject('stepResult', $resultID, $stepID); - } + foreach($result->stepResults as $stepID => $stepResult) $result->stepResults[$stepID]['files'] = isset($stepFiles[$resultID][$stepID]) ? $stepFiles[$resultID][$stepID] : array(); } return $results; } diff --git a/module/testtask/view/results.html.php b/module/testtask/view/results.html.php index 704e5a05b5..07a0fb058a 100644 --- a/module/testtask/view/results.html.php +++ b/module/testtask/view/results.html.php @@ -49,7 +49,7 @@ - +
@@ -58,32 +58,46 @@ - + stepResults as $key => $stepResult): ?> id . '-' . $key; $fileCount = '(' . count($stepResult['files']) . ')'; ?> - - - - + + + + + - + -
testcase->stepID;?>testcase->stepVersion;?> testcase->result;?> testcase->real;?>
> +
+ {$stepId}.{$childId}";?> + +
+
version)) echo nl2br($result->version);?> text-center'>testcase->resultList[$stepResult['result']];?> files . $fileCount, '', "data-toggle='modal' data-type='iframe'")?>
diff --git a/module/testtask/view/runcase.html.php b/module/testtask/view/runcase.html.php index b139a1d42f..548e4c41c4 100644 --- a/module/testtask/view/runcase.html.php +++ b/module/testtask/view/runcase.html.php @@ -20,7 +20,7 @@
- +
@@ -38,17 +38,35 @@ { $step = new stdclass(); $step->id = 0; + $step->parent = 0; $step->case = $run->case->id; + $step->type = 'item'; $step->desc = ''; $step->expect = ''; $run->case->steps[] = $step; } + $stepId = $childId = 0; ?> case->steps as $key => $step):?> - - - - + type}"; + if($step->type == 'group' or ($step->type == 'item' and $step->parent == 0)) + { + $stepId++; + $childId = 0; + } + if($step->type == 'item' and $step->parent == 0) $stepClass = 'step-group'; + ?> + + + + type != 'group'):?> + + +
testcase->precondition;?> case->precondition;?>
desc);?>expect);?>
type == 'group') echo "colspan='4'"?>> +
+ type == 'item' and $step->parent != 0) echo "{$stepId}.{$childId}";?> + desc);?> +
+
expect);?> id]", $lang->testcase->resultList, 'pass', "class='form-control'");?> @@ -58,7 +76,9 @@