• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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