From 335042cc030e62f472db92a4322ba097e8e3dc65 Mon Sep 17 00:00:00 2001 From: wangyuting Date: Fri, 2 Jun 2023 09:24:31 +0800 Subject: [PATCH] * Refactoring the create function of testcases. --- module/testcase/config.php | 7 +- module/testcase/config/form.php | 21 ++ module/testcase/control.php | 89 ++++----- module/testcase/model.php | 116 ++++------- module/testcase/ui/browse.html.php | 29 +++ module/testcase/ui/create.html.php | 301 +++++++++++++++++++++++++++++ module/testcase/zen.php | 30 +++ 7 files changed, 467 insertions(+), 126 deletions(-) create mode 100644 module/testcase/ui/create.html.php diff --git a/module/testcase/config.php b/module/testcase/config.php index 46776b1572..cc2dcd8d34 100644 --- a/module/testcase/config.php +++ b/module/testcase/config.php @@ -5,9 +5,10 @@ $config->testcase->batchCreate = 10; $config->testcase->needReview = 0; $config->testcase->create = new stdclass(); -$config->testcase->edit = new stdclass(); -$config->testcase->create->requiredFields = 'title,type'; -$config->testcase->edit->requiredFields = 'title,type'; +$config->testcase->create->requiredFields = 'product,title,type'; + +$config->testcase->edit = new stdclass(); +$config->testcase->edit->requiredFields = 'title,type'; $config->testcase->editor = new stdclass(); $config->testcase->editor->edit = array('id' => 'comment', 'tools' => 'simpleTools'); diff --git a/module/testcase/config/form.php b/module/testcase/config/form.php index 0f03008b0a..14f66dfb70 100644 --- a/module/testcase/config/form.php +++ b/module/testcase/config/form.php @@ -3,3 +3,24 @@ declare(strict_types=1); global $lang, $app; $config->testcase->form = new stdclass(); + +$config->testcase->form->create = array(); +$config->testcase->form->create['product'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->testcase->form->create['branch'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->testcase->form->create['module'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->testcase->form->create['type'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->testcase->form->create['stage'] = array('required' => false, 'type' => 'array', 'default' => array(''), 'filter' => 'join'); +$config->testcase->form->create['story'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->testcase->form->create['scene'] = array('required' => false, 'type' => 'int', 'default' => 0); +$config->testcase->form->create['title'] = array('required' => true, 'type' => 'string', 'filter' => 'trim'); +$config->testcase->form->create['color'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->testcase->form->create['pri'] = array('required' => false, 'type' => 'int', 'default' => 3); +$config->testcase->form->create['precondition'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->testcase->form->create['steps'] = array('required' => false, 'type' => 'array', 'default' => array('')); +$config->testcase->form->create['expects'] = array('required' => false, 'type' => 'array', 'default' => array('')); +$config->testcase->form->create['stepType'] = array('required' => false, 'type' => 'array', 'default' => array('')); +$config->testcase->form->create['keywords'] = array('required' => false, 'type' => 'string', 'default' => ''); +$config->testcase->form->create['status'] = array('required' => false, 'type' => 'string', 'default' => 'wait'); +$config->testcase->form->create['version'] = array('required' => false, 'type' => 'int', 'default' => 1); +$config->testcase->form->create['openedBy'] = array('required' => false, 'type' => 'string', 'default' => $app->user->account); +$config->testcase->form->create['openedDate'] = array('required' => false, 'type' => 'date', 'default' => helper::now()); diff --git a/module/testcase/control.php b/module/testcase/control.php index 811820484e..f09a710845 100644 --- a/module/testcase/control.php +++ b/module/testcase/control.php @@ -426,6 +426,44 @@ class testcase extends control */ public function create($productID, $branch = '', $moduleID = 0, $from = '', $param = 0, $storyID = 0, $extras = '') { + if(!empty($_POST)) + { + $case = form::data($this->config->testcase->form->create) + ->setIF($from == 'bug', 'fromBug', $param) + ->setIF($this->post->auto, 'auto', 'auto') + ->setIF($this->post->auto && $this->post->script, 'script', htmlentities($this->post->script)) + ->setIF($this->forceNotReview() || $this->post->forceNotReview, 'status', 'normal') + ->setIF($this->app->tab == 'project', 'project', $this->session->project) + ->setIF($this->app->tab == 'execution', 'execution', $this->session->execution) + ->setIF($this->post->story, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story)) + ->get(); + + $this->testcaseZen->checkCreateFormData($case); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + + helper::setcookie('lastCaseModule', $case->module); + helper::setcookie('lastCaseScene', $case->scene); + + $caseID = $this->testcase->create($case); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + + /* If the story is linked project, make the case link the project. */ + $this->testcase->syncCase2Project($case, $caseID); + + $message = $this->executeHooks($caseID); + if(!$message) $message = $this->lang->saveSuccess; + + if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $message, 'id' => $caseID)); + /* If link from no head then reload. */ + if(isonlybody()) return $this->send(array('result' => 'success', 'message' => $message, 'closeModal' => true)); + + helper::setcookie('caseModule', 0); + /* Use this session link, when the tab is not QA, a session of the case list exists, and the session is not from the Dynamic page. */ + $useSession = ($this->app->tab != 'qa' and $this->session->caseList and strpos($this->session->caseList, 'dynamic') === false); + $locateLink = $this->app->tab == 'project' ? $this->createLink('project', 'testcase', "projectID={$this->session->project}") : $this->createLink('testcase', 'browse', "productID={$this->post->product}&branch={$this->post->branch}"); + return $this->send(array('result' => 'success', 'message' => $message, 'load' => $useSession ? $this->session->caseList : $locateLink)); + } + $testcaseID = ($from and strpos('testcase|work|contribute', $from) !== false) ? $param : 0; $bugID = $from == 'bug' ? $param : 0; $executionID = $from == 'execution' ? $param : 0; @@ -433,53 +471,6 @@ class testcase extends control $extras = str_replace(array(',', ' '), array('&', ''), $extras); parse_str($extras, $output); - $this->loadModel('story'); - if(!empty($_POST)) - { - if(!empty($_FILES['scriptFile'])) unset($_FILES['scriptFile']); - $response['result'] = 'success'; - - setcookie('lastCaseModule', (int)$this->post->module, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, false); - setcookie('lastCaseScene', (int)$this->post->scene, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, false); - $caseResult = $this->testcase->create($bugID); - if(!$caseResult or dao::isError()) - { - $response['result'] = 'fail'; - $response['message'] = dao::getError(); - return $this->send($response); - } - - $caseID = $caseResult['id']; - if($caseResult['status'] == 'exists') - { - $response['message'] = sprintf($this->lang->duplicate, $this->lang->testcase->common); - $response['locate'] = $this->createLink('testcase', 'view', "caseID=$caseID"); - return $this->send($response); - } - - $this->loadModel('action'); - $this->action->create('case', $caseID, 'Opened'); - if($this->testcase->getStatus('create') == 'wait') $this->action->create('case', $caseID, 'submitReview'); - - /* If the story is linked project, make the case link the project. */ - $this->testcase->syncCase2Project($caseResult['caseInfo'], $caseID); - - $message = $this->executeHooks($caseID); - if($message) $this->lang->saveSuccess = $message; - $response['message'] = $this->lang->saveSuccess; - - if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $caseID)); - /* If link from no head then reload. */ - if(isonlybody()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true)); - - setcookie('caseModule', 0, 0, $this->config->webRoot, '', $this->config->cookieSecure, false); - - /* Use this session link, when the tab is not QA, a session of the case list exists, and the session is not from the Dynamic page. */ - $useSession = ($this->app->tab != 'qa' and $this->session->caseList and strpos($this->session->caseList, 'dynamic') === false); - $locateLink = $this->app->tab == 'project' ? $this->createLink('project', 'testcase', "projectID={$this->session->project}") : $this->createLink('testcase', 'browse', "productID={$this->post->product}&branch={$this->post->branch}"); - $response['locate'] = $useSession ? $this->session->caseList : $locateLink; - return $this->send($response); - } if(empty($this->products)) $this->locate($this->createLink('product', 'create')); /* Init vars. */ @@ -525,7 +516,7 @@ class testcase extends control } /* Set productID and branch. */ - $productID = $this->product->saveState($productID, $this->products); + $productID = $this->product->saveVisitState($productID, $this->products); if($branch === '') $branch = $this->cookie->preBranch; /* Set menu. */ @@ -594,7 +585,7 @@ class testcase extends control $modules = $this->tree->getAllChildID($modules); } - $stories = $this->story->getProductStoryPairs($productID, $branch, $modules, 'active', 'id_desc', 50, 'full', 'story', false); + $stories = $this->loadModel('story')->getProductStoryPairs($productID, $branch, $modules, 'active', 'id_desc', 50, 'full', 'story', false); if($this->app->tab != 'qa' and $this->app->tab != 'product') { $projectID = $this->app->tab == 'project' ? $this->session->project : $this->session->execution; diff --git a/module/testcase/model.php b/module/testcase/model.php index fb51d42b6b..0d6885e783 100644 --- a/module/testcase/model.php +++ b/module/testcase/model.php @@ -33,89 +33,57 @@ class testcaseModel extends model /** * Create a case. * - * @param int $bugID + * @param object $case * @access public - * @return void + * @return bool|int */ - function create($bugID) + public function create($case): bool|int { - $steps = $this->post->steps; - $expects = $this->post->expects; - foreach($expects as $key => $value) - { - if(!empty($value) and empty($steps[$key])) - { - dao::$errors[] = sprintf($this->lang->testcase->stepsEmpty, $key); - return false; - } - } - - if(!empty($_POST['auto'])) - { - $_POST['auto'] = 'auto'; - if($_POST['script']) $_POST['script'] = htmlentities($_POST['script']); - } - else - { - unset($_POST['script']); - } - - $now = helper::now(); - $status = $this->getStatus('create'); - $case = fixer::input('post') - ->add('status', $status) - ->add('version', 1) - ->add('fromBug', $bugID) - ->setDefault('openedBy', $this->app->user->account) - ->setDefault('openedDate', $now) - ->setIF($this->app->tab == 'project', 'project', $this->session->project) - ->setIF($this->app->tab == 'execution', 'execution', $this->session->execution) - ->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion((int)$this->post->story)) - ->remove('steps,expects,files,labels,stepType,forceNotReview,scriptFile,scriptName') - ->setDefault('story', 0) - ->cleanInt('story,product,branch,module') - ->join('stage', ',') - ->get(); - - $param = ''; - if(!empty($case->lib))$param = "lib={$case->lib}"; - if(!empty($case->product))$param = "product={$case->product}"; - $result = $this->loadModel('common')->removeDuplicate('case', $case, $param); - if($result and $result['stop']) return array('status' => 'exists', 'id' => $result['duplicate']); - if(empty($case->product)) $this->config->testcase->create->requiredFields = str_replace('story', '', $this->config->testcase->create->requiredFields); - /* Value of story may be showmore. */ - $case->story = (int)$case->story; - $this->dao->insert(TABLE_CASE)->data($case)->autoCheck()->batchCheck($this->config->testcase->create->requiredFields, 'notempty')->checkFlow()->exec(); - if(!$this->dao->isError()) + $this->dao->insert(TABLE_CASE)->data($case) + ->autoCheck() + ->batchCheck($this->config->testcase->create->requiredFields, 'notempty') + ->checkFlow() + ->exec(); + if(dao::isError()) return false; + + $caseID = $this->dao->lastInsertID(); + + $this->loadModel('action'); + $this->action->create('case', $caseID, 'Opened'); + if($case->status == 'wait') $this->action->create('case', $caseID, 'submitReview'); + + $this->config->dangers = ''; + $this->loadModel('file')->saveUpload('testcase', $caseID, 'autoscript', 'script', 'scriptName'); + $this->loadModel('file')->saveUpload('testcase', $caseID); + + $this->loadModel('score')->create('testcase', 'create', $caseID); + + $parentStepID = 0; + foreach($case->steps as $stepID => $stepDesc) { - $caseID = $this->dao->lastInsertID(); - $this->config->dangers = ''; - $this->loadModel('file')->saveUpload('testcase', $caseID, 'autoscript', 'script', 'scriptName'); - $this->loadModel('file')->saveUpload('testcase', $caseID); - $parentStepID = 0; - $this->loadModel('score')->create('testcase', 'create', $caseID); + if(empty($stepDesc)) continue; - $data = fixer::input('post')->get(); - foreach($data->steps as $stepID => $stepDesc) - { - if(empty($stepDesc)) continue; - $stepType = $this->post->stepType; - $step = new stdClass(); - $step->type = ($stepType[$stepID] == 'item' and $parentStepID == 0) ? 'step' : $stepType[$stepID]; - $step->parent = ($step->type == 'item') ? $parentStepID : 0; - $step->case = $caseID; - $step->version = 1; - $step->desc = rtrim(htmlSpecialString($stepDesc)); - $step->expect = $step->type == 'group' ? '' : rtrim(htmlSpecialString($data->expects[$stepID])); - $this->dao->insert(TABLE_CASESTEP)->data($step)->autoCheck()->exec(); - if($step->type == 'group') $parentStepID = $this->dao->lastInsertID(); - if($step->type == 'step') $parentStepID = 0; - } + $stepType = $this->post->stepType; + $step = new stdClass(); + $step->type = ($stepType[$stepID] == 'item' and $parentStepID == 0) ? 'step' : $stepType[$stepID]; + $step->parent = ($step->type == 'item') ? $parentStepID : 0; + $step->case = $caseID; + $step->version = 1; + $step->desc = rtrim(htmlSpecialString($stepDesc)); + $step->expect = $step->type == 'group' ? '' : rtrim(htmlSpecialString($data->expects[$stepID])); - return array('status' => 'created', 'id' => $caseID, 'caseInfo' => $case); + $this->dao->insert(TABLE_CASESTEP)->data($step) + ->autoCheck() + ->exec(); + + if($step->type == 'group') $parentStepID = $this->dao->lastInsertID(); + if($step->type == 'step') $parentStepID = 0; } + if(dao::isError()) return false; + + return $caseID; } /** diff --git a/module/testcase/ui/browse.html.php b/module/testcase/ui/browse.html.php index ad52982099..6fbd966e3b 100644 --- a/module/testcase/ui/browse.html.php +++ b/module/testcase/ui/browse.html.php @@ -27,6 +27,35 @@ foreach($cases as $case) $cols = array_values($config->testcase->dtable->fieldList); $data = array_values($cases); +featureBar(); +toolbar +( + btngroup + ( + btn + ( + setClass('btn primary'), + set::icon('plus'), + set::url(helper::createLink('testcase', 'create', "productID=$productID&branch=$branch&moduleID=$initModule")), + $lang->testcase->create + ), + dropdown + ( + btn(setClass('btn primary dropdown-toggle'), setStyle(array('padding' => '6px', 'border-radius' => '0 2px 2px 0'))), + set::items + ( + array + ( + array('text' => $lang->testcase->create, 'url' => helper::createLink('testcase', 'create', "productID=$productID&branch=$branch&moduleID=$initModule")), + array('text' => $lang->testcase->batchCreate, 'url' => helper::createLink('testcase', 'batchCreate', "productID=$productID&branch=$branch&moduleID=$initModule")), + array('text' => $lang->testcase->newScene, 'url' => helper::createLink('testcase', 'createScene', "productID=$productID&branch=$branch&moduleID=$initModule")) + ) + ), + set::placement('bottom-end'), + ) + ) +); + dtable ( set::cols($cols), diff --git a/module/testcase/ui/create.html.php b/module/testcase/ui/create.html.php new file mode 100644 index 0000000000..cf5b730443 --- /dev/null +++ b/module/testcase/ui/create.html.php @@ -0,0 +1,301 @@ + + * @package bug + * @link http://www.zentao.net + */ +namespace zin; + +formPanel +( + on::change('#product', 'loadAllNew'), + on::change('#branch', 'loadBranchNew'), + on::click('#refresh', 'loadProductModulesNew'), + to::headingActions(icon('cog-outline')), + formRow + ( + formGroup + ( + set::width('1/2'), + set::class($hiddenProduct ? 'hidden' : ''), + set::label($lang->testcase->product), + inputGroup + ( + select + ( + set::name('product'), + set::items($products), + set::value($productID) + ), + isset($product->type) && $product->type != 'normal' ? select + ( + set::width('100px'), + set::name('branch'), + set::items($branches), + set::value($branch) + ) : null + ) + ), + formGroup + ( + set::width('1/2'), + set::label($lang->testcase->module), + inputGroup + ( + set('id', 'moduleBox'), + select + ( + set::name('module'), + set::items($moduleOptionMenu), + set::value($currentModuleID) + ), + count($moduleOptionMenu) == 1 ? span + ( + set('class', 'input-group-addon'), + a + ( + set('class', 'mr-2'), + set('href', $this->createLink('tree', 'browse', "rootID=$productID&view=bug¤tModuleID=0&branch={$branch}")), + set('data-toggle', 'modal'), + $lang->tree->manage + ), + a + ( + set('id', 'refreshModule'), + set('class', 'text-black'), + set('href', 'javascript:void(0)'), + icon('refresh') + ) + ) : null + ) + ), + ), + formRow + ( + formGroup + ( + set::width('1/2'), + set::label($lang->testcase->scene), + inputGroup + ( + set('id', 'sceneBox'), + select + ( + set::name('scene'), + set::items($sceneOptionMenu), + set::value($currentSceneID) + ) + ) + ) + ), + formRow + ( + formGroup + ( + set::width('1/2'), + set::label($lang->testcase->type), + inputGroup + ( + select + ( + set::name('type'), + set::items($lang->testcase->typeList), + set::value($type) + ), + span + ( + set('class', 'input-group-addon'), + checkbox + ( + set::name('auto'), + set::text($lang->testcase->showAutoCase), + ) + ) + ) + ) + ), + formRow + ( + formGroup + ( + set::width('1/2'), + set::label($lang->testcase->scene), + inputGroup + ( + set('id', 'stageBox'), + select + ( + set::name('stage'), + set::multiple(true), + set::items($lang->testcase->stageList), + set::value($stage) + ) + ) + ) + ), + formRow + ( + formGroup + ( + set::width('1/2'), + set::label($lang->testcase->lblStory), + inputGroup + ( + set('id', 'storyBox'), + select + ( + set::name('story'), + set::items($stories), + set::value($storyID) + ) + ) + ) + ), + formRow + ( + formGroup + ( + set::label($lang->testcase->title), + set::name('title'), + set::value($caseTitle) + ), + formGroup + ( + set::width('180px'), + set::class(), + set::label($lang->testcase->pri), + set::control(array('type' => 'select', 'items' => $lang->testcase->priList)), + set::name('pri'), + set::value() + ), + formGroup + ( + set::width('150px'), + set::class(), + set::label('是否评审'), + set::control(array('type' => 'select', 'items' => $lang->testcase->reviewList)), + set::name('forceNotReview'), + set::value('1') + ) + ), + formRow + ( + formGroup + ( + set::label($lang->testcase->precondition), + set::control(array('type' => 'textarea', 'rows' => 2)), + set::name('precondition'), + set::value($precondition) + ) + ), + formRow + ( + + formGroup + ( + set::label($lang->testcase->steps), + printStepsTable() + ) + ), + formRow + ( + formGroup + ( + set::label($lang->testcase->keywords), + set::name('keywords'), + set::value($keywords) + ) + ), + formRow + ( + formGroup + ( + set::label($lang->testcase->files), + set::name('files[]'), + set::control('file') + ) + ) +); + +render(); + +function printStepsTable() +{ + global $lang; + + $stepsTR = array(); + for($i = 1; $i <= 3; $i ++) + { + $stepsTR[] = h::tr + ( + h::td + ( + set::class('center'), + $i + ), + h::td + ( + inputGroup + ( + textarea + ( + set::rows(1), + set::name("steps[$i]") + ), + span + ( + set('class', 'input-group-addon'), + checkbox + ( + set::name("stepType[$i]"), + set::text($lang->testcase->showAutoCase), + ) + ) + ) + ), + h::td + ( + textarea + ( + set::rows(1), + set::name("expects[$i]") + ) + ), + h::td + ( + set::class('center'), + btnGroup + ( + set::items(array( + array('icon' => 'plus'), + array('icon' => 'trash'), + array('icon' => 'move') + )) + ) + ) + ); + } + return h::table + ( + set::class('w-full'), + h::thead + ( + h::tr + ( + h::th($lang->testcase->stepID), + h::th($lang->testcase->stepDesc), + h::th($lang->testcase->stepExpect), + h::th($lang->actions) + ) + ), + h::tbody + ( + $stepsTR + ) + ); +} diff --git a/module/testcase/zen.php b/module/testcase/zen.php index e3855c1a75..da92a67ecb 100644 --- a/module/testcase/zen.php +++ b/module/testcase/zen.php @@ -49,5 +49,35 @@ class testcaseZen extends testcase $this->view->modulePath = $this->tree->getParents($case->module); $this->view->caseModule = empty($case->module) ? '' : $this->tree->getById($case->module); } + + /** + * 创建测试用例前检验表单数据是否正确。 + * check from data for create case. + * + * @param object $case + * @access protected + * @return bool + */ + protected function checkCreateFormData(object $case): bool + { + $steps = $case->steps; + $expects = $case->expects; + foreach($expects as $key => $value) + { + if(!empty($value) and empty($steps[$key])) dao::$errors['message']["steps$key"] = sprintf($this->lang->testcase->stepsEmpty, $key); + } + if(dao::isError()) return false; + + $param = ''; + if(!empty($case->lib)) $param = "lib={$case->lib}"; + if(!empty($case->product)) $param = "product={$case->product}"; + + $result = $this->loadModel('common')->removeDuplicate('case', $case, $param); + if($result and $result['stop']) + { + return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->duplicate, $this->lang->testcase->common), 'locate' => $this->createLink('testcase', 'view', "caseID={$result['duplicate']}"))); + } + return true; + } }