fix testsuite name bugs and improve some ui details
[bottlenecks.git] / test-scheduler / ui / src / components / testsuite.vue
1 <template>
2   <div class="wrapper wrapper-content animated fadeIn">
3     <div class="row" style="margin-bottom: 20px;">
4       <div class="col-md-12">
5         <ol class="breadcrumb" style="padding-left: 20px; font-size: 17px;">
6           <li>
7             <router-link to="/" >root</router-link>
8           </li>
9         </ol>
10       </div>
11     </div>
12     <div id="page-content" class="row">
13       <div class="col-lg-12">
14         <div class="ibox">
15             <div class="ibox-title">
16                 <h5 style="font-size:26px;margin-top: -3px;">Test Suite</h5>
17                 <div class="ibox-tools">
18                     <button class="btn btn-info btn-sm my-button-sm" type="button" v-on:click="runTestsuites()">Run</button>
19                     <button class="btn btn-success btn-sm my-button-sm" type="button" v-on:click="createSuite()">Create</button>
20                     <button class="btn btn-danger btn-sm my-button-sm" v-on:click="deleteSuites()" type="button">Delete</button>
21                     <a class="collapse-link">
22                         <i class="fa fa-chevron-up"></i>
23                     </a>
24                     <a class="fullscreen-link">
25                         <i class="fa fa-expand"></i>
26                     </a>
27                 </div>
28             </div>
29             <div class="ibox-content" style="text-align:center;">
30               <table class="my-table table table-bordered" cellspacing="0" cellpadding="0" style="text-align: center;">
31                 <thead>
32                   <tr>
33                     <td style="width:20px"><input type="checkbox" v-model="selectAll"> All</td>
34                     <td class="smallbox" style="with:250px;">TestSuite Name</td>
35                   </tr>
36                 </thead>
37                 <tbody>
38                     <tr v-for="testsuite in testsuites">
39                       <td><input style="width:20px" type="checkbox" v-model="selected" :value="testsuite.testsuite"> </td>
40                       <td class="smallbox" style="with:250px;"><router-link :to="{ path: '/testcase', query: { name: testsuite.testsuite }}" >{{testsuite.testsuite}}</router-link></td>
41                     </tr>
42                 </tbody>
43                 <tfoot id="create-box" style="display: none">
44                     <tr>
45                       <td style="width:20px"><input type="checkbox"> </td>
46                       <td class="smallbox" style="with:250px;"><input type="text" v-model="newSuite" @keydown.enter="addItem" ></td>
47                     </tr>
48                 </tfoot>
49               </table>
50             </div>
51         </div>
52       </div>
53     </div>
54     <hr />
55     <div class="row" v-show="runYet">
56       <div class="col-lg-12">
57           <div class="ibox">
58               <div class="ibox-title">
59                   <h5 style="font-size:26px;margin-top: -3px;">Workflow</h5>
60                   <div class="ibox-tools">
61                       <a class="collapse-link">
62                           <i class="fa fa-chevron-up"></i>
63                       </a>
64                       <a class="fullscreen-link">
65                           <i class="fa fa-expand"></i>
66                       </a>
67                   </div>
68               </div>
69               <div class="ibox-content" style="padding-top: 30px;">
70                 <div id="executing" class="row" style="padding: 0 30px 60px;">
71                   <div class="col-md-offset-2 col-md-8">
72                       <div class="table-responsive">
73                         <table class="table text-center" style="margin-top: 30px;">
74                           <thead>
75                             <tr>
76                               <th class="text-center">#</th>
77                               <th class="text-center">testcase</th>
78                               <th class="text-center">status</th>
79                               <th class="text-center">operation</th>
80                             </tr>
81                           </thead>
82                           <tbody>
83                             <tr v-for="testcase in casesInSuite">
84                               <td>{{ testcase.id }}</td>
85                               <td>{{ testcase.testcase }}</td>
86                               <td><span class="badge" v-bind:class="'badge-' + statusClass(testcase.status)">{{ testcase.status }}</span></td>
87                               <td>
88                               <div style="display: inline-block;min-width: 130px;">
89                                 <button class="btn btn-primary btn-outline btn-xs fadeIn" v-on:click="runTestcase()" v-show="testcase.status == 'failed'">rerun</button>
90                                 <button class="btn btn-primary btn-outline btn-xs fadeIn" v-on:click="runNextCase($event.target)" v-show="testcase.status == 'failed'">run next one</button>
91                               </div>
92                               </td>
93                             </tr>
94                           </tbody>
95                         </table>
96                       </div>
97                   </div>
98                 </div>
99                 <hr class="hr-line-solid">
100                 <div class="row" style="margin-top: 60px;">
101                   <wfresult v-bind:workflowId="workflowId" v-bind:wfloading='wfloading' v-bind:wfJson='wfJson' v-on:wfComplete="wfComplete = $event"></wfresult>
102                 </div>
103               </div>
104           </div>
105       </div>
106     </div>
107   </div>
108 </template>
109 <script>
110 import wfresult from './workflow_graph/wfresult.vue'
111 import showMessage from './message/showMessage.js'
112 export default {
113   name: 'testsuite',
114   data () {
115     return {
116       newSuite : '',
117       testsuites : '',
118       service_selected : '',
119       workflowId: '',
120       wfloading: false,
121       wfJson: '',
122       selected: [],
123       casesInSuite: [],
124       running: {
125         suiteName: "",
126         caseName: ""
127       },
128       curRunningId: 0,
129       wfComplete: false,
130       runYet: false
131     }
132   },
133   created: function() {
134     var self = this;
135     var msgTitle = "GET -- TESTSUITES";
136     var errorInfo = "Failed to get testsuite list.";
137     $.ajax({
138       url: this.global.SERVER_ADDR + "testsuite/list",
139       method:"GET",
140       data:{},
141       success:function (data) {
142         if(data['code'] == 200) {
143           self.testsuites = data['result'];
144         } else {
145           showMessage(data['code'], msgTitle, errorInfo, data['error']);
146         }
147       },
148       error: function(obj, status, msg) {
149         showMessage(status, msgTitle, errorInfo, msg);
150       }
151     });
152   },
153   computed: {
154     selectAll: {
155       get: function () {
156         return this.testsuites ? this.selected.length == this.testsuites.length : false;
157       },
158       set: function (value) {
159         var selected = [];
160         if (value) {
161           this.testsuites.forEach(function (story) {
162             selected.push(story.testsuite);
163           });
164         }
165         this.selected = selected;
166       }
167     }
168 },
169   methods:{
170     createSuite: function () {
171       var cbox = document.getElementById("create-box");
172       cbox.style.display = "table-footer-group";
173     },
174     addItem: function () {
175       var self = this;
176       const suiteName = self.newSuite.trim();
177       if(suiteName)
178       {
179         var msgTitle = "CREATE -- TESTSUITE";
180         $.ajax({
181           url: this.global.SERVER_ADDR + "testsuite/new",
182           method:"POST",
183           data:{
184             suiteName:suiteName
185           },
186           success:function(data){
187             if(data['code'] == 200){
188               self.testsuites.push({
189                 id: self.testsuites.length + 1 ,
190                 testsuite: suiteName,
191               });
192               showMessage(data['code'], msgTitle, "Create <strong>" + suiteName + "</strong> succesfully!");
193             } else {
194               showMessage(data['code'], msgTitle, "Failed to create <strong>" + suiteName + "</strong>!", data['error']);
195             }
196           },
197           error: function(obj, status, msg) {
198             showMessage(status, msgTitle, "Failed to create <strong>" + suiteName + "</strong>!", msg);
199           }
200         })
201       }
202       var cbox = document.getElementById("create-box");
203       cbox.style.display = "none";
204       this.newSuite = '';
205     },
206     deleteSuites:function () {
207       var self = this;
208       var msgTitle = "DELETE -- TESTSUITE";
209       var deleteArr = self.selected.slice(0);
210       self.testsuites = self.testsuites.filter(item => {
211           for(var i in deleteArr) {
212             if(item.testsuite == deleteArr[i]) {
213               return false;
214             }
215           }
216           return true;
217       });
218       self.selected = [];
219       for(var i in deleteArr)
220       {
221         $.ajax({
222           url: this.global.SERVER_ADDR + "testsuite/delete",
223           method:"POST",
224           data:{
225             suiteName: deleteArr[i]
226           },
227           success:function (data) {
228             if(data['code'] == 200){
229               showMessage(data['code'], msgTitle, "Delete <strong>" + deleteArr[i] + "</strong> succesfully!");
230             } else {
231               showMessage(data['code'], msgTitle, "Failed to delete <strong>" + deleteArr[i] + "</strong>!", data['error']);
232             }
233           },
234           error: function(obj, status, msg) {
235             showMessage(status, msgTitle, "Failed to delete <strong>" + deleteArr[i] + "</strong>!", msg);
236           }
237         });
238       }
239     },
240     runTestsuites: function() {
241       var self = this;
242       var msgTitle = "RUN -- TESTSUITE";
243       if(!self.runYet) {
244         self.runYet = true;
245       }
246       if(self.selected.length == 0) {
247         showMessage("warning", msgTitle, "please select one!");
248         return;
249       } else if(self.selected.length != 1) {
250         showMessage("warning", msgTitle, "sorry, one suite at a time!");
251         return;
252       }
253       self.running.suiteName = self.selected[0];
254       $.ajax({
255         url: this.global.SERVER_ADDR + "testsuite/content",
256         method: "GET",
257         data: {
258           "suiteName": self.running.suiteName
259         },
260         success: function(data) {
261           if (data['code'] == 200) {
262             var caseList = data['result'];
263             if(caseList.length == 0) {
264               showMessage("info", msgTitle, "<strong>" + self.running.suiteName + "</strong> is empty!");
265               return;
266             }
267             for(var i=0; i < caseList.length; i++) {
268               caseList[i]['status'] = "waiting";
269             }
270             self.casesInSuite = caseList;
271             showMessage(data['code'], msgTitle, "Start to run <strong>" + self.running.suiteName + "</strong>");
272             self.runTestcase();
273           } else {
274             showMessage(data['code'], msgTitle, "Failed to run <strong>" + self.running.suiteName + "</strong>", data['error']);
275           }
276         },
277         error: function(obj, status, msg) {
278           showMessage(status, msgTitle, "Failed to run <strong>" + self.running.suiteName + "</strong>", msg);
279         }
280       });
281     },
282     runTestcase: function() {
283         var self = this;
284         var msgTitle = "RUN -- TESTCASE";
285         if (self.curRunningId == self.casesInSuite.length) {
286           self.curRunningId = 0;
287           return;
288         }
289         self.wfComplete = false;
290         var i = self.curRunningId;
291         self.casesInSuite[i]['status'] = "running";
292         self.running.caseName = self.casesInSuite[i]['testcase'];
293         $.ajax({
294           url: self.global.SERVER_ADDR + "execute/testcase",
295           method: "POST",
296           data: {
297               "suiteName": self.running.suiteName,
298               "caseName": self.running.caseName
299           },
300           beforeSend: function(XHR) {
301               self.wfloading = true;
302           },
303           success: function(data) {
304               if(data['code'] == 200) {
305                 self.workflowId = data['result']['workflowId'];
306                 $.ajax({
307                     url: self.global.SERVER_ADDR + "story-content",
308                     method: "GET",
309                     data: {
310                         "service":  self.running.suiteName,
311                         "story": self.running.caseName
312                     },
313                     success: function(data) {
314                         if(data['code'] == 200) {
315                             self.wfJson = data['result']['content'];
316                         } else {
317                             showMessage(data['code'], msgTitle, "workflow.json get failed!");
318                         }
319                     },
320                     error: function(obj, status, msg) {
321                       showMessage(status, msgTitle, msg);
322                     }
323                 });
324               } else {
325                 var i = self.curRunningId;
326                 self.casesInSuite[i]['status'] = "failed";
327                 self.wfloading = false;
328                 showMessage(data['code'], msgTitle, "Failed to run <strong>" + self.running.caseName + "</strong>", data['error']);
329               }
330           },
331           error: function(obj, status, msg) {
332             var i = self.curRunningId;
333             self.casesInSuite[i]['status'] = "failed";
334             self.wfloading = false;
335             showMessage(status, msgTitle, "Failed to run <strong>" + self.running.caseName + "</strong>", msg);
336           }
337         });
338     },
339     statusClass: function(status) {
340       if(status == "waiting") {
341         return "success";
342       }
343       if(status == "running") {
344         return "warning";
345       }
346       if(status == "pass") {
347         return "primary";
348       }
349       if(status == "failed") {
350         return "danger";
351       }
352     },
353     runNextCase: function(obj) {
354       $(obj).parent().css({"display": "none"});
355       var i = this.curRunningId++;
356       this.runTestcase();
357     }
358   },
359   watch: {
360     wfComplete: function(val) {
361       if(val == false) return;
362       this.wfloading = false;
363       var i = this.curRunningId++;
364       this.casesInSuite[i]['status'] = "pass";
365       // run the next testcase.
366       this.runTestcase();
367     }
368   },
369   components: {
370     wfresult
371   }
372 }
373 </script>