1/* 2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import SysTestKit from "./module/kit/SysTestKit"; 17 18class AssertException extends Error { 19 constructor(message) { 20 super(); 21 this.name = "AssertException"; 22 this.message = message; 23 } 24} 25 26function getFuncWithArgsZero(func, timeout, isStressTest) { 27 return new Promise(async (resolve, reject) => { 28 let timer = null; 29 if (!isStressTest) { 30 timer = setTimeout(() => { 31 reject(new Error('execute timeout ' + timeout + 'ms')); 32 }, timeout); 33 } 34 try { 35 await func(); 36 } catch (err) { 37 reject(err); 38 } 39 timer !== null ? clearTimeout(timer) : null; 40 resolve(); 41 }); 42} 43 44function getFuncWithArgsOne(func, timeout, isStressTest) { 45 return new Promise(async (resolve, reject) => { 46 let timer = null; 47 if (!isStressTest) { 48 timer = setTimeout(() => { 49 reject(new Error('execute timeout ' + timeout + 'ms')); 50 }, timeout);; 51 } 52 53 function done() { 54 timer !== null ? clearTimeout(timer) : null; 55 resolve(); 56 } 57 58 try { 59 await func(done); 60 } catch (err) { 61 timer !== null ? clearTimeout(timer) : null; 62 reject(err); 63 } 64 }); 65} 66 67function getFuncWithArgsTwo(func, timeout, paramItem, isStressTest) { 68 return new Promise(async (resolve, reject) => { 69 let timer = null; 70 if (!isStressTest) { 71 timer = setTimeout(() => { 72 reject(new Error('execute timeout ' + timeout + 'ms')); 73 }, timeout); 74 } 75 76 function done() { 77 timer !== null ? clearTimeout(timer) : null; 78 resolve(); 79 } 80 81 try { 82 await func(done, paramItem); 83 } catch (err) { 84 timer !== null ? clearTimeout(timer) : null; 85 reject(err); 86 } 87 }); 88} 89 90function processFunc(coreContext, func) { 91 let argNames = ((func || '').toString() 92 .replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '') 93 .match(/^(function)?\s*[^\(]*\(\s*([^\)]*)\)/m) || ['', '', ''])[2] 94 .split(',') // split parameters 95 .map(item => item.replace(/^\s*(_?)(.+?)\1\s*$/, name => name.split('=')[0].trim())) 96 .filter(String); 97 let funcLen = func.length; 98 let processedFunc; 99 const config = coreContext.getDefaultService('config'); 100 config.setSupportAsync(true); 101 const timeout = + (config.timeout === undefined ? 5000 : config.timeout); 102 const isStressTest = (coreContext.getServices('dataDriver') !== undefined || config.getStress() > 1); 103 switch (funcLen) { 104 case 0: { 105 processedFunc = function () { 106 return getFuncWithArgsZero(func, timeout, isStressTest); 107 }; 108 break; 109 } 110 case 1: { 111 if (argNames[0] === 'data') { 112 processedFunc = function (paramItem) { 113 func(paramItem); 114 }; 115 } else { 116 processedFunc = function () { 117 return getFuncWithArgsOne(func, timeout, isStressTest); 118 }; 119 } 120 break; 121 } 122 default: { 123 processedFunc = function (paramItem) { 124 return getFuncWithArgsTwo(func, timeout, paramItem, isStressTest); 125 }; 126 break; 127 } 128 } 129 return processedFunc; 130} 131 132function secureRandomNumber() { 133 return crypto.randomBytes(8).readUInt32LE() / 0xffffffff; 134} 135 136class SuiteService { 137 constructor(attr) { 138 this.id = attr.id; 139 this.rootSuite = new SuiteService.Suite({}); 140 this.currentRunningSuite = this.rootSuite; 141 this.suitesStack = [this.rootSuite]; 142 } 143 144 describe(desc, func) { 145 const configService = this.coreContext.getDefaultService('config'); 146 if (configService.filterSuite(desc)) { 147 console.info('filter suite :' + desc); 148 return; 149 } 150 const suite = new SuiteService.Suite({description: desc}); 151 if (typeof this.coreContext.getServices('dataDriver') !== 'undefined' && configService['dryRun'] !== 'true') { 152 let suiteStress = this.coreContext.getServices('dataDriver').dataDriver.getSuiteStress(desc); 153 for (let i = 1; i < suiteStress; i++) { 154 this.currentRunningSuite.childSuites.push(suite); 155 } 156 } 157 this.currentRunningSuite.childSuites.push(suite); 158 this.currentRunningSuite = suite; 159 this.suitesStack.push(suite); 160 func.call(); 161 let childSuite = this.suitesStack.pop(); 162 if (this.suitesStack.length === 0) { 163 this.currentRunningSuite = childSuite; 164 this.suitesStack.push(childSuite); 165 } 166 if (this.suitesStack.length > 1) { 167 this.currentRunningSuite = this.suitesStack.pop(); 168 } else { 169 this.currentRunningSuite = this.suitesStack.pop(); 170 this.suitesStack.push(this.currentRunningSuite); 171 } 172 } 173 174 beforeAll(func) { 175 this.currentRunningSuite.beforeAll.push(processFunc(this.coreContext, func)); 176 } 177 178 beforeEach(func) { 179 this.currentRunningSuite.beforeEach.push(processFunc(this.coreContext, func)); 180 } 181 182 afterAll(func) { 183 this.currentRunningSuite.afterAll.push(processFunc(this.coreContext, func)); 184 } 185 186 afterEach(func) { 187 this.currentRunningSuite.afterEach.push(processFunc(this.coreContext, func)); 188 } 189 190 getCurrentRunningSuite() { 191 return this.currentRunningSuite; 192 } 193 194 setCurrentRunningSuite(suite) { 195 this.currentRunningSuite = suite; 196 } 197 198 traversalResults(suite, obj, breakOnError) { 199 if (suite.childSuites.length === 0 && suite.specs.length === 0) { 200 return obj; 201 } 202 if (suite.specs.length > 0) { 203 for (const itItem of suite.specs) { 204 obj.total++; 205 if (breakOnError && (obj.error > 0 || obj.failure > 0)) { // breakOnError模式 206 continue; 207 } 208 if (itItem.error) { 209 obj.error++; 210 } else if (itItem.result.failExpects.length > 0) { 211 obj.failure++; 212 } else if (itItem.result.pass === true) { 213 obj.pass++; 214 } 215 } 216 } 217 218 obj.duration += suite.duration; 219 220 if (suite.childSuites.length > 0) { 221 for (const suiteItem of suite.childSuites) { 222 this.traversalResults(suiteItem, obj, breakOnError); 223 } 224 } 225 } 226 227 getSummary() { 228 let suiteService = this.coreContext.getDefaultService('suite'); 229 let rootSuite = suiteService.rootSuite; 230 const specService = this.coreContext.getDefaultService('spec'); 231 const configService = this.coreContext.getDefaultService('config'); 232 let breakOnError = configService.isBreakOnError(); 233 let isError = specService.getStatus(); 234 let isBreaKOnError = breakOnError && isError; 235 let obj = {total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0}; 236 for (const suiteItem of rootSuite.childSuites) { 237 this.traversalResults(suiteItem, obj, isBreaKOnError); 238 } 239 obj.ignore = obj.total - obj.pass - obj.failure - obj.error; 240 return obj; 241 } 242 243 init(coreContext) { 244 this.coreContext = coreContext; 245 } 246 247 traversalSuites(suite, obj, configService) { 248 if (suite.childSuites.length === 0 && suite.specs.length === 0) { 249 return []; 250 } 251 if (suite.specs.length > 0) { 252 let itArray = []; 253 for (const itItem of suite['specs']) { 254 if (!configService.filterDesc(suite.description, itItem.description, itItem.fi, null)) { 255 itArray.push({'itName': itItem.description}); 256 } 257 } 258 obj[suite.description] = itArray; 259 } 260 261 if (suite.childSuites.length > 0) { 262 let suiteArray = []; 263 for (const suiteItem of suite.childSuites) { 264 let suiteObj = {}; 265 this.traversalSuites(suiteItem, suiteObj, configService); 266 if (!configService.filterSuite(suiteItem.description)) { 267 suiteArray.push(suiteObj); 268 } 269 } 270 obj.suites = suiteArray; 271 } 272 } 273 274 async dryRun(abilityDelegator) { 275 const configService = this.coreContext.getDefaultService('config'); 276 let testSuitesObj = {}; 277 let suitesArray = []; 278 for (const suiteItem of this.rootSuite.childSuites) { 279 let obj = {}; 280 this.traversalSuites(suiteItem, obj, configService); 281 if (!configService.filterSuite(suiteItem.description)) { 282 suitesArray.push(obj); 283 } 284 } 285 testSuitesObj['suites'] = suitesArray; 286 287 let strJson = JSON.stringify(testSuitesObj); 288 let strLen = strJson.length; 289 let maxLen = 500; 290 let maxCount = Math.floor(strLen / maxLen); 291 292 for (let count = 0; count <= maxCount; count++) { 293 await SysTestKit.print(strJson.substring(count * maxLen, (count + 1) * maxLen)); 294 } 295 console.info('dryRun print success'); 296 abilityDelegator.finishTest('dry run finished!!!', 0, () => { }); 297 } 298 299 execute() { 300 const configService = this.coreContext.getDefaultService('config'); 301 if (configService.filterValid.length !== 0) { 302 this.coreContext.fireEvents('task', 'incorrectFormat'); 303 return; 304 } 305 306 if (configService.isRandom() && this.rootSuite.childSuites.length > 0) { 307 this.rootSuite.childSuites.sort(function () { 308 return Math.random().toFixed(1) > 0.5 ? -1 : 1; 309 }); 310 this.currentRunningSuite = this.rootSuite.childSuites[0]; 311 } 312 313 if (configService.isSupportAsync()) { 314 let asyncExecute = async () => { 315 await this.coreContext.fireEvents('task', 'taskStart'); 316 await this.rootSuite.asyncRun(this.coreContext); 317 }; 318 asyncExecute().then(async () => { 319 await this.coreContext.fireEvents('task', 'taskDone'); 320 }); 321 } else { 322 this.coreContext.fireEvents('task', 'taskStart'); 323 this.rootSuite.run(this.coreContext); 324 this.coreContext.fireEvents('task', 'taskDone'); 325 } 326 } 327 328 apis() { 329 const _this = this; 330 return { 331 describe: function (desc, func) { 332 return _this.describe(desc, func); 333 }, 334 beforeAll: function (func) { 335 return _this.beforeAll(func); 336 }, 337 beforeEach: function (func) { 338 return _this.beforeEach(func); 339 }, 340 afterAll: function (func) { 341 return _this.afterAll(func); 342 }, 343 afterEach: function (func) { 344 return _this.afterEach(func); 345 } 346 }; 347 } 348} 349 350SuiteService.Suite = class { 351 constructor(attrs) { 352 this.description = attrs.description || ''; 353 this.childSuites = []; 354 this.specs = []; 355 this.beforeAll = []; 356 this.afterAll = []; 357 this.beforeEach = []; 358 this.afterEach = []; 359 this.duration = 0; 360 } 361 362 pushSpec(spec) { 363 this.specs.push(spec); 364 } 365 366 removeSpec(desc) { 367 this.specs = this.specs.filter((item, index) => { 368 return item.description !== desc; 369 }); 370 } 371 372 getSpecsNum() { 373 return this.specs.length; 374 } 375 376 isRun(coreContext) { 377 const configService = coreContext.getDefaultService('config'); 378 const suiteService = coreContext.getDefaultService('suite'); 379 const specService = coreContext.getDefaultService('spec'); 380 let breakOnError = configService.isBreakOnError(); 381 let isError = specService.getStatus(); 382 return breakOnError && isError; 383 } 384 385 run(coreContext) { 386 const suiteService = coreContext.getDefaultService('suite'); 387 suiteService.setCurrentRunningSuite(this); 388 if (this.description !== '') { 389 coreContext.fireEvents('suite', 'suiteStart', this); 390 } 391 this.runHookFunc('beforeAll'); 392 if (this.specs.length > 0) { 393 const configService = coreContext.getDefaultService('config'); 394 if (configService.isRandom()) { 395 this.specs.sort(function () { 396 return Math.random().toFixed(1) > 0.5 ? -1 : 1; 397 }); 398 } 399 for (let spec in this.specs) { 400 let isBreakOnError = this.isRun(coreContext); 401 if (isBreakOnError) { 402 break; 403 } 404 this.runHookFunc('beforeEach'); 405 spec.run(coreContext); 406 this.runHookFunc('afterEach'); 407 } 408 } 409 if (this.childSuites.length > 0) { 410 for (let suite in this.childSuites) { 411 let isBreakOnError = this.isRun(coreContext); 412 if (isBreakOnError) { 413 break; 414 } 415 suite.run(coreContext); 416 suiteService.setCurrentRunningSuite(suite); 417 } 418 } 419 this.runHookFunc('afterAll'); 420 if (this.description !== '') { 421 coreContext.fireEvents('suite', 'suiteDone'); 422 } 423 } 424 425 async asyncRun(coreContext) { 426 const suiteService = coreContext.getDefaultService('suite'); 427 suiteService.setCurrentRunningSuite(this); 428 suiteService.suitesStack.push(this); 429 if (this.description !== '') { 430 await coreContext.fireEvents('suite', 'suiteStart', this); 431 } 432 await this.runAsyncHookFunc('beforeAll'); 433 if (this.specs.length > 0) { 434 const configService = coreContext.getDefaultService('config'); 435 if (configService.isRandom()) { 436 this.specs.sort(function () { 437 return Math.random().toFixed(1) > 0.5 ? -1 : 1; 438 }); 439 } 440 for (let i = 0; i < this.specs.length; i++) { 441 // 遇错即停模式,发现用例有问题,直接返回,不在执行后面的it 442 let isBreakOnError = this.isRun(coreContext); 443 if (isBreakOnError) { 444 console.log("break description :" + this.description); 445 break; 446 } 447 await this.runAsyncHookFunc('beforeEach'); 448 await this.specs[i].asyncRun(coreContext); 449 await this.runAsyncHookFunc('afterEach'); 450 } 451 } 452 453 if (this.childSuites.length > 0) { 454 for (let i = 0; i < this.childSuites.length; i++) { 455 // 遇错即停模式, 发现用例有问题,直接返回,不在执行后面的description 456 let isBreakOnError = this.isRun(coreContext); 457 if (isBreakOnError) { 458 console.log("break description :" + this.description); 459 break; 460 } 461 await this.childSuites[i].asyncRun(coreContext); 462 } 463 } 464 465 await this.runAsyncHookFunc('afterAll'); 466 if (this.description !== '') { 467 await coreContext.fireEvents('suite', 'suiteDone'); 468 let childSuite = suiteService.suitesStack.pop(); 469 if (suiteService.suitesStack.length === 0) { 470 suiteService.suitesStack.push(childSuite); 471 } 472 if (suiteService.suitesStack.length > 1) { 473 suiteService.setCurrentRunningSuite(suiteService.suitesStack.pop()); 474 } else { 475 let currentRunningSuite = suiteService.suitesStack.pop(); 476 suiteService.setCurrentRunningSuite(currentRunningSuite); 477 suiteService.suitesStack.push(currentRunningSuite); 478 } 479 } 480 } 481 482 runHookFunc(hookName) { 483 if (this[hookName] && this[hookName].length > 0) { 484 this[hookName].forEach(func => { 485 try { 486 func(); 487 } catch (e) { 488 console.error(e); 489 } 490 }); 491 } 492 } 493 494 runAsyncHookFunc(hookName) { 495 if (this[hookName] && this[hookName].length > 0) { 496 return new Promise(async resolve => { 497 for (let i = 0; i < this[hookName].length; i++) { 498 try { 499 await this[hookName][i](); 500 } catch (e) { 501 console.error(e); 502 } 503 } 504 resolve(); 505 }); 506 } 507 } 508}; 509 510class SpecService { 511 constructor(attr) { 512 this.id = attr.id; 513 this.totalTest = 0; 514 this.hasError = false; 515 } 516 517 init(coreContext) { 518 this.coreContext = coreContext; 519 } 520 521 setCurrentRunningSpec(spec) { 522 this.currentRunningSpec = spec; 523 } 524 525 setStatus(obj) { 526 this.hasError = obj; 527 } 528 529 getStatus() { 530 return this.hasError; 531 } 532 533 getTestTotal() { 534 return this.totalTest; 535 } 536 537 getCurrentRunningSpec() { 538 return this.currentRunningSpec; 539 } 540 541 it(desc, filter, func) { 542 const configService = this.coreContext.getDefaultService('config'); 543 const currentSuiteName = this.coreContext.getDefaultService('suite').getCurrentRunningSuite().description; 544 if (configService.filterDesc(currentSuiteName, desc, filter, this.coreContext)) { 545 console.info('filter it :' + desc); 546 } else { 547 let processedFunc = processFunc(this.coreContext, func); 548 const spec = new SpecService.Spec({description: desc, fi: filter, fn: processedFunc}); 549 const suiteService = this.coreContext.getDefaultService('suite'); 550 if (typeof this.coreContext.getServices('dataDriver') !== 'undefined' && configService['dryRun'] !== 'true') { 551 let specStress = this.coreContext.getServices('dataDriver').dataDriver.getSpecStress(desc); 552 for (let i = 1; i < specStress; i++) { 553 this.totalTest++; 554 suiteService.getCurrentRunningSuite().pushSpec(spec); 555 } 556 } 557 558 // dryRun 状态下不统计压力测试重复数据 559 if (configService['dryRun'] !== 'true') { 560 let stress = configService.getStress(); // 命令配置压力测试 561 console.info('stress length :' + stress); 562 for (let i = 1; i < stress; i++) { 563 this.totalTest++; 564 suiteService.getCurrentRunningSuite().pushSpec(spec); 565 } 566 } 567 this.totalTest++; 568 suiteService.getCurrentRunningSuite().pushSpec(spec); 569 } 570 } 571 572 apis() { 573 const _this = this; 574 return { 575 it: function (desc, filter, func) { 576 return _this.it(desc, filter, func); 577 } 578 }; 579 } 580} 581 582SpecService.Spec = class { 583 constructor(attrs) { 584 this.description = attrs.description || ''; 585 this.fi = attrs.fi; 586 this.fn = attrs.fn || function () { 587 }; 588 this.result = { 589 failExpects: [], 590 passExpects: [] 591 }; 592 this.error = undefined; 593 this.duration = 0; 594 this.startTime = 0; 595 this.isExecuted = false; // 当前用例是否执行 596 } 597 598 setResult(coreContext) { 599 const specService = coreContext.getDefaultService('spec'); 600 if (this.result.failExpects.length > 0) { 601 this.result.pass = false; 602 specService.setStatus(true); 603 } else { 604 this.result.pass = true; 605 } 606 console.info('testcase ' + this.description + ' result:' + this.result.pass); 607 } 608 609 run(coreContext) { 610 const specService = coreContext.getDefaultService('spec'); 611 specService.setCurrentRunningSpec(this); 612 coreContext.fireEvents('spec', 'specStart', this); 613 this.isExecuted = true; 614 try { 615 let dataDriver = coreContext.getServices('dataDriver'); 616 if (typeof dataDriver === 'undefined') { 617 this.fn(); 618 } else { 619 let suiteParams = dataDriver.dataDriver.getSuiteParams(); 620 let specParams = dataDriver.dataDriver.getSpecParams(); 621 console.info('[suite params] ' + JSON.stringify(suiteParams)); 622 console.info('[spec params] ' + JSON.stringify(specParams)); 623 if (this.fn.length === 0) { 624 this.fn(); 625 } else if (specParams.length === 0) { 626 this.fn(suiteParams); 627 } else { 628 specParams.forEach(paramItem => this.fn(Object.assign({}, paramItem, suiteParams))); 629 } 630 } 631 this.setResult(coreContext); 632 } catch (e) { 633 this.error = e; 634 specService.setStatus(true); 635 } 636 coreContext.fireEvents('spec', 'specDone', this); 637 } 638 639 async asyncRun(coreContext) { 640 const specService = coreContext.getDefaultService('spec'); 641 specService.setCurrentRunningSpec(this); 642 643 await coreContext.fireEvents('spec', 'specStart', this); 644 try { 645 let dataDriver = coreContext.getServices('dataDriver'); 646 if (typeof dataDriver === 'undefined') { 647 await this.fn(); 648 this.setResult(coreContext); 649 } else { 650 let suiteParams = dataDriver.dataDriver.getSuiteParams(); 651 let specParams = dataDriver.dataDriver.getSpecParams(); 652 console.info('[suite params] ' + JSON.stringify(suiteParams)); 653 console.info('[spec params] ' + JSON.stringify(specParams)); 654 if (this.fn.length === 0) { 655 await this.fn(); 656 this.setResult(coreContext); 657 } else if (specParams.length === 0) { 658 await this.fn(suiteParams); 659 this.setResult(coreContext); 660 } else { 661 for (const paramItem of specParams) { 662 await this.fn(Object.assign({}, paramItem, suiteParams)); 663 this.setResult(coreContext); 664 } 665 } 666 } 667 } catch (e) { 668 if (e instanceof AssertException) { 669 this.fail = e; 670 specService.setStatus(true); 671 } else { 672 this.error = e; 673 specService.setStatus(true); 674 } 675 } 676 this.isExecuted = true; 677 await coreContext.fireEvents('spec', 'specDone', this); 678 } 679 680 filterCheck(coreContext) { 681 const specService = coreContext.getDefaultService('spec'); 682 specService.setCurrentRunningSpec(this); 683 return true; 684 } 685 686 addExpectationResult(expectResult) { 687 if (this.result.failExpects.length === 0) { 688 this.result.failExpects.push(expectResult); 689 } 690 throw new AssertException(expectResult.message); 691 } 692}; 693 694class ExpectService { 695 constructor(attr) { 696 this.id = attr.id; 697 this.matchers = {}; 698 } 699 700 expect(actualValue) { 701 return this.wrapMatchers(actualValue); 702 } 703 704 init(coreContext) { 705 this.coreContext = coreContext; 706 this.addMatchers(this.basicMatchers()); 707 } 708 709 addMatchers(matchers) { 710 for (const matcherName in matchers) { 711 if (Object.prototype.hasOwnProperty.call(matchers, matcherName)) { 712 this.matchers[matcherName] = matchers[matcherName]; 713 } 714 } 715 } 716 717 basicMatchers() { 718 return { 719 assertTrue: function (actualValue) { 720 return { 721 pass: (actualValue) === true, 722 message: 'expect true, actualValue is ' + actualValue 723 }; 724 }, 725 assertEqual: function (actualValue, args) { 726 return { 727 pass: (actualValue) === args[0], 728 expectValue: args[0], 729 message: 'expect ' + actualValue + ' equals ' + args[0] 730 }; 731 }, 732 assertThrow: function (actual, args) { 733 const result = { 734 pass: false 735 }; 736 if (typeof actual !== 'function') { 737 result.message = 'toThrow\'s Actual should be a Function'; 738 } else { 739 let hasThrow = false; 740 let throwError; 741 try { 742 actual(); 743 } catch (e) { 744 hasThrow = true; 745 throwError = e; 746 } 747 if (!hasThrow) { 748 result.message = 'function did not throw an exception'; 749 } else if (throwError && throwError.message === args[0]) { 750 result.pass = true; 751 } else { 752 result.message = `expect to throw ${args[0]} , actual throw ${throwError.message}`; 753 } 754 } 755 return result; 756 } 757 }; 758 } 759 760 wrapMatchers(actualValue) { 761 const _this = this; 762 const wrappedMatchers = { 763 // 翻转标识 764 isNot: false, 765 766 // 翻转方法 767 not: function () { 768 this.isNot = true; 769 return this; 770 } 771 }; 772 const specService = _this.coreContext.getDefaultService('spec'); 773 const currentRunningSpec = specService.getCurrentRunningSpec(); 774 for (const matcherName in this.matchers) { 775 let result = Object.prototype.hasOwnProperty.call(this.matchers, matcherName); 776 if (!result) { 777 continue; 778 } 779 if (matcherName.search('assertPromise') == 0) { 780 wrappedMatchers[matcherName] = async function () { 781 await _this.matchers[matcherName](actualValue, arguments).then(function (result) { 782 if (wrappedMatchers.isNot) { 783 result.pass = !result.pass; 784 } 785 result.actualValue = actualValue; 786 result.checkFunc = matcherName; 787 if (!result.pass) { 788 currentRunningSpec.addExpectationResult(result); 789 } 790 }); 791 }; 792 } else { 793 wrappedMatchers[matcherName] = function () { 794 const result = _this.matchers[matcherName](actualValue, arguments); 795 if (wrappedMatchers.isNot) { 796 result.pass = !result.pass; 797 } 798 result.actualValue = actualValue; 799 result.checkFunc = matcherName; 800 if (!result.pass) { 801 currentRunningSpec.addExpectationResult(result); 802 } 803 }; 804 } 805 } 806 return wrappedMatchers; 807 } 808 809 apis() { 810 const _this = this; 811 return { 812 expect: function (actualValue) { 813 return _this.expect(actualValue); 814 } 815 }; 816 } 817} 818 819class ReportService { 820 constructor(attr) { 821 this.id = attr.id; 822 } 823 824 init(coreContext) { 825 this.coreContext = coreContext; 826 this.specService = this.coreContext.getDefaultService('spec'); 827 this.suiteService = this.coreContext.getDefaultService('suite'); 828 this.duration = 0; 829 } 830 831 taskStart() { 832 console.info('[start] start run suites'); 833 } 834 835 async suiteStart() { 836 console.info('[suite start]' + this.suiteService.getCurrentRunningSuite().description); 837 } 838 839 async specStart() { 840 console.info('start running case \'' + this.specService.currentRunningSpec.description + '\''); 841 this.index = this.index + 1; 842 let spec = this.specService.currentRunningSpec; 843 spec.startTime = await SysTestKit.getRealTime(); 844 } 845 846 async specDone() { 847 let msg = ''; 848 let spec = this.specService.currentRunningSpec; 849 let suite = this.suiteService.currentRunningSuite; 850 spec.duration = await SysTestKit.getRealTime() - spec.startTime; 851 suite.duration += spec.duration; 852 if (spec.error) { 853 this.formatPrint('error', spec.description + ' ; consuming ' + spec.duration + 'ms'); 854 this.formatPrint('errorDetail', spec.error); 855 } else if (spec.result) { 856 if (spec.result.failExpects.length > 0) { 857 this.formatPrint('fail', spec.description + ' ; consuming ' + spec.duration + 'ms'); 858 spec.result.failExpects.forEach(failExpect => { 859 msg = failExpect.message || ('expect ' + failExpect.actualValue + ' ' 860 + failExpect.checkFunc + ' ' + (failExpect.expectValue)); 861 this.formatPrint('failDetail', msg); 862 }); 863 } else { 864 this.formatPrint('pass', spec.description + ' ; consuming ' + spec.duration + 'ms'); 865 } 866 } 867 this.formatPrint(this.specService.currentRunningSpec.error, msg); 868 } 869 870 suiteDone() { 871 let suite = this.suiteService.currentRunningSuite; 872 console.info(`[suite end] ${suite.description} consuming ${suite.duration} ms`); 873 } 874 875 taskDone() { 876 let msg = ''; 877 let summary = this.suiteService.getSummary(); 878 msg = 'total cases:' + summary.total + ';failure ' + summary.failure + ',' + 'error ' + summary.error; 879 msg += ',pass ' + summary.pass + '; consuming ' + summary.duration + 'ms'; 880 console.info(msg); 881 console.info('[end] run suites end'); 882 } 883 884 incorrectFormat() { 885 if (this.coreContext.getDefaultService('config').filterValid.length !== 0) { 886 this.coreContext.getDefaultService('config').filterValid.forEach(function (item) { 887 console.info('this param ' + item + ' is invalid'); 888 }); 889 } 890 } 891 892 formatPrint(type, msg) { 893 switch (type) { 894 case 'pass': 895 console.info('[pass]' + msg); 896 break; 897 case 'fail': 898 console.info('[fail]' + msg); 899 break; 900 case 'failDetail': 901 console.info('[failDetail]' + msg); 902 break; 903 case 'error': 904 console.info('[error]' + msg); 905 break; 906 case 'errorDetail': 907 console.info('[errorDetail]' + msg); 908 break; 909 } 910 } 911 912 sleep(numberMillis) { 913 var now = new Date(); 914 var exitTime = now.getTime() + numberMillis; 915 while (true) { 916 now = new Date(); 917 if (now.getTime() > exitTime) { 918 return; 919 } 920 } 921 } 922} 923 924export { 925 SuiteService, 926 SpecService, 927 ExpectService, 928 ReportService 929}; 930