feat: 运行

This commit is contained in:
wangzhongjie 2024-02-21 13:15:42 +08:00
parent ed236df1d6
commit be472470ff
59 changed files with 4621 additions and 46 deletions

View File

@ -4,13 +4,13 @@
{
"name": "default",
"material": {
"certpath": "C:\\Users\\surenjun\\.ohos\\config\\openharmony\\auto_ohos_default_end2_bak_com.oh.dts.cer",
"storePassword": "0000001BBCF008AF436022E84525958DDA30DAACBAE95FB89880984155936D5A2B2211EBFC642FCC2C063B",
"certpath": "/Users/wangzhongjie/.ohos/config/openharmony/auto_ohos_default_subject-two_com.oh.dts.cer",
"storePassword": "0000001A3E7D97C4BC5819BCBC0470AB1397AAD09AC6E70069CFC6FD7D21A58A50AA6EE3FEBCDA027D71",
"keyAlias": "debugKey",
"keyPassword": "0000001B43018ED537D1DAF50E0FBEDF8E721D4B33B58ED0429751E6224D301D25C6BB44B66F90B57FFDEF",
"profile": "C:\\Users\\surenjun\\.ohos\\config\\openharmony\\auto_ohos_default_end2_bak_com.oh.dts.p7b",
"keyPassword": "0000001A764ACBDC861BE169BE8B85E333F52659116CD5B8F12254C0F8F893E26884787B99199D49B10C",
"profile": "/Users/wangzhongjie/.ohos/config/openharmony/auto_ohos_default_subject-two_com.oh.dts.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "C:\\Users\\surenjun\\.ohos\\config\\openharmony\\auto_ohos_default_end2_bak_com.oh.dts.p12"
"storeFile": "/Users/wangzhongjie/.ohos/config/openharmony/auto_ohos_default_subject-two_com.oh.dts.p12"
}
}
],

View File

@ -0,0 +1,13 @@
{
"lockfileVersion": 1,
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {
"@ohos/hypium@1.0.6": "@ohos/hypium@1.0.6"
},
"packages": {
"@ohos/hypium@1.0.6": {
"resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.6.tgz",
"integrity": "sha512-bb3DWeWhYrFqj9mPFV3yZQpkm36kbcK+YYaeY9g292QKSjOdmhEIQR2ULPvyMsgSR4usOBf5nnYrDmaCCXirgQ=="
}
}
}

12
entry/oh-package.json5 Normal file
View File

@ -0,0 +1,12 @@
{
"license": "",
"devDependencies": {
"@ohos/hypium": "1.0.6"
},
"author": "",
"name": "myapplication",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

View File

@ -0,0 +1,45 @@
## 1.0.6
- 适配模块化编译
- 适配IDE覆盖率数据输出
## 1.0.5
- 优化接口异常场景处理能力
- 修复大规模压力测试下内存溢出问题
- 修复测试脚本定义扩展原型方法与框架的兼容性问题
- 异步promise状态判断断言与取反断言兼容
## 1.0.4
- 新增异步promise状态判断断言
- 新增基础数据判断断言
- 新增断言异常信息描述
- 优化用例计时逻辑,采用相对时间计时
- 修改用例执行过程,异步执行
- 修复用例结果偶现的乱序问题
## 1.0.3
- 新增mock对象的能力支持mock无参数函数
- 新增测试套、测试用例随机执行功能
- 解决测试套声明不规范,导致用例加载异常的问题
- 修复命令行窗口输出乱序的问题
## 1.0.2
- 新增mock接口判断当前mock方法状态、使用次数
- 修复用例耗时统计问题
- 修改断言功能,断言失败后,会抛出异常
## 1.0.1
- 新增mock基础能力
- 修复部分断言失败后,消息提示异常问题
## 1.0.0
- 新增应用日志关键字查询接口查询hilog日志中是否包含指定字符串
- 支持用例筛选功能,用于指定测试用例的执行。可按用例名称、类型、规模、级别与测试套名称筛选
- 支持新SDK下单元测试
- 支持dry run 功能,通过命令行传参数,返回当前测试套用例名称全集
- 新增框架接口声明文件用于deveco联想
- 修复用例状态统计问题

View File

@ -0,0 +1,219 @@
<div style="text-align: center;font-size: xxx-large" >Hypium</div>
<div style="text-align: center">A unit test framework for OpenHarmonyOS application</div>
## Hypium是什么?
***
- Hypium是OpenHarmony上的测试框架提供测试用例编写、执行、结果显示能力用于OpenHarmony系统应用接口以及应用界面测试。
- Hypium结构化模型hypium工程主要由List.test.js与TestCase.test.js组成。
```
rootProject // Hypium工程根目录
├── moduleA
│   ├── src
│      ├── main // 被测试应用目录
│      ├── ohosTest // 测试用例目录
│         ├── js/ets
│            └── test
│               └── List.test.js // 测试用例加载脚本ets目录下为.ets后缀
│               └── TestCase.test.js // 测试用例脚本ets目录下为.ets后缀
└── moduleB
...
│               └── List.test.js // 测试用例加载脚本ets目录下为.ets后缀
│               └── TestCase.test.js // 测试用例脚本ets目录下为.ets后缀
```
## 安装使用
***
- 在DevEco Studio内使用Hypium
- 工程级package.json内配置:
```json
"dependencies": {
"@ohos/hypium": "1.0.6"
}
```
注:
hypium服务于OpenHarmonyOS应用对外接口测试、系统对外接口测试SDK中接口完成HAP自动化测试。详细指导
[Deveco Studio](https://developer.harmonyos.com/cn/develop/deveco-studio)
#### 通用语法
- 测试用例采用业内通用语法describe代表一个测试套 it代表一条用例。
| No. | API | 功能说明 |
| --- | ---------- | ---------------------------------------------------------------------------------------------------------------------- |
| 1 | describe | 定义一个测试套,支持两个参数:测试套名称和测试套函数 |
| 2 | beforeAll | 在测试套内定义一个预置条件,在所有测试用例开始前执行且仅执行一次,支持一个参数:预置动作函数 |
| 3 | beforeEach | 在测试套内定义一个单元预置条件在每条测试用例开始前执行执行次数与it定义的测试用例数一致支持一个参数预置动作函数 |
| 4 | afterEach | 在测试套内定义一个单元清理条件在每条测试用例结束后执行执行次数与it定义的测试用例数一致支持一个参数清理动作函数 |
| 5 | afterAll | 在测试套内定义一个清理条件,在所有测试用例结束后执行且仅执行一次,支持一个参数:清理动作函数 |
| 6 | it | 定义一条测试用例,支持三个参数:用例名称,过滤参数和用例函数 |
| 7 | expect | 支持bool类型判断等多种断言方法 |
#### 断言库
- 示例代码:
```javascript
expect(${actualvalue}).assertX(${expectvalue})
```
- 断言功能列表:
| No. | API | 功能说明 |
| :--- | :------------------------------- | ---------------------------------------------------------------------------------------------- |
| 1 | assertClose | 检验actualvalue和expectvalue(0)的接近程度是否是expectValue(1) |
| 2 | assertContain | 检验actualvalue中是否包含expectvalue |
| 3 | assertDeepEquals | @since1.0.4 检验actualvalue和expectvalue(0)是否是同一个对象 |
| 4 | assertEqual | 检验actualvalue是否等于expectvalue[0] |
| 5 | assertFail | 抛出一个错误 |
| 6 | assertFalse | 检验actualvalue是否是false |
| 7 | assertTrue | 检验actualvalue是否是true |
| 8 | assertInstanceOf | 检验actualvalue是否是expectvalue类型 |
| 9 | assertLarger | 检验actualvalue是否大于expectvalue |
| 10 | assertLess | 检验actualvalue是否小于expectvalue |
| 11 | assertNaN | @since1.0.4 检验actualvalue是否是NaN |
| 12 | assertNegUnlimited | @since1.0.4 检验actualvalue是否等于Number.NEGATIVE_INFINITY |
| 13 | assertNull | 检验actualvalue是否是null |
| 14 | assertPosUnlimited | @since1.0.4 检验actualvalue是否等于Number.POSITIVE_INFINITY |
| 15 | assertPromiseIsPending | @since1.0.4 检验actualvalue是否处于Pending状态【actualvalue为promse对象】 |
| 16 | assertPromiseIsRejected | @since1.0.4 检验actualvalue是否处于Rejected状态【同15】 |
| 17 | assertPromiseIsRejectedWith | @since1.0.4 检验actualvalue是否处于Rejected状态并且比较执行的结果值【同15】 |
| 18 | assertPromiseIsRejectedWithError | @since1.0.4 检验actualvalue是否处于Rejected状态并有异常同时比较异常的类型和message值【同15】 |
| 19 | assertPromiseIsResolved | @since1.0.4 检验actualvalue是否处于Resolved状态【同15】 |
| 20 | assertPromiseIsResolvedWith | @since1.0.4 检验actualvalue是否处于Resolved状态并且比较执行的结果值【同15】 |
| 21 | assertThrowError | 检验actualvalue抛出Error内容是否是expectValue |
| 22 | assertUndefined | 检验actualvalue是否是undefined |
| 23 | not | @since1.0.4 断言结果取反 |
示例代码:
```javascript
import { describe, it, expect } from '@ohos/hypium';
export default async function assertCloseTest() {
describe('assertClose', function () {
it('assertClose_success', 0, function () {
let a = 100;
let b = 0.1;
expect(a).assertClose(99, b);
})
})
}
```
#### 公共系统能力
| No. | API | 功能描述 |
| ---- | ------------------------------------------------------- | ------------------------------------------------------------ |
| 1 | existKeyword(keyword: string, timeout: number): boolean | @since1.0.3 hilog日志中查找指定字段是否存在keyword是待查找关键字timeout为设置的查找时间 |
| 2 | actionStart(tag: string): void | @since1.0.3 cmd窗口输出开始tag |
| 3 | actionEnd(tag: string): void | @since1.0.3 cmd窗口输出结束tag |
示例代码:
```javascript
import { describe, it, expect, SysTestKit} from '@ohos/hypium';
export default function existKeywordTest() {
describe('existKeywordTest', function () {
it('existKeyword',DEFAULT, async function () {
console.info("HelloTest");
let isExist = await SysTestKit.existKeyword('HelloTest');
console.info('isExist ------>' + isExist);
})
})
}
```
```javascript
import { describe, it, expect, SysTestKit} from '@ohos/hypium';
export default function actionTest() {
describe('actionTest', function () {
it('existKeyword',DEFAULT, async function () {
let tag = '[MyTest]';
SysTestKit.actionStart(tag);
//do something
SysTestKit.actionEnd(tag);
})
})
}
```
#### 专项能力
- 测试用例属性筛选能力hypium支持根据用例属性筛选执行指定测试用例使用方式是先在测试用例上标记用例属性后再在测试应用的启动shell命令后新增" -s ${Key} ${Value}"。
| Key | 含义说明 | Value取值范围 |
| -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| level | 用例级别 | "0","1","2","3","4", 例如:-s level 1 |
| size | 用例粒度 | "small","medium","large", 例如:-s size small |
| testType | 用例测试类型 | "function","performance","power","reliability","security","global","compatibility","user","standard","safety","resilience", 例如:-s testType function |
示例代码
```javascript
import { describe, it, expect, TestType, Size, Level } from '@ohos/hypium';
export default function attributeTest() {
describe('attributeTest', function () {
it("testAttributeIt", TestType.FUNCTION | Size.SMALLTEST | Level.LEVEL0, function () {
console.info('Hello Test');
})
})
}
```
示例命令
```shell
XX -s level 1 -s size small -s testType function
```
该命令的作用是筛选测试应用中同时满足a用例级别是1 b用例粒度是small c用例测试类型是function 三个条件的用例执行。
- 测试套/测试用例名称筛选能力(测试套与用例名称用“#”号连接,多个用“,”英文逗号分隔)
| Key | 含义说明 | Value取值范围 |
| -------- | ----------------------- | -------------------------------------------------------------------------------------------- |
| class | 指定要执行的测试套&用例 | ${describeName}#${itName}${describeName} , 例如:-s class attributeTest#testAttributeIt |
| notClass | 指定不执行的测试套&用例 | ${describeName}#${itName}${describeName} , 例如:-s notClass attributeTest#testAttributeIt |
示例命令
```shell
XX -s class attributeTest#testAttributeIt,abilityTest#testAbilityIt
```
该命令的作用是筛选测试应用中attributeTest测试套下的testAttributeIt测试用例abilityTest测试套下的testAbilityIt测试用例只执行这两条用例。
- 其他能力
| 能力项 | Key | 含义说明 | Value取值范围 |
| ------------ | ------- | ---------------------------- | ---------------------------------------------- |
| 随机执行能力 | random | 测试套&测试用例随机执行 | true, 不传参默认为false 例如:-s random true |
| 空跑能力 | dryRun | 显示要执行的测试用例信息全集 | true , 不传参默认为false例如-s dryRun true |
| 异步超时能力 | timeout | 异步用例执行的超时时间 | 正整数 , 单位ms例如-s timeout 5000 |
##### 约束限制
随机执行能力和空跑能力从npm包1.0.3版本开始支持
#### Mock能力
##### 约束限制
单元测试框架Mock能力从npm包[1.0.1版本](https://repo.harmonyos.com/#/cn/application/atomService/@ohos%2Fhypium/v/1.0.1)开始支持
## 约束
***
本模块首批接口从OpenHarmony SDK API version 8开始支持。
## Hypium开放能力隐私声明
- 我们如何收集和使用您的个人信息
您在使用集成了Hypium开放能力的测试应用时Hypium不会处理您的个人信息。
- SDK处理的个人信息
不涉及。
- SDK集成第三方服务声明
不涉及。
- SDK数据安全保护
不涉及。
- SDK版本更新声明
为了向您提供最新的服务我们会不时更新Hypium版本。我们强烈建议开发者集成使用最新版本的Hypium。

View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export const DEFAULT = 0B0000
export const when: when;
export enum TestType {
FUNCTION = 0B1,
PERFORMANCE = 0B1 << 1,
POWER = 0B1 << 2,
RELIABILITY = 0B1 << 3,
SECURITY = 0B1 << 4,
GLOBAL = 0B1 << 5,
COMPATIBILITY = 0B1 << 6,
USER = 0B1 << 7,
STANDARD = 0B1 << 8,
SAFETY = 0B1 << 9,
RESILIENCE = 0B1 << 10
}
export enum Size {
SMALLTEST = 0B1 << 16,
MEDIUMTEST = 0B1 << 17,
LARGETEST = 0B1 << 18
}
export enum Level {
LEVEL0 = 0B1 << 24,
LEVEL1 = 0B1 << 25,
LEVEL2 = 0B1 << 26,
LEVEL3 = 0B1 << 27,
LEVEL4 = 0B1 << 28
}
export function describe(testSuiteName: string, callback: Function): void
export function beforeEach(callback: Function): void
export function afterEach(callback: Function): void
export function beforeAll(callback: Function): void
export function afterAll(callback: Function): void
export function it(testCaseName: string, attribute: (TestType | Size | Level), callback: Function)
export interface Assert {
assertClose(expectValue: number, precision: number): void
assertContain(expectValue: any): void
assertEqual(expectValue: any): void
assertFail(): void
assertFalse(): void
assertTrue(): void
assertInstanceOf(expectValue: string): void
assertLarger(expectValue: number): void
assertLess(expectValue: number): void
assertNull(): void
assertThrowError(expectValue: string): void
assertUndefined(): void
assertLargerOrEqual(expectValue: number):void
assertLessOrEqual(expectValue: number):void
assertNaN():void
assertNegUnlimited(): void
assertPosUnlimited(): void
not(): Assert;
assertDeepEquals(expectValue: any):void
assertPromiseIsPending(): void
assertPromiseIsRejected(): void
assertPromiseIsRejectedWith(expectValue?: any): void
assertPromiseIsRejectedWithError(...expectValue): void
assertPromiseIsResolved(): void
assertPromiseIsResolvedWith(expectValue?: any): void
}
export function expect(actualValue?: any): Assert
export class ArgumentMatchers {
static any;
static anyString;
static anyBoolean;
static anyNumber;
static anyObj;
static anyFunction;
static matchRegexs(Regex: RegExp): void
}
declare interface when {
afterReturn(value: any): any
afterReturnNothing(): undefined
afterAction(action: any): any
afterThrow(e_msg: string): string
(argMatchers?: any): when;
}
export interface VerificationMode {
times(count: Number): void
never(): void
once(): void
atLeast(count: Number): void
atMost(count: Number): void
}
export class MockKit {
constructor()
mockFunc(obj: Object, func: Function): Function
mockObject(obj: Object): Object
verify(methodName: String, argsArray: Array<any>): VerificationMode
ignoreMock(obj: Object, func: Function): void
clear(obj: Object): void
clearAll(): void
}
export class SysTestKit {
static actionStart(tag: string): void
static actionEnd(tag: string): void
static existKeyword(keyword: string, timeout?: number): boolean
}
export class Hypium {
static setData(data: {[key: string]: any}): void
static setTimeConfig(systemTime: any)
static hypiumTest(abilityDelegator: any, abilityDelegatorArguments: any, testsuite: Function): void
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Core from './src/main/core';
import {DEFAULT, TestType, Size, Level} from './src/main/Constant';
import DataDriver from './src/main/module/config/DataDriver';
import ExpectExtend from './src/main/module/assert/ExpectExtend';
import OhReport from './src/main/module/report/OhReport';
import SysTestKit from './src/main/module/kit/SysTestKit';
import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from './src/main/interface';
import {MockKit, when} from './src/main/module/mock/MockKit';
import ArgumentMatchers from './src/main/module/mock/ArgumentMatchers';
class Hypium {
static setData(data) {
const core = Core.getInstance();
const dataDriver = new DataDriver({data});
core.addService('dataDriver', dataDriver);
}
static setTimeConfig(systemTime) {
SysTestKit.systemTime = systemTime;
}
static hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) {
const core = Core.getInstance();
const expectExtend = new ExpectExtend({
'id': 'extend'
});
core.addService('expect', expectExtend);
const ohReport = new OhReport({
'delegator': abilityDelegator,
'abilityDelegatorArguments': abilityDelegatorArguments
});
SysTestKit.delegator = abilityDelegator;
core.addService('report', ohReport);
core.init();
core.subscribeEvent('spec', ohReport);
core.subscribeEvent('suite', ohReport);
core.subscribeEvent('task', ohReport);
const configService = core.getDefaultService('config');
let testParameters = {};
if (abilityDelegatorArguments !== null) {
testParameters = configService.translateParams(abilityDelegatorArguments.parameters);
}
console.info('parameters:' + JSON.stringify(testParameters));
configService.setConfig(testParameters);
testsuite();
if (Object.prototype.hasOwnProperty.call(globalThis, 'setupUiTestEnvironment')) {
globalThis.setupUiTestEnvironment().then(() => {
console.info('UiTestKit::after run uitest setup, start run testcases');
core.execute(abilityDelegator);
}).catch((error) => {
console.error('UiTestKit:: call setupUiTestEnvironment failure:' + error);
core.execute(abilityDelegator);
});
} else {
console.info('UiTestKit:: no need to setup uitest, start run testcases');
core.execute(abilityDelegator);
}
}
}
export {
Hypium,
Core,
DEFAULT,
TestType,
Size,
Level,
DataDriver,
ExpectExtend,
OhReport,
SysTestKit,
describe, beforeAll, beforeEach, afterEach, afterAll, it, expect,
MockKit, when,
ArgumentMatchers
};

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Core from './src/main/core';
import {DEFAULT, TestType, Size, Level} from './src/main/Constant';
import DataDriver from './src/main/module/config/DataDriver';
import ExpectExtend from './src/main/module/assert/ExpectExtend';
import OhReport from './src/main/module/report/OhReport';
import SysTestKit from './src/main/module/kit/SysTestKit';
import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from './src/main/interface';
import {MockKit, when} from './src/main/module/mock/MockKit';
import ArgumentMatchers from './src/main/module/mock/ArgumentMatchers';
class Hypium {
static setData(data) {
const core = Core.getInstance();
const dataDriver = new DataDriver({data});
core.addService('dataDriver', dataDriver);
}
static setTimeConfig(systemTime) {
SysTestKit.systemTime = systemTime;
}
static hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) {
const core = Core.getInstance();
const expectExtend = new ExpectExtend({
'id': 'extend'
});
core.addService('expect', expectExtend);
const ohReport = new OhReport({
'delegator': abilityDelegator,
'abilityDelegatorArguments': abilityDelegatorArguments
});
SysTestKit.delegator = abilityDelegator;
core.addService('report', ohReport);
core.init();
core.subscribeEvent('spec', ohReport);
core.subscribeEvent('suite', ohReport);
core.subscribeEvent('task', ohReport);
const configService = core.getDefaultService('config');
let testParameters = {};
if (abilityDelegatorArguments !== null) {
testParameters = configService.translateParams(abilityDelegatorArguments.parameters);
}
console.info('parameters:' + JSON.stringify(testParameters));
configService.setConfig(testParameters);
testsuite();
if (Object.prototype.hasOwnProperty.call(globalThis, 'setupUiTestEnvironment')) {
globalThis.setupUiTestEnvironment().then(() => {
console.info('UiTestKit::after run uitest setup, start run testcases');
core.execute(abilityDelegator);
}).catch((error) => {
console.error('UiTestKit:: call setupUiTestEnvironment failure:' + error);
core.execute(abilityDelegator);
});
} else {
console.info('UiTestKit:: no need to setup uitest, start run testcases');
core.execute(abilityDelegator);
}
}
}
export {
Hypium,
Core,
DEFAULT,
TestType,
Size,
Level,
DataDriver,
ExpectExtend,
OhReport,
SysTestKit,
describe, beforeAll, beforeEach, afterEach, afterAll, it, expect,
MockKit, when,
ArgumentMatchers
};

View File

@ -0,0 +1,11 @@
{
"name": "@ohos/hypium",
"version": "1.0.6",
"description": "A unit test framework for OpenHarmony application",
"main": "index.js",
"keywords": [],
"author": "huawei",
"license": "Apache-2.0",
"dependencies": {
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* define the testcase type : TestType, Size , Level
*/
export const DEFAULT = 0B0000;
export class TestType {
static FUNCTION = 0B1;
static PERFORMANCE = 0B1 << 1;
static POWER = 0B1 << 2;
static RELIABILITY = 0B1 << 3;
static SECURITY = 0B1 << 4;
static GLOBAL = 0B1 << 5;
static COMPATIBILITY = 0B1 << 6;
static USER = 0B1 << 7;
static STANDARD = 0B1 << 8;
static SAFETY = 0B1 << 9;
static RESILIENCE = 0B1 << 10;
}
export class Size {
static SMALLTEST = 0B1 << 16;
static MEDIUMTEST = 0B1 << 17;
static LARGETEST = 0B1 << 18;
}
export class Level {
static LEVEL0 = 0B1 << 24;
static LEVEL1 = 0B1 << 25;
static LEVEL2 = 0B1 << 26;
static LEVEL3 = 0B1 << 27;
static LEVEL4 = 0B1 << 28;
}

View File

@ -0,0 +1,159 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {SuiteService, SpecService, ExpectService, ReportService} from './service';
import {ConfigService} from './module/config/configService';
import {SpecEvent, TaskEvent, SuiteEvent} from './event';
/**
* core service for execute testcase.
*/
class Core {
static getInstance() {
if (!this.instance) {
this.instance = new Core();
}
return this.instance;
}
constructor() {
this.instance = null;
this.services = {
suite: {},
spec: {},
config: {},
expect: {},
log: {},
report: {}
};
this.events = {
suite: {},
spec: {},
task: {}
};
}
addService(name, service) {
let serviceObj = {};
if (!this.services[name]) {
this.services[name] = serviceObj;
} else {
serviceObj = this.services[name];
}
serviceObj[service.id] = service;
}
getDefaultService(name) {
return this.services[name].default;
}
getServices(name) {
return this.services[name];
}
registerEvent(serviceName, event) {
let eventObj = {};
if (!this.events[serviceName]) {
this.events[serviceName] = eventObj;
} else {
eventObj = this.events[serviceName];
}
eventObj[event.id] = event;
}
unRegisterEvent(serviceName, eventID) {
const eventObj = this.events[serviceName];
if (eventObj) {
delete eventObj[eventID];
}
}
subscribeEvent(serviceName, serviceObj) {
const eventObj = this.events[serviceName];
if (eventObj) {
for (const attr in eventObj) {
eventObj[attr]['subscribeEvent'](serviceObj);
}
}
}
async fireEvents(serviceName, eventName) {
const eventObj = this.events[serviceName];
if (!eventObj) {
return;
}
for (const attr in eventObj) {
await eventObj[attr][eventName]();
}
}
addToGlobal(apis) {
if (typeof globalThis !== 'undefined') {
for (let api in apis) {
globalThis[api] = apis[api];
}
}
for (const api in apis) {
this[api] = apis[api];
}
}
init() {
this.addService('suite', new SuiteService({id: 'default'}));
this.addService('spec', new SpecService({id: 'default'}));
this.addService('expect', new ExpectService({id: 'default'}));
this.addService('report', new ReportService({id: 'default'}));
this.addService('config', new ConfigService({id: 'default'}));
this.registerEvent('task', new TaskEvent({id: 'default', coreContext: this}));
this.registerEvent('suite', new SuiteEvent({id: 'default', coreContext: this}));
this.registerEvent('spec', new SpecEvent({id: 'default', coreContext: this}));
this.subscribeEvent('spec', this.getDefaultService('report'));
this.subscribeEvent('suite', this.getDefaultService('report'));
this.subscribeEvent('task', this.getDefaultService('report'));
const context = this;
for (const key in this.services) {
const serviceObj = this.services[key];
for (const serviceID in serviceObj) {
const service = serviceObj[serviceID];
service.init(context);
if (typeof service.apis !== 'function') {
continue;
}
const apis = service.apis();
if (apis) {
this.addToGlobal(apis);
}
}
}
}
execute(abilityDelegator) {
const suiteService = this.getDefaultService('suite');
const configService = this.getDefaultService('config');
if (configService['dryRun'] === 'true') {
(async function () {
await suiteService.dryRun(abilityDelegator);
})();
return;
}
setTimeout(() => {
suiteService.execute();
}, 10);
}
}
export default Core;

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class SpecEvent {
constructor(attr) {
this.id = attr.id;
this.coreContext = attr.context;
this.eventMonitors = [];
}
subscribeEvent(service) {
this.eventMonitors.push(service);
}
async specStart() {
for (const monitor of this.eventMonitors) {
await monitor['specStart']();
}
}
async specDone() {
for (const monitor of this.eventMonitors) {
await monitor['specDone']();
}
}
}
class SuiteEvent {
constructor(attr) {
this.id = attr.id;
this.suiteContext = attr.coreContext;
this.eventMonitors = [];
}
subscribeEvent(service) {
this.eventMonitors.push(service);
}
async suiteStart() {
for (const monitor of this.eventMonitors) {
await monitor['suiteStart']();
}
}
async suiteDone() {
for (const monitor of this.eventMonitors) {
await monitor['suiteDone']();
}
}
}
class TaskEvent {
constructor(attr) {
this.id = attr.id;
this.coreContext = attr.coreContext;
this.eventMonitors = [];
}
subscribeEvent(service) {
this.eventMonitors.push(service);
}
async taskStart() {
for (const monitor of this.eventMonitors) {
await monitor['taskStart']();
}
}
async taskDone() {
for (const monitor of this.eventMonitors) {
await monitor['taskDone']();
}
}
incorrectFormat() {
for (const monitor of this.eventMonitors) {
monitor['incorrectFormat']();
}
}
}
export {SpecEvent, TaskEvent, SuiteEvent};

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Core from './core';
const core = Core.getInstance();
const describe = function (desc, func) {
return Reflect.has(core, 'describe') ? core.describe(desc, func) : (desc, func) => { };
};
const it = function (desc, filter, func) {
return Reflect.has(core, 'it') ? core.it(desc, filter, func) : (desc, filter, func) => { };
};
const beforeEach = function (func) {
return Reflect.has(core, 'beforeEach') ? core.beforeEach(func) : (func) => { };
};
const afterEach = function (func) {
return Reflect.has(core, 'afterEach') ? core.afterEach(func) : (func) => { };
};
const beforeAll = function (func) {
return Reflect.has(core, 'beforeAll') ? core.beforeAll(func) : (func) => { };
};
const afterAll = function (func) {
return Reflect.has(core, 'afterAll') ? core.afterAll(func) : (func) => { };
};
const expect = function (actualValue) {
return Reflect.has(core, 'expect') ? core.expect(actualValue) : (actualValue) => { };
};
export {
describe, it, beforeAll, beforeEach, afterEach, afterAll, expect
};

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import assertNull from './assertNull';
import assertClose from './assertClose';
import assertContain from './assertContain';
import assertLess from './assertLess';
import assertLarger from './assertLarger';
import assertFail from './assertFail';
import assertUndefined from './assertUndefined';
import assertFalse from './assertFalse';
import assertInstanceOf from './assertInstanceOf';
import assertThrowError from './assertThrowError';
import assertLargerOrEqual from './assertLargerOrEqual'
import assertLessOrEqual from './assertLessOrEqual'
import assertNaN from './assertNaN'
import assertNegUnlimited from './assertNegUnlimited'
import assertPosUnlimited from './assertPosUnlimited'
import assertDeepEquals from './deepEquals/assertDeepEquals'
import assertPromiseIsPending from './assertPromiseIsPending';
import assertPromiseIsRejected from './assertPromiseIsRejected';
import assertPromiseIsRejectedWith from './assertPromiseIsRejectedWith';
import assertPromiseIsRejectedWithError from './assertPromiseIsRejectedWithError';
import assertPromiseIsResolved from './assertPromiseIsResolved';
import assertPromiseIsResolvedWith from './assertPromiseIsResolvedWith';
class ExpectExtend {
constructor(attr) {
this.id = attr.id;
this.matchers = {};
}
extendsMatchers() {
this.matchers.assertNull = assertNull;
this.matchers.assertClose = assertClose;
this.matchers.assertContain = assertContain;
this.matchers.assertLess = assertLess;
this.matchers.assertLarger = assertLarger;
this.matchers.assertFail = assertFail;
this.matchers.assertUndefined = assertUndefined;
this.matchers.assertFalse = assertFalse;
this.matchers.assertInstanceOf = assertInstanceOf;
this.matchers.assertThrowError = assertThrowError;
this.matchers.assertLargerOrEqual = assertLargerOrEqual;
this.matchers.assertLessOrEqual = assertLessOrEqual;
this.matchers.assertNaN = assertNaN;
this.matchers.assertNegUnlimited = assertNegUnlimited;
this.matchers.assertPosUnlimited = assertPosUnlimited;
this.matchers.assertDeepEquals = assertDeepEquals;
this.matchers.assertPromiseIsPending = assertPromiseIsPending;
this.matchers.assertPromiseIsRejected = assertPromiseIsRejected;
this.matchers.assertPromiseIsRejectedWith = assertPromiseIsRejectedWith;
this.matchers.assertPromiseIsRejectedWithError = assertPromiseIsRejectedWithError;
this.matchers.assertPromiseIsResolved = assertPromiseIsResolved;
this.matchers.assertPromiseIsResolvedWith = assertPromiseIsResolvedWith;
}
init(coreContext) {
this.coreContext = coreContext;
this.extendsMatchers();
const expectService = this.coreContext.getDefaultService('expect');
expectService.addMatchers(this.matchers);
}
apis() {
return {
'expect': function (actualValue) {
return this.coreContext.getDefaultService('expect').expect(actualValue);
}
};
}
}
export default ExpectExtend;

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertClose(actualValue, expected) {
console.log('expected:' + expected[0] + ',precision:' + expected[1]);
if (actualValue === null && expected[0] === null) {
throw new Error('actualValue and expected can not be both null!!!');
}
let result;
let diff = Math.abs(expected[0] - actualValue);
let actualAbs = Math.abs(actualValue);
if ((actualAbs - 0) === 0) {
if ((diff - 0) === 0) {
result = true;
} else {
result = false;
}
} else if (diff / actualAbs < expected[1]) {
result = true;
} else {
result = false;
}
return {
pass: result,
message: '|' + actualValue + ' - ' + expected[0] + '|/' + actualValue + ' is not less than ' + expected[1]
};
}
export default assertClose;

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertContain(actualValue, expect) {
let result = false;
if (Object.prototype.toString.call(actualValue).indexOf('Array')) {
for (let i in actualValue) {
if (actualValue[i] == expect[0]) {
result = true;
}
}
}
let type = Object.prototype.toString.call(actualValue);
if (type === '[object String]') {
result = actualValue.indexOf(expect[0]) >= 0;
}
return {
pass: result,
message: 'expect false, ' + actualValue + ' do not have ' + expect[0]
};
}
export default assertContain;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertFail() {
return {
pass: false,
message: 'fail '
};
}
export default assertFail;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertFalse(actualValue) {
return {
pass: (actualValue) === false,
message: 'expect false, actualValue is ' + actualValue
};
}
export default assertFalse;

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertInstanceOf(actualValue, expected) {
if (Object.prototype.toString.call(actualValue) == '[object ' + expected[0] + ']') {
return {
pass: true
};
} else {
return {
pass: false,
message: actualValue + ' is ' + Object.prototype.toString.call(actualValue) + 'not ' + expected[0]
};
}
}
export default assertInstanceOf;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertLarger(actualValue, expected) {
return {
pass: (actualValue) > expected[0],
message: (actualValue) + ' is not larger than ' + expected[0]
};
}
export default assertLarger;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertLargerOrEqual(actualValue, expected) {
return {
pass: (actualValue) >= expected[0],
message: (actualValue) + ' is not larger than ' + expected[0]
};
}
export default assertLargerOrEqual;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertLess(actualValue, expected) {
return {
pass: (actualValue) < expected[0],
message: (actualValue) + ' is not less than ' + expected[0]
};
}
export default assertLess;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertLessOrEqual(actualValue, expected) {
return {
pass: (actualValue) <= expected[0],
message: (actualValue) + ' is not less than ' + expected[0]
};
}
export default assertLessOrEqual;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertNaN(actualValue) {
return {
pass: actualValue !== actualValue,
message: 'expect NaN, actualValue is ' + actualValue
};
}
export default assertNaN;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertNegUnlimited(actualValue) {
return {
pass: actualValue === Number.NEGATIVE_INFINITY,
message: 'Expected actualValue not to be -Infinity. actualValue is,' + actualValue
};
}
export default assertNegUnlimited;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertNull(actualValue) {
return {
pass: (actualValue) === null,
message: 'expect null, actualValue is ' + (actualValue)
};
}
export default assertNull;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertPosUnlimited(actualValue) {
return {
pass: actualValue === Number.POSITIVE_INFINITY,
message: 'Expected actualValue is POSITIVE_INFINITY. actualValue is,' + actualValue
};
}
export default assertPosUnlimited;

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import isPromiseLike from './isPromiseLike';
function assertPromiseIsPending(actualPromise) {
if (!isPromiseLike(actualPromise)) {
return Promise.reject().then(function () {
}, function () {
return {pass: false, message: 'Expected not be called on a promise.'};
});
}
const helper = {};
return Promise.race([actualPromise, Promise.resolve(helper)]).then(
function (got) {
return helper === got ? {pass: true, message: 'actualValue is isPending'}
: {
pass: false,
message: 'expect isPending, actualValue is resolve'
};
},
function () {
return {
pass: false
, message: 'expect isPending, actualValue is reject'
};
});
}
export default assertPromiseIsPending;

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import isPromiseLike from './isPromiseLike';
function assertPromiseIsRejected(actualPromise) {
if (!isPromiseLike(actualPromise)) {
return Promise.reject().then(function () {
}, function () {
return {pass: false, message: 'Expected not be called on a promise.'};
});
}
const helper = {};
return Promise.race([actualPromise, Promise.resolve(helper)]).then(
function (got) {
return {
pass: false,
message: 'expect isRejected, but actualValue is '
+ (helper === got ? 'isPending' : 'resolve')
};
},
function () {
return {pass: true, message: 'actualValue is isRejected'};
}
);
}
export default assertPromiseIsRejected;

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import isPromiseLike from './isPromiseLike';
function assertPromiseIsRejectedWith(actualPromise, expectedValue) {
if (!isPromiseLike(actualPromise)) {
return Promise.reject().then(function () {
}, function () {
return {pass: false, message: 'Expected not be called on a promise.'};
});
}
function tips(passed) {
return ('Expected a promise ' + (passed ? 'not ' : '') +
'to be rejected with ' + JSON.stringify(expectedValue[0]));
}
const helper = {};
return Promise.race([actualPromise, Promise.resolve(helper)]).then(
function (got) {
return {
pass: false,
message: tips(false) + ' but actualValue is '
+ (helper === got ? 'isPending' : 'resolve')
};
},
function (actualValue) {
if (JSON.stringify(actualValue) == JSON.stringify(expectedValue[0])) {
return {
pass: true,
message: 'actualValue was rejected with ' + JSON.stringify(actualValue) + '.'
};
} else {
return {
pass: false,
message: tips(false) + ' but it was rejected with ' + JSON.stringify(actualValue) + '.'
};
}
}
);
}
export default assertPromiseIsRejectedWith;

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import isPromiseLike from './isPromiseLike';
function assertPromiseIsRejectedWithError(actualPromise, expectedValue) {
if (!isPromiseLike(actualPromise)) {
return Promise.reject().then(function () {
}, function () {
return {pass: false, message: 'Expected not be called on a promise.'};
});
}
const helper = {};
return Promise.race([actualPromise, Promise.resolve(helper)]).then(
function (got) {
return {
pass: false,
message: 'Expected a promise to be rejected but actualValue is '
+ (helper === got ? 'isPending' : 'resolve')
};
},
function (actualValue) {
return matchError(actualValue, expectedValue);
}
);
}
function matchError(actualValue, expectedValue) {
if (expectedValue.length == 1 && typeof expectedValue[0] === 'function') {
if (expectedValue[0].name === actualValue.__proto__.name) {
return {pass: true, message: 'actual error type is ' + actualValue.name + '.'};
}
return {
pass: false,
message: 'except error type is ' + expectedValue[0].name + ',but actual is ' + actualValue.name + '.'
};
}
if (expectedValue.length == 1 && typeof expectedValue[0] === 'string') {
if (expectedValue[0] === actualValue.message) {
return {pass: true, message: 'actual error message is ' + actualValue.message + '.'};
}
return {
pass: false,
message: 'except error message ' + expectedValue[0] + ',but actual is ' + actualValue.message + '.'
};
}
if (expectedValue.length == 1) {
return {
pass: false,
message: 'When only one parameter, it ' +
'should be error type or error message.'
};
}
if (expectedValue.length == 2 && typeof expectedValue[0] === 'function' && expectedValue[0].name === actualValue.name) {
if (typeof expectedValue[1] === 'string' && actualValue.message === expectedValue[1]) {
return {pass: true, message: 'actual error message is ' + actualValue.message + '.'};
} else {
return {
pass: false,
message: 'except error message is ' + expectedValue[1] + ',but actual is ' + actualValue.message + '.'
};
}
}
if (expectedValue.length == 2 && typeof expectedValue[0] === 'function' && expectedValue[0].name !== actualValue.name) {
if (typeof expectedValue[1] === 'string' && actualValue.message === expectedValue[1]) {
return {
pass: false,
message: 'except error type is ' + expectedValue[0].name + ',but actual is ' + actualValue.name + '.'
};
} else {
return {
pass: false,
message: 'except error type and message are incorrect.'
};
}
}
if (expectedValue.length > 2) {
return {
pass: false,
message: 'Up to two parameters are supported.'
};
}
}
export default assertPromiseIsRejectedWithError;

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import isPromiseLike from './isPromiseLike';
function assertPromiseIsResolved(actualPromise) {
if (!isPromiseLike(actualPromise)) {
return Promise.reject().then(function () {
}, function () {
return {pass: false, message: 'Expected not be called on a promise.'};
});
}
const helper = {};
return Promise.race([actualPromise, Promise.resolve(helper)]).then(
function (got) {
return helper === got ? {
pass: false,
message: 'expect resolve, actualValue is isPending'
}
: {pass: true, message: 'actualValue is isResolved'};
},
function (rej) {
return {
pass: false,
message: 'Expected a promise to be resolved but it was ' +
'rejected with ' + JSON.stringify(rej) + '.'
};
}
);
}
export default assertPromiseIsResolved;

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import isPromiseLike from './isPromiseLike';
function assertPromiseIsResolvedWith(actualPromise, expectedValue) {
if (!isPromiseLike(actualPromise)) {
return Promise.reject().then(function () {
}, function () {
return {pass: false, message: 'Expected not be called on a promise.'};
});
}
function tips(passed) {
return (
'Expected a promise ' + (passed ? 'not ' : '') +
'to be resolved with ' + JSON.stringify(expectedValue[0]));
}
const helper = {};
return Promise.race([actualPromise, Promise.resolve(helper)]).then(
function (got) {
if (helper === got) {
return {pass: false, message: 'expect resolve, actualValue is isPending'};
}
if (JSON.stringify(got) == JSON.stringify(expectedValue[0])) {
return {
pass: true,
message: 'actualValue was resolved with ' + JSON.stringify(got) + '.'
};
}
return {
pass: false,
message: tips(false) + ' but it was resolved with ' +
JSON.stringify(got) + '.'
};
},
function (rej) {
return {
pass: false,
message: tips(false) + ' but it was rejected with ' + JSON.stringify(rej) + '.'
};
}
);
}
export default assertPromiseIsResolvedWith;

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertThrowError(actualValue, expected) {
let result = false;
let err;
if (typeof actualValue !== 'function') {
throw new Error('actualValue is not a function');
}
try {
actualValue();
return {
pass: result,
message: ' An error is not thrown while it is expected!'
};
} catch (e) {
err = e;
}
if (err instanceof Error) {
console.log(err.message);
if (err.message == expected[0]) {
result = true;
}
}
return {
pass: result,
message: 'expected throw failed , ' + err.message + ' is not ' + expected[0]
};
}
export default assertThrowError;

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function assertUndefined(actualValue) {
return {
pass: undefined === (actualValue),
message: 'expect Undefined, actualValue is ' + (actualValue)
};
}
export default assertUndefined;

View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class DeepTypeUtils {
static getType_(value) {
return Object.prototype.toString.apply(value);
}
static isA_(typeName, value) {
return this.getType_(value) === '[object ' + typeName + ']';
}
static isAsymmetricEqualityTester_(obj) {
return obj ? this.isA_('Function', obj.asymmetricMatch) : false;
}
/**
* 是否是function
* @param value
*/
static isFunction_(value) {
return this.isA_('Function', value);
}
/**
* 是否是undefined
* @param obj
*/
static isUndefined(obj) {
return obj === void 0;
}
/**
* 是否是Node
* @param obj
*/
static isDomNode(obj) {
return obj !== null &&
typeof obj === 'object' &&
typeof obj.nodeType === 'number' &&
typeof obj.nodeName === 'string';
}
/**
* 是否是promise对象
* @param obj
*/
static isPromise (obj) {
return !!obj && obj.constructor === Promise;
};
/**
* 是否是map对象
* @param obj
*/
static isMap(obj) {
return (
obj !== null &&
typeof obj !== 'undefined' &&
obj.constructor === Map
);
}
/**
* 是否是set对象
* @param obj 对象
*/
static isSet(obj) {
return (
obj !== null &&
typeof obj !== 'undefined' &&
obj.constructor === Set
);
}
/**
* 对象是否有key属性
* @param obj 对象
* @param key 对象属性名称
*/
static has(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
/**
* 获取对象的自有属性
* @param obj 对象
* @param isArray 是否是数组,[object Array]
*/
static keys(obj, isArray) {
const extraKeys = [];
// 获取对象所有属性
const allKeys = this.getAllKeys(obj);
if (!isArray) {
return allKeys;
}
if (allKeys.length === 0) {
return allKeys;
}
for (const k of allKeys) {
if (typeof k === 'symbol' || !/^[0-9]+$/.test(k)) {
extraKeys.push(k);
}
}
return extraKeys;
}
/**
* 获取obj对象的所有属性
* @param obj obj对象
*/
static getAllKeys(obj) {
const keys = [];
for (let key in obj) {
if(this.has(obj, key)) {
keys.push(key);
}
}
const symbols = Object.getOwnPropertySymbols(obj);
for (const sym of symbols) {
if (obj.propertyIsEnumerable(sym)) {
keys.push(sym);
}
}
return keys;
}
}
export default DeepTypeUtils;

View File

@ -0,0 +1,311 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import DeepTypeUtils from './DeepTypeUtils'
function assertDeepEquals(actualValue, expected) {
console.log('actualValue:' + actualValue + ',expected:' + expected[0]);
let result = eq(actualValue, expected[0],[], [])
let msg = logMsg(actualValue, expected[0]);
return {
pass: result,
message: msg
};
}
/**
* 获取失败显示日志
* @param actualValue 实际对象
* @param expected 期待比较对象
*/
function logMsg(actualValue, expected) {
// 获取a的对象名称
const aClassName = Object.prototype.toString.call(actualValue);
const bClassName = Object.prototype.toString.call(expected);
let actualMsg;
let expectMsg;
if(aClassName == "[object Function]") {
actualMsg = "actualValue Function"
}else if(aClassName == "[object Promise]") {
actualMsg = "actualValue Promise"
}else if(aClassName == "[object Set]" || aClassName == "[object Map]") {
actualMsg = JSON.stringify(Array.from(actualValue));;
}else if(aClassName == "[object RegExp]") {
actualMsg = JSON.stringify(actualValue.source.replace("\\",""));;
}
else{
actualMsg = JSON.stringify(actualValue);
}
if(bClassName == "[object Function]") {
expectMsg = "expected Function"
}else if(bClassName == "[object Promise]") {
expectMsg = "expected Promise"
}else if(aClassName == "[object Set]" || bClassName == "[object Map]") {
expectMsg = JSON.stringify(Array.from(expected));
}else if(aClassName == "[object RegExp]") {
expectMsg = JSON.stringify(expected.source.replace("\\",""));;
}
else{
expectMsg = JSON.stringify(expected);
}
return actualMsg + " is not deep equal " + expectMsg;
}
function eq(a, b, aStack, bStack) {
let result = true;
console.log('a is:' + a + ',b is:' + b);
const asymmetricResult = asymmetricMatch_(a,b);
if (!DeepTypeUtils.isUndefined(asymmetricResult)) {
return asymmetricResult;
}
if (a instanceof Error && b instanceof Error) {
result = a.message == b.message;
return result;
}
if (a === b) {
result = a !== 0 || 1 / a == 1 / b;
return result;
}
if (a === null || b === null) {
result = a === b;
return result;
}
// 获取a的对象名称
const aClassName = Object.prototype.toString.call(a);
const bClassName = Object.prototype.toString.call(b);
console.log('aClassName is:' + aClassName);
console.log('bClassName is:' + bClassName);
// 不同类型不同对象
if (aClassName != bClassName) {
return false;
}
// 俩个string对象
if(aClassName === '[object String]') {
result = a == String(b);
return result;
}
// 俩个Number对象
if(aClassName === '[object Number]') {
result = a != +a ? b != +b : a === 0 && b === 0 ? 1 / a == 1 / b : a == +b;
return result;
}
if(aClassName === '[object Date]' || aClassName === '[object Boolean]') {
result = +a == +b;
return result;
}
// 数组
if(aClassName === '[object ArrayBuffer]') {
return eq(new Uint8Array(a), new Uint8Array(b), aStack, bStack);
}
// 正则表达式
if(aClassName === '[object RegExp]') {
return (
a.source == b.source &&
a.global == b.global &&
a.multiline == b.multiline &&
a.ignoreCase == b.ignoreCase
);
}
if (typeof a != 'object' || typeof b != 'object') {
return false;
}
const aIsDomNode = DeepTypeUtils.isDomNode(a);
const bIsDomNode = DeepTypeUtils.isDomNode(b);
if (aIsDomNode && bIsDomNode) {
// At first try to use DOM3 method isEqualNode
result = a.isEqualNode(b);
return result;
}
if (aIsDomNode || bIsDomNode) {
return false;
}
const aIsPromise = DeepTypeUtils.isPromise(a);
const bIsPromise = DeepTypeUtils.isPromise(b);
if (aIsPromise && bIsPromise) {
return a === b;
}
let length = aStack.length;
while (length--) {
if (aStack[length] == a) {
return bStack[length] == b;
}
}
aStack.push(a);
bStack.push(b);
let size = 0;
// 都是数组
if(aClassName == '[object Array]') {
const aLength = a.length;
const bLength = b.length;
if (aLength !== bLength) {
// 数组长度不同,不是同一个对象
return false;
}
for (let i = 0; i < aLength || i < bLength; i++) {
// 递归每一个元素是否相同
result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack) && result;
}
if (!result) {
return false;
}
} else if(DeepTypeUtils.isMap(a) && DeepTypeUtils.isMap(b)) {
if (a.size != b.size) {
return false;
}
const keysA = [];
const keysB = [];
a.forEach(function(valueA, keyA) {
keysA.push(keyA);
});
b.forEach(function(valueB, keyB) {
keysB.push(keyB);
});
const mapKeys = [keysA, keysB];
const cmpKeys = [keysB, keysA];
for (let i = 0; result && i < mapKeys.length; i++) {
const mapIter = mapKeys[i];
const cmpIter = cmpKeys[i];
for (let j = 0; result && j < mapIter.length; j++) {
const mapKey = mapIter[j];
const cmpKey = cmpIter[j];
const mapValueA = a.get(mapKey);
let mapValueB;
if (
DeepTypeUtils.isAsymmetricEqualityTester_(mapKey) ||
(DeepTypeUtils.isAsymmetricEqualityTester_(cmpKey) &&
eq(mapKey, cmpKey))
) {
mapValueB = b.get(cmpKey);
} else {
mapValueB = b.get(mapKey);
}
result = eq(mapValueA, mapValueB, aStack, bStack);
}
}
if (!result) {
return false;
}
} else if(DeepTypeUtils.isSet(a) && DeepTypeUtils.isSet(b)) {
if (a.size != b.size) {
return false;
}
const valuesA = [];
a.forEach(function(valueA) {
valuesA.push(valueA);
});
const valuesB = [];
b.forEach(function(valueB) {
valuesB.push(valueB);
});
const setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
const stackPairs = [[aStack, bStack], [bStack, aStack]];
for (let i = 0; result && i < setPairs.length; i++) {
const baseValues = setPairs[i][0];
const otherValues = setPairs[i][1];
const baseStack = stackPairs[i][0];
const otherStack = stackPairs[i][1];
for (const baseValue of baseValues) {
let found = false;
for (let j = 0; !found && j < otherValues.length; j++) {
const otherValue = otherValues[j];
const prevStackSize = baseStack.length;
// 深度比较对象
found = eq(baseValue, otherValue, baseStack, otherStack);
if (!found && prevStackSize !== baseStack.length) {
baseStack.splice(prevStackSize);
otherStack.splice(prevStackSize);
}
}
result = result && found;
}
}
if (!result) {
return false;
}
} else {
const aCtor = a.constructor,
bCtor = b.constructor;
if (
aCtor !== bCtor &&
DeepTypeUtils.isFunction_(aCtor) &&
DeepTypeUtils.isFunction_(bCtor) &&
a instanceof aCtor &&
b instanceof bCtor &&
!(aCtor instanceof aCtor && bCtor instanceof bCtor)
) {
return false;
}
}
// 获取对象所有的属性集合
const aKeys = DeepTypeUtils.keys(a, aClassName == '[object Array]');
size = aKeys.length;
// 俩个对象属性长度不一致, 俩对象不相同
if (DeepTypeUtils.keys(b, bClassName == '[object Array]').length !== size) {
return false;
}
// 俩对象属性数量相同, 递归比较每个属性值得值
for (const key of aKeys) {
console.log('key is:' + key);
// b 没有 key 属性
if(!DeepTypeUtils.has(b, key)) {
result = false;
continue;
}
if (!eq(a[key], b[key], aStack, bStack)) {
result = false;
}
}
if (!result) {
return false;
}
aStack.pop();
bStack.pop();
return result;
}
function asymmetricMatch_(a, b) {
const asymmetricA = DeepTypeUtils.isAsymmetricEqualityTester_(a);
const asymmetricB = DeepTypeUtils.isAsymmetricEqualityTester_(b);
if (asymmetricA === asymmetricB) {
return undefined;
}
}
/**
* 获取对象的自有属性
*
* @param obj 对象
* @param isArray 是否是一个数组
*/
function keys(obj, isArray) {
const keys = [];
}
export default assertDeepEquals;

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function isPromiseLike(obj) {
return !!obj && isFunction_(obj.then);
}
function isFunction_(value) {
return isA_('Function', value);
}
function isA_(typeName, value) {
return getType_(value) === '[object ' + typeName + ']';
}
function getType_(value) {
return Object.prototype.toString.apply(value);
}
export default isPromiseLike;

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const SUITES_KEY = 'suites';
const SPECS_KEY = 'items';
const DESCRIBE_KEY = 'describe';
const IT_KEY = 'it';
const PARAMS_KEY = 'params';
const STRESS_KEY = 'stress';
class ObjectUtils {
static get(object, name, defaultValue) {
let result = defaultValue;
for (const key in object) {
if (key === name) {
return object[key];
}
}
return result;
}
static has(object, key) {
return Object.prototype.hasOwnProperty.call(object, key);
}
}
class DataDriver {
constructor(attr) {
this.id = 'dataDriver';
this.data = attr.data || {};
}
init(coreContext) {
this.coreContext = coreContext;
this.suiteService = this.coreContext.getDefaultService('suite');
this.specService = this.coreContext.getDefaultService('spec');
}
getSpecParams() {
let specParams = [];
let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
let specDesc = this.specService.getCurrentRunningSpec().description;
let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
for (const suiteItem of suites) {
let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, '');
if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []);
for (const specItem of specs) {
if (ObjectUtils.has(specItem, IT_KEY) && ObjectUtils.get(specItem, IT_KEY) === specDesc) {
return ObjectUtils.get(specItem, PARAMS_KEY, specParams);
}
}
}
}
return specParams;
}
getSuiteParams() {
let suiteParams = {};
let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
for (const suiteItem of suites) {
let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, []);
if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
suiteParams = Object.assign({}, suiteParams, ObjectUtils.get(suiteItem, PARAMS_KEY, suiteParams));
}
}
return suiteParams;
}
getSpecStress(specDesc) {
let stress = 1;
let suiteDesc = this.suiteService.getCurrentRunningSuite().description;
let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
for (const suiteItem of suites) {
let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, '');
if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
let specs = ObjectUtils.get(suiteItem, SPECS_KEY, []);
for (const specItem of specs) {
if (ObjectUtils.has(specItem, IT_KEY) && ObjectUtils.get(specItem, IT_KEY) === specDesc) {
let tempStress = ObjectUtils.get(specItem, STRESS_KEY, stress);
return (Number.isInteger(tempStress) && tempStress >= 1) ? tempStress : stress;
}
}
}
}
return stress;
}
getSuiteStress(suiteDesc) {
let stress = 1;
let suites = ObjectUtils.get(this.data, SUITES_KEY, []);
for (const suiteItem of suites) {
let describeValue = ObjectUtils.get(suiteItem, DESCRIBE_KEY, []);
if (ObjectUtils.has(suiteItem, DESCRIBE_KEY) && (typeof describeValue === 'object') && describeValue.constructor === Array && describeValue.includes(suiteDesc)) {
let tempStress = ObjectUtils.get(suiteItem, STRESS_KEY, stress);
return (Number.isInteger(tempStress) && tempStress >= 1) ? tempStress : stress;
}
}
return stress;
}
}
export default DataDriver;

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ClassFilter {
constructor(suiteName, itName, params) {
this.suiteName = suiteName;
this.itName = itName;
this.params = params;
}
filterSuite() {
return !this.params.split(',').map(item => item.split('#')[0]).map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
}
filterIt() {
let classArray = this.params.split(',') || [];
let suiteFilterResult = classArray.filter(item => !item.includes('#')).map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
let itFilterResult = classArray.filter(item => item.includes('#')).map(item => item == (this.suiteName + '#' + this.itName)).reduce((pre, cur) => pre || cur, false);
return !(suiteFilterResult || itFilterResult);
}
}
class NotClassFilter {
constructor(suiteName, itName, params) {
this.suiteName = suiteName;
this.itName = itName;
this.params = params;
}
filterSuite() {
return this.params.split(',').map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
}
filterIt() {
return this.params.split(',').some(item => item == (this.suiteName + '#' + this.itName));
}
}
class SuiteAndItNameFilter {
constructor(suiteName, itName, params) {
this.suiteName = suiteName;
this.itName = itName;
this.params = params;
}
filterSuite() {
return !this.params.split(',').map(item => item == this.suiteName).reduce((pre, cur) => pre || cur, false);
}
filterIt() {
return !this.params.split(',').map(item => item == this.itName).reduce((pre, cur) => pre || cur, false);
}
}
class TestTypesFilter {
constructor(suiteName, itName, fi, params) {
this.suiteName = suiteName;
this.itName = itName;
this.params = params;
this.fi = fi;
}
filterIt() {
return !((this.params === (this.fi & this.params)) || this.fi === 0);
}
}
export {ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter};

View File

@ -0,0 +1,292 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter} from './Filter';
const STRESS_RULE = /^[1-9]\d*$/;
class ConfigService {
constructor(attr) {
this.id = attr.id;
this.supportAsync = false;
this.random = false;
this.filterValid = [];
this.filter = 0;
this.flag = false;
this.suite = null;
this.itName = null;
this.testType = null;
this.level = null;
this.size = null;
this.class = null;
this.notClass = null;
this.timeout = null;
// 遇错即停模式配置
this.breakOnError = false;
// 压力测试配置
this.stress = null;
}
init(coreContext) {
this.coreContext = coreContext;
}
isNormalInteger(str) {
const n = Math.floor(Number(str));
return n !== Infinity && String(n) === String(str) && n >= 0;
}
getStress() {
if (this.stress === undefined || this.stress === '' || this.stress === null) {
return 1;
}
return !this.stress.match(STRESS_RULE) ? 1 : Number.parseInt(this.stress);
}
basicParamValidCheck(params) {
let size = params.size;
if (size !== undefined && size !== '' && size !== null) {
let sizeArray = ['small', 'medium', 'large'];
if (sizeArray.indexOf(size) === -1) {
this.filterValid.push('size:' + size);
}
}
let level = params.level;
if (level !== undefined && level !== '' && level !== null) {
let levelArray = ['0', '1', '2', '3', '4'];
if (levelArray.indexOf(level) === -1) {
this.filterValid.push('level:' + level);
}
}
let testType = params.testType;
if (testType !== undefined && testType !== '' && testType !== null) {
let testTypeArray = ['function', 'performance', 'power', 'reliability', 'security',
'global', 'compatibility', 'user', 'standard', 'safety', 'resilience'];
if (testTypeArray.indexOf(testType) === -1) {
this.filterValid.push('testType:' + testType);
}
}
}
filterParamValidCheck(params) {
let timeout = params.timeout;
if (timeout !== undefined && timeout !== '' && timeout !== null) {
if (!this.isNormalInteger(timeout)) {
this.filterValid.push('timeout:' + timeout);
}
}
let paramKeys = ['dryRun', 'random', 'breakOnError', 'coverage'];
for (const key of paramKeys) {
if (params[key] !== undefined && params[key] !== 'true' && params[key] !== 'false') {
this.filterValid.push(`${key}:${params[key]}`);
}
}
// 压力测试参数验证,正整数
if (params.stress !== undefined && params.stress !== '' && params.stress !== null) {
if (!params.stress.match(STRESS_RULE)) {
this.filterValid.push('stress:' + params.stress);
}
}
let nameRule = /^[A-Za-z]{1}[\w#,.]*$/;
let paramClassKeys = ['class', 'notClass'];
for (const key of paramClassKeys) {
if (params[key] !== undefined && params[key] !== '' && params[key] !== null) {
let classArray = params[key].split(',');
classArray.forEach(item => !item.match(nameRule) ? this.filterValid.push(`${key}:${params[key]}`) : null);
}
}
}
setConfig(params) {
this.basicParamValidCheck(params);
this.filterParamValidCheck(params);
try {
this.class = params.class;
this.notClass = params.notClass;
this.flag = params.flag || {flag: false};
this.suite = params.suite;
this.itName = params.itName;
this.filter = params.filter;
this.testType = params.testType;
this.level = params.level;
this.size = params.size;
this.timeout = params.timeout;
this.dryRun = params.dryRun;
this.breakOnError = params.breakOnError;
this.random = params.random === 'true' ? true : false;
this.stress = params.stress;
this.coverage = params.coverage;
this.filterParam = {
testType: {
'function': 1,
'performance': 1 << 1,
'power': 1 << 2,
'reliability': 1 << 3,
'security': 1 << 4,
'global': 1 << 5,
'compatibility': 1 << 6,
'user': 1 << 7,
'standard': 1 << 8,
'safety': 1 << 9,
'resilience': 1 << 10,
},
level: {
'0': 1 << 24,
'1': 1 << 25,
'2': 1 << 26,
'3': 1 << 27,
'4': 1 << 28,
},
size: {
'small': 1 << 16,
'medium': 1 << 17,
'large': 1 << 18,
}
};
this.parseParams();
} catch (err) {
console.info('setConfig error: ' + err.message);
}
}
parseParams() {
if (this.filter != null) {
return;
}
let testTypeFilter = 0;
let sizeFilter = 0;
let levelFilter = 0;
if (this.testType != null) {
testTypeFilter = this.testType.split(',')
.map(item => this.filterParam.testType[item] || 0)
.reduce((pre, cur) => pre | cur, 0);
}
if (this.level != null) {
levelFilter = this.level.split(',')
.map(item => this.filterParam.level[item] || 0)
.reduce((pre, cur) => pre | cur, 0);
}
if (this.size != null) {
sizeFilter = this.size.split(',')
.map(item => this.filterParam.size[item] || 0)
.reduce((pre, cur) => pre | cur, 0);
}
this.filter = testTypeFilter | sizeFilter | levelFilter;
console.info('filter params:' + this.filter);
}
isCurrentSuite(description) {
if (this.suite !== undefined && this.suite !== '' && this.suite !== null) {
let suiteArray = this.suite.split(',');
return suiteArray.indexOf(description) !== -1;
}
return false;
}
filterSuite(currentSuiteName) {
let filterArray = [];
if (this.suite !== undefined && this.suite !== '' && this.suite !== null) {
filterArray.push(new SuiteAndItNameFilter(currentSuiteName, '', this.suite));
}
if (this.class !== undefined && this.class !== '' && this.class !== null) {
filterArray.push(new ClassFilter(currentSuiteName, '', this.class));
}
if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) {
filterArray.push(new NotClassFilter(currentSuiteName, '', this.notClass));
}
let result = filterArray.map(item => item.filterSuite()).reduce((pre, cur) => pre || cur, false);
return result;
}
filterDesc(currentSuiteName, desc, fi, coreContext) {
let filterArray = [];
if (this.itName !== undefined && this.itName !== '' && this.itName !== null) {
filterArray.push(new SuiteAndItNameFilter(currentSuiteName, desc, this.itName));
}
if (this.class !== undefined && this.class !== '' && this.class !== null) {
filterArray.push(new ClassFilter(currentSuiteName, desc, this.class));
}
if (this.notClass !== undefined && this.notClass !== '' && this.notClass !== null) {
filterArray.push(new NotClassFilter(currentSuiteName, desc, this.notClass));
}
if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && fi !== 0) {
filterArray.push(new TestTypesFilter('', '', fi, this.filter));
}
let result = filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false);
return result;
}
isRandom() {
return this.random || false;
}
isBreakOnError() {
return this.breakOnError !== 'true' ? false : true;
}
setSupportAsync(value) {
this.supportAsync = value;
}
isSupportAsync() {
return this.supportAsync;
}
translateParams(parameters) {
const keySet = new Set([
'-s class', '-s notClass', '-s suite', '-s itName',
'-s level', '-s testType', '-s size', '-s timeout',
'-s dryRun', '-s random', '-s breakOnError', '-s stress',
'-s coverage', 'class', 'notClass', 'suite', 'itName',
'level', 'testType', 'size', 'timeout', 'dryRun', 'random',
'breakOnError', 'stress', 'coverage'
]);
let targetParams = {};
for (const key in parameters) {
if (keySet.has(key)) {
var newKey = key.replace("-s ", "");
targetParams[newKey] = parameters[key];
}
}
return targetParams;
}
translateParamsToString(parameters) {
const keySet = new Set([
'-s class', '-s notClass', '-s suite', '-s itName',
'-s level', '-s testType', '-s size', '-s timeout',
'-s dryRun', '-s random', '-s breakOnError', '-s stress',
'-s coverage','class', 'notClass', 'suite', 'itName',
'level', 'testType', 'size', 'timeout', 'dryRun', 'random',
'breakOnError', 'stress', 'coverage'
]);
let targetParams = '';
for (const key in parameters) {
if (keySet.has(key)) {
targetParams += ' ' + key + ' ' + parameters[key];
}
}
return targetParams.trim();
}
execute() {
}
}
export {
ConfigService
};

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import SysTestKit from "../kit/SysTestKit";
export async function collectCoverageData() {
if (globalThis.__coverage__ === undefined) {
return;
}
const strJson = JSON.stringify(globalThis.__coverage__);
const strLen = strJson.length;
const maxLen = 500;
const maxCount = Math.floor(strLen / maxLen);
const OHOS_REPORT_COVERAGE_DATA = 'OHOS_REPORT_COVERAGE_DATA:';
for (let count = 0; count <= maxCount; count++) {
await SysTestKit.print(`${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}`);
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class SysTestKit {
static delegator = null;
static systemTime = null;
constructor() {
this.id = 'sysTestKit';
this.index = 0;
}
static actionStart(tag) {
console.info(JSON.stringify(tag));
var message = '\n' + 'OHOS_REPORT_ACTIONSTART: ' + JSON.stringify(tag) + '\n';
SysTestKit.print(message);
console.info(tag + ' actionStart print success');
}
static actionEnd(tag) {
console.info(JSON.stringify(tag));
var message = '\n' + 'OHOS_REPORT_ACTIONEND: ' + JSON.stringify(tag) + '\n';
SysTestKit.print(message);
console.info(tag + ' actionEnd print success');
}
static async existKeyword(keyword, timeout) {
let reg = new RegExp(/^[a-zA-Z0-9]{1,}$/)
if (!reg.test(keyword)) {
throw new Error('keyword must contain more than one string, and only letters and numbers are supported.')
}
timeout = timeout || 4;
let searchResult = false;
let cmd = 'hilog -x | grep -i \'' + keyword + '\' | wc -l';
await executePromise(cmd, timeout).then((data) => {
searchResult = data;
});
return searchResult;
}
static async print(message) {
if ('printSync' in SysTestKit.delegator) {
console.debug(`printSync called ...`);
SysTestKit.delegator.printSync(message);
} else {
await SysTestKit.delegator.print(message);
}
}
static async getRealTime() {
let currentTime = new Date().getTime();
if (SysTestKit.systemTime !== null && SysTestKit.systemTime !== undefined) {
await SysTestKit.systemTime.getRealTime().then((time) => {
console.info(`systemTime.getRealTime success data: ${JSON.stringify(time)}`);
currentTime = time;
}).catch((error) => {
console.error(`failed to systemTime.getRealTime because ${JSON.stringify(error)}`);
});
}
return currentTime;
}
}
function executePromise(cmd, timeout) {
return new Promise((resolve, reject) => {
SysTestKit.delegator.executeShellCommand(cmd, timeout,
(error, data) => {
console.info('existKeyword CallBack: err : ' + JSON.stringify(error));
console.info('existKeyword CallBack: data : ' + JSON.stringify(data));
resolve(parseInt(data.stdResult) > 3 ? true : false);
});
});
}
export default SysTestKit;

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ArgumentMatchers {
ANY = "<any>";
ANY_STRING = "<any String>";
ANY_BOOLEAN = "<any Boolean>";
ANY_NUMBER = "<any Number>";
ANY_OBJECT = "<any Object>";
ANY_FUNCTION = "<any Function>";
MATCH_REGEXS = "<match regexs>";
static any() {
}
static anyString() {
}
static anyBoolean() {
}
static anyNumber() {
}
static anyObj() {
}
static anyFunction() {
}
static matchRegexs() {
let regex = arguments[0];
if (ArgumentMatchers.isRegExp(regex)) {
return regex;
}
throw Error("not a regex");
}
static isRegExp(value) {
return Object.prototype.toString.call(value) === "[object RegExp]";
}
matcheReturnKey() {
let arg = arguments[0];
let regex = arguments[1];
let stubSetKey = arguments[2];
if (stubSetKey && stubSetKey == this.ANY) {
return this.ANY;
}
if (typeof arg === "string" && !regex) {
return this.ANY_STRING;
}
if (typeof arg === "boolean" && !regex) {
return this.ANY_BOOLEAN;
}
if (typeof arg === "number" && !regex) {
return this.ANY_NUMBER;
}
if (typeof arg === "object" && !regex) {
return this.ANY_OBJECT;
}
if (typeof arg === "function" && !regex) {
return this.ANY_FUNCTION;
}
if (typeof arg === "string" && regex) {
return regex.test(arg);
}
return null;
}
matcheStubKey() {
let key = arguments[0];
if (key === ArgumentMatchers.any) {
return this.ANY;
}
if (key === ArgumentMatchers.anyString) {
return this.ANY_STRING;
}
if (key === ArgumentMatchers.anyBoolean) {
return this.ANY_BOOLEAN;
}
if (key === ArgumentMatchers.anyNumber) {
return this.ANY_NUMBER;
}
if (key === ArgumentMatchers.anyObj) {
return this.ANY_OBJECT;
}
if (key === ArgumentMatchers.anyFunction) {
return this.ANY_FUNCTION;
}
if (ArgumentMatchers.isRegExp(key)) {
return key;
}
return null;
}
}
export default ArgumentMatchers;

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ExtendInterface {
constructor(mocker) {
this.mocker = mocker;
}
stub() {
this.params = arguments;
return this;
}
stubMockedCall(returnInfo) {
this.mocker.stubApply(this, this.params, returnInfo);
}
afterReturn(value) {
this.stubMockedCall(function () {
return value;
});
}
afterReturnNothing() {
this.stubMockedCall(function () {
return undefined;
});
}
afterAction(action) {
this.stubMockedCall(action);
}
afterThrow(msg) {
this.stubMockedCall(function () {
throw msg;
});
}
clear() {
this.mocker.clear();
}
}
export default ExtendInterface;

View File

@ -0,0 +1,256 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ExtendInterface from "./ExtendInterface";
import VerificationMode from "./VerificationMode";
import ArgumentMatchers from "./ArgumentMatchers";
class MockKit {
constructor() {
this.mFunctions = [];
this.stubs = new Map();
this.recordCalls = new Map();
this.currentSetKey = null;
this.mockObj = null;
this.recordMockedMethod = new Map();
}
init() {
this.reset();
}
reset() {
this.mFunctions = [];
this.stubs = {};
this.recordCalls = {};
this.currentSetKey = null;
this.mockObj = null;
this.recordMockedMethod = new Map();
}
clearAll() {
this.reset();
var props = Object.keys(this);
for (var i = 0; i < props.length; i++) {
delete this[props[i]];
}
var props = Object.getOwnPropertyNames(this);
for (var i = 0; i < props.length; i++) {
delete this[props[i]];
}
for (var key in this) {
delete this[key];
}
}
clear(obj) {
if (!obj) throw Error("Please enter an object to be cleaned");
if (typeof (obj) != 'object') throw new Error('Not a object');
this.recordMockedMethod.forEach(function (value, key, map) {
if (key) {
obj[key] = value;
}
});
}
ignoreMock(obj, method) {
if (typeof (obj) != 'object') throw new Error('Not a object');
if (typeof (method) != 'function') throw new Error('Not a function');
let og = this.recordMockedMethod.get(method.propName);
if (og) {
obj[method.propName] = og;
this.recordMockedMethod.set(method.propName, undefined);
}
}
extend(dest, source) {
dest["stub"] = source["stub"];
dest["afterReturn"] = source["afterReturn"];
dest["afterReturnNothing"] = source["afterReturnNothing"];
dest["afterAction"] = source["afterAction"];
dest["afterThrow"] = source["afterThrow"];
dest["stubMockedCall"] = source["stubMockedCall"];
dest["clear"] = source["clear"];
return dest;
}
stubApply(f, params, returnInfo) {
let values = this.stubs.get(f);
if (!values) {
values = new Map();
}
let key = params[0];
if (typeof key == "undefined") {
key = "anonymous-mock-" + f.propName;
}
let matcher = new ArgumentMatchers();
if (matcher.matcheStubKey(key)) {
key = matcher.matcheStubKey(key);
if (key) {
this.currentSetKey = key;
}
}
values.set(key, returnInfo);
this.stubs.set(f, values);
}
getReturnInfo(f, params) {
let values = this.stubs.get(f);
if (!values) {
return undefined;
}
let retrunKet = params[0];
if (typeof retrunKet == "undefined") {
retrunKet = "anonymous-mock-" + f.propName;
}
let stubSetKey = this.currentSetKey;
if (this.currentSetKey && (typeof (retrunKet) != "undefined")) {
retrunKet = stubSetKey;
}
let matcher = new ArgumentMatchers();
if (matcher.matcheReturnKey(params[0], undefined, stubSetKey) && matcher.matcheReturnKey(params[0], undefined, stubSetKey) != stubSetKey) {
retrunKet = params[0];
}
values.forEach(function (value, key, map) {
if (ArgumentMatchers.isRegExp(key) && matcher.matcheReturnKey(params[0], key)) {
retrunKet = key;
}
});
return values.get(retrunKet);
}
findName(obj, value) {
let properties = this.findProperties(obj);
let name = null;
properties.forEach(
function (va1, idx, array) {
if (obj[va1] === value) {
name = va1;
}
}
);
return name;
}
isFunctionFromPrototype(f, container, propName) {
if (container.constructor != Object && container.constructor.prototype !== container) {
return container.constructor.prototype[propName] === f;
}
return false;
}
findProperties(obj, ...arg) {
function getProperty(new_obj) {
if (new_obj.__proto__ === null) {
return [];
}
let properties = Object.getOwnPropertyNames(new_obj);
return [...properties, ...getProperty(new_obj.__proto__)];
}
return getProperty(obj);
}
recordMethodCall(originalMethod, args) {
Function.prototype.getName = function () {
return this.name || this.toString().match(/function\s*([^(]*)\(/)[1];
};
let name = originalMethod.getName();
let arglistString = name + '(' + Array.from(args).toString() + ')';
let records = this.recordCalls.get(arglistString);
if (!records) {
records = 0;
}
records++;
this.recordCalls.set(arglistString, records);
}
mockFunc(originalObject, originalMethod) {
let tmp = this;
this.originalMethod = originalMethod;
let f = function () {
let args = arguments;
let action = tmp.getReturnInfo(f, args);
if (originalMethod) {
tmp.recordMethodCall(originalMethod, args);
}
if (action) {
return action.apply(this, args);
}
};
f.container = null || originalObject;
f.original = originalMethod || null;
if (originalObject && originalMethod) {
if (typeof (originalMethod) != 'function') throw new Error('Not a function');
var name = this.findName(originalObject, originalMethod);
originalObject[name] = f;
this.recordMockedMethod.set(name, originalMethod);
f.propName = name;
f.originalFromPrototype = this.isFunctionFromPrototype(f.original, originalObject, f.propName);
}
f.mocker = this;
this.mFunctions.push(f);
this.extend(f, new ExtendInterface(this));
return f;
}
verify(methodName, argsArray) {
if (!methodName) {
throw Error("not a function name");
}
let a = this.recordCalls.get(methodName + '(' + argsArray.toString() + ')');
return new VerificationMode(a ? a : 0);
}
mockObject(object) {
if (!object || typeof object === "string") {
throw Error(`this ${object} cannot be mocked`);
}
const _this = this;
let mockedObject = {};
let keys = Reflect.ownKeys(object);
keys.filter(key => (typeof Reflect.get(object, key)) === 'function')
.forEach(key => {
mockedObject[key] = object[key];
mockedObject[key] = _this.mockFunc(mockedObject, mockedObject[key]);
});
return mockedObject;
}
}
function ifMockedFunction(f) {
if (Object.prototype.toString.call(f) != "[object Function]" &&
Object.prototype.toString.call(f) != "[object AsyncFunction]") {
throw Error("not a function");
}
if (!f.stub) {
throw Error("not a mock function");
}
return true;
}
function when(f) {
if (ifMockedFunction(f)) {
return f.stub.bind(f);
}
}
export {MockKit, when};

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {expect} from '../../interface';
class VerificationMode {
constructor(times) {
this.doTimes = times;
}
times(count) {
expect(count).assertEqual(this.doTimes);
}
never() {
console.log(this.doTimes);
expect(0).assertEqual(this.doTimes);
}
once() {
expect(1).assertEqual(this.doTimes);
}
atLeast(count) {
if (count > this.doTimes) {
throw Error('failed ' + count + ' greater than the actual execution times of method');
}
}
atMost(count) {
if (count < this.doTimes) {
throw Error('failed ' + count + ' less than the actual execution times of method');
}
}
}
export default VerificationMode;

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import SysTestKit from "../kit/SysTestKit";
import {collectCoverageData} from '../coverage/coverageCollect';
class OhReport {
constructor(attr) {
this.delegator = attr.delegator;
this.abilityDelegatorArguments = attr.abilityDelegatorArguments;
this.id = 'report';
this.index = 0;
this.duration = 0;
}
init(coreContext) {
this.coreContext = coreContext;
this.suiteService = this.coreContext.getDefaultService('suite');
this.specService = this.coreContext.getDefaultService('spec');
}
taskStart() {
}
async taskDone() {
if (this.abilityDelegatorArguments !== null) {
this.taskDoneTime = new Date().getTime();
let summary = this.suiteService.getSummary();
const configService = this.coreContext.getDefaultService('config');
if (configService['coverage'] === 'true') {
await collectCoverageData();
}
let message = '\n' + 'OHOS_REPORT_RESULT: stream=Tests run: ' + summary.total + ', Failure: ' + summary.failure;
message += ', Error: ' + summary.error;
message += ', Pass: ' + summary.pass;
message += ', Ignore: ' + summary.ignore;
message += '\n' + 'OHOS_REPORT_CODE: ' + (summary.failure > 0 ? -1 : 0) + '\n';
let isHasError = summary.failure > 0 || summary.error > 0;
let config = this.coreContext.getDefaultService('config');
if (config.isBreakOnError() && isHasError) {
// 未执行全部说明
message += '\n' + 'OHOS_REPORT_RESULT: breakOnError model, Stopping whole test suite if one specific test case failed or error' + '\n';
}
message += 'OHOS_REPORT_STATUS: taskconsuming=' + summary.duration + '\n';
console.info(message);
await SysTestKit.print(message);
}
console.info('report print success');
this.delegator.finishTest('your test finished!!!', 0, () => { });
}
incorrectFormat() {
if (this.coreContext.getDefaultService('config').filterValid.length !== 0) {
var value = this.coreContext.getDefaultService('config').filterValid;
var message = 'this param ' + value.join(',') + ' is invalid' + '\n';
this.delegator.finishTest(message, 0, () => {
});
}
}
async suiteStart() {
if (this.abilityDelegatorArguments !== null) {
let message = '\n' + 'OHOS_REPORT_SUM: ' + this.suiteService.getCurrentRunningSuite().getSpecsNum();
message += '\n' + 'OHOS_REPORT_STATUS: class=' + this.suiteService.getCurrentRunningSuite().description + '\n';
console.info(message);
await SysTestKit.print(message);
console.info(this.suiteService.getCurrentRunningSuite().description + ' suiteStart print success');
}
}
async suiteDone() {
if (this.abilityDelegatorArguments !== null) {
let message = '\n' + 'OHOS_REPORT_STATUS: class=' + this.suiteService.getCurrentRunningSuite().description;
message += '\n' + 'OHOS_REPORT_STATUS: suiteconsuming=' + this.suiteService.getCurrentRunningSuite().duration + '\n';
console.info(message);
await SysTestKit.print(message);
console.info(this.suiteService.getCurrentRunningSuite().description + ' suiteDone print success');
}
}
async specStart() {
if (this.abilityDelegatorArguments !== null) {
let message = '\n' + 'OHOS_REPORT_STATUS: class=' + this.suiteService.getCurrentRunningSuite().description;
message += '\n' + 'OHOS_REPORT_STATUS: current=' + (++this.index);
message += '\n' + 'OHOS_REPORT_STATUS: id=JS';
message += '\n' + 'OHOS_REPORT_STATUS: numtests=' + this.specService.getTestTotal();
message += '\n' + 'OHOS_REPORT_STATUS: stream=';
message += '\n' + 'OHOS_REPORT_STATUS: test=' + this.specService.currentRunningSpec.description;
message += '\n' + 'OHOS_REPORT_STATUS_CODE: 1' + '\n';
console.info(message);
await SysTestKit.print(message);
console.info(this.specService.currentRunningSpec.description + ' specStart start print success');
}
}
async specDone() {
if (this.abilityDelegatorArguments !== null) {
let message = '\n' + 'OHOS_REPORT_STATUS: class=' + this.suiteService.getCurrentRunningSuite().description;
message += '\n' + 'OHOS_REPORT_STATUS: current=' + (this.index);
message += '\n' + 'OHOS_REPORT_STATUS: id=JS';
message += '\n' + 'OHOS_REPORT_STATUS: numtests=' + this.specService.getTestTotal();
let errorMsg = '';
if (this.specService.currentRunningSpec.error) {
message += '\n' + 'OHOS_REPORT_STATUS: stack=' + this.specService.currentRunningSpec.error.message;
message += '\n' + 'OHOS_REPORT_STATUS: stream=';
message += '\n' + 'Error in ' + this.specService.currentRunningSpec.description;
message += '\n' + this.specService.currentRunningSpec.error.message;
message += '\n' + 'OHOS_REPORT_STATUS: test=' + this.specService.currentRunningSpec.description;
message += '\n' + 'OHOS_REPORT_STATUS_CODE: -1' + '\n';
} else if (this.specService.currentRunningSpec.result) {
if (this.specService.currentRunningSpec.result.failExpects.length > 0) {
this.specService.currentRunningSpec.result.failExpects.forEach(failExpect => {
errorMsg = failExpect.message || ('expect ' + failExpect.actualValue + ' ' + failExpect.checkFunc + ' ' + (failExpect.expectValue));
});
message += '\n' + 'OHOS_REPORT_STATUS: stack=' + errorMsg;
message += '\n' + 'OHOS_REPORT_STATUS: stream=';
message += '\n' + 'Error in ' + this.specService.currentRunningSpec.description;
message += '\n' + errorMsg + '\n' + 'OHOS_REPORT_STATUS: test=' + this.specService.currentRunningSpec.description;
message += '\n' + 'OHOS_REPORT_STATUS_CODE: -2' + '\n';
} else {
message += '\n' + 'OHOS_REPORT_STATUS: stream=';
message += '\n' + 'OHOS_REPORT_STATUS: test=' + this.specService.currentRunningSpec.description;
message += '\n' + 'OHOS_REPORT_STATUS_CODE: 0' + '\n';
}
} else {
message += '\n';
}
message += 'OHOS_REPORT_STATUS: consuming=' + this.specService.currentRunningSpec.duration + '\n';
console.info(message);
await SysTestKit.print(message);
console.info(this.specService.currentRunningSpec.description + ' specDone end print success');
}
}
}
export default OhReport;

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ReportExtend {
constructor(fileModule) {
this.id = 'extend';
this.fileModule = fileModule;
}
init(coreContext) {
this.coreContext = coreContext;
this.suiteService = this.coreContext.getDefaultService('suite');
}
taskStart() {
}
taskDone() {
const report = {
tag: 'testsuites',
name: 'summary_report',
timestamp: new Date().toDateString(),
time: '1',
errors: 0,
failures: 0,
tests: 0,
children: []
};
const rootSuite = this.suiteService.rootSuite;
if (rootSuite && rootSuite.childSuites) {
for (let testsuite of rootSuite.childSuites) {
let suiteReport = {
tag: 'testsuite',
name: testsuite['description'],
errors: 0,
tests: 0,
failures: 0,
time: '0.1',
children: []
};
let specs = testsuite['specs'];
for (let testcase of specs) {
report.tests++;
suiteReport.tests++;
let caseReport = {
tag: 'testcase',
name: testcase['description'],
status: 'run',
time: '0.0',
classname: testsuite['description']
};
if (testcase.error) {
caseReport['result'] = false;
caseReport['children'] = [{
tag: 'error',
type: '',
message: testcase.error.message
}];
report.errors++;
suiteReport.errors++;
} else if (testcase.result.failExpects.length > 0) {
caseReport['result'] = false;
let message = '';
testcase.result.failExpects.forEach(failExpect => {
message += failExpect.message || ('expect ' + failExpect.actualValue + ' ' + failExpect.checkFunc + ' ' + (failExpect.expectValue || '')) + ';';
});
caseReport['children'] = [{
tag: 'failure',
type: '',
message: message
}];
report.failures++;
suiteReport.failures++;
} else {
caseReport['result'] = true;
}
suiteReport.children.push(caseReport);
}
report.children.push(suiteReport);
}
}
let reportXml = '<?xml version="1.0" encoding="UTF-8"?>\n' + json2xml(report);
this.fileModule.writeText({
uri: 'internal://app/report.xml',
text: reportXml,
success: function () {
console.info('call success callback success');
},
fail: function (data, code) {
console.info('call fail callback success:');
},
complete: function () {
console.info('call complete callback success');
}
});
}
}
function json2xml(json) {
let tagName;
let hasChildren = false;
let childrenStr = '';
let attrStr = '';
for (let key in json) {
if (key === 'tag') {
tagName = json[key];
} else if (key === 'children') {
if (json[key].length > 0) {
hasChildren = true;
for (let child of json[key]) {
childrenStr += json2xml(child);
}
}
} else {
attrStr += ` ${key}="${json[key]}"`;
}
}
let xml = `<${tagName}${attrStr}`;
xml += hasChildren ? `>${childrenStr}</${tagName}>` : '/>';
return xml;
}
export default ReportExtend;

View File

@ -0,0 +1,929 @@
/*
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import SysTestKit from "./module/kit/SysTestKit";
class AssertException extends Error {
constructor(message) {
super();
this.name = "AssertException";
this.message = message;
}
}
function getFuncWithArgsZero(func, timeout, isStressTest) {
return new Promise(async (resolve, reject) => {
let timer = null;
if (!isStressTest) {
timer = setTimeout(() => {
reject(new Error('execute timeout ' + timeout + 'ms'));
}, timeout);
}
try {
await func();
} catch (err) {
reject(err);
}
timer !== null ? clearTimeout(timer) : null;
resolve();
});
}
function getFuncWithArgsOne(func, timeout, isStressTest) {
return new Promise(async (resolve, reject) => {
let timer = null;
if (!isStressTest) {
timer = setTimeout(() => {
reject(new Error('execute timeout ' + timeout + 'ms'));
}, timeout);;
}
function done() {
timer !== null ? clearTimeout(timer) : null;
resolve();
}
try {
await func(done);
} catch (err) {
timer !== null ? clearTimeout(timer) : null;
reject(err);
}
});
}
function getFuncWithArgsTwo(func, timeout, paramItem, isStressTest) {
return new Promise(async (resolve, reject) => {
let timer = null;
if (!isStressTest) {
timer = setTimeout(() => {
reject(new Error('execute timeout ' + timeout + 'ms'));
}, timeout);
}
function done() {
timer !== null ? clearTimeout(timer) : null;
resolve();
}
try {
await func(done, paramItem);
} catch (err) {
timer !== null ? clearTimeout(timer) : null;
reject(err);
}
});
}
function processFunc(coreContext, func) {
let argNames = ((func || '').toString()
.replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '')
.match(/^(function)?\s*[^\(]*\(\s*([^\)]*)\)/m) || ['', '', ''])[2]
.split(',') // split parameters
.map(item => item.replace(/^\s*(_?)(.+?)\1\s*$/, name => name.split('=')[0].trim()))
.filter(String);
let funcLen = func.length;
let processedFunc;
const config = coreContext.getDefaultService('config');
config.setSupportAsync(true);
const timeout = + (config.timeout === undefined ? 5000 : config.timeout);
const isStressTest = (coreContext.getServices('dataDriver') !== undefined || config.getStress() > 1);
switch (funcLen) {
case 0: {
processedFunc = function () {
return getFuncWithArgsZero(func, timeout, isStressTest);
};
break;
}
case 1: {
if (argNames[0] === 'data') {
processedFunc = function (paramItem) {
func(paramItem);
};
} else {
processedFunc = function () {
return getFuncWithArgsOne(func, timeout, isStressTest);
};
}
break;
}
default: {
processedFunc = function (paramItem) {
return getFuncWithArgsTwo(func, timeout, paramItem, isStressTest);
};
break;
}
}
return processedFunc;
}
function secureRandomNumber() {
return crypto.randomBytes(8).readUInt32LE() / 0xffffffff;
}
class SuiteService {
constructor(attr) {
this.id = attr.id;
this.rootSuite = new SuiteService.Suite({});
this.currentRunningSuite = this.rootSuite;
this.suitesStack = [this.rootSuite];
}
describe(desc, func) {
const configService = this.coreContext.getDefaultService('config');
if (configService.filterSuite(desc)) {
console.info('filter suite :' + desc);
return;
}
const suite = new SuiteService.Suite({description: desc});
if (typeof this.coreContext.getServices('dataDriver') !== 'undefined' && configService['dryRun'] !== 'true') {
let suiteStress = this.coreContext.getServices('dataDriver').dataDriver.getSuiteStress(desc);
for (let i = 1; i < suiteStress; i++) {
this.currentRunningSuite.childSuites.push(suite);
}
}
this.currentRunningSuite.childSuites.push(suite);
this.currentRunningSuite = suite;
this.suitesStack.push(suite);
func.call();
let childSuite = this.suitesStack.pop();
if (this.suitesStack.length === 0) {
this.currentRunningSuite = childSuite;
this.suitesStack.push(childSuite);
}
if (this.suitesStack.length > 1) {
this.currentRunningSuite = this.suitesStack.pop();
} else {
this.currentRunningSuite = this.suitesStack.pop();
this.suitesStack.push(this.currentRunningSuite);
}
}
beforeAll(func) {
this.currentRunningSuite.beforeAll.push(processFunc(this.coreContext, func));
}
beforeEach(func) {
this.currentRunningSuite.beforeEach.push(processFunc(this.coreContext, func));
}
afterAll(func) {
this.currentRunningSuite.afterAll.push(processFunc(this.coreContext, func));
}
afterEach(func) {
this.currentRunningSuite.afterEach.push(processFunc(this.coreContext, func));
}
getCurrentRunningSuite() {
return this.currentRunningSuite;
}
setCurrentRunningSuite(suite) {
this.currentRunningSuite = suite;
}
traversalResults(suite, obj, breakOnError) {
if (suite.childSuites.length === 0 && suite.specs.length === 0) {
return obj;
}
if (suite.specs.length > 0) {
for (const itItem of suite.specs) {
obj.total++;
if (breakOnError && (obj.error > 0 || obj.failure > 0)) { // breakOnError模式
continue;
}
if (itItem.error) {
obj.error++;
} else if (itItem.result.failExpects.length > 0) {
obj.failure++;
} else if (itItem.result.pass === true) {
obj.pass++;
}
}
}
obj.duration += suite.duration;
if (suite.childSuites.length > 0) {
for (const suiteItem of suite.childSuites) {
this.traversalResults(suiteItem, obj, breakOnError);
}
}
}
getSummary() {
let suiteService = this.coreContext.getDefaultService('suite');
let rootSuite = suiteService.rootSuite;
const specService = this.coreContext.getDefaultService('spec');
const configService = this.coreContext.getDefaultService('config');
let breakOnError = configService.isBreakOnError();
let isError = specService.getStatus();
let isBreaKOnError = breakOnError && isError;
let obj = {total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0};
for (const suiteItem of rootSuite.childSuites) {
this.traversalResults(suiteItem, obj, isBreaKOnError);
}
obj.ignore = obj.total - obj.pass - obj.failure - obj.error;
return obj;
}
init(coreContext) {
this.coreContext = coreContext;
}
traversalSuites(suite, obj, configService) {
if (suite.childSuites.length === 0 && suite.specs.length === 0) {
return [];
}
if (suite.specs.length > 0) {
let itArray = [];
for (const itItem of suite['specs']) {
if (!configService.filterDesc(suite.description, itItem.description, itItem.fi, null)) {
itArray.push({'itName': itItem.description});
}
}
obj[suite.description] = itArray;
}
if (suite.childSuites.length > 0) {
let suiteArray = [];
for (const suiteItem of suite.childSuites) {
let suiteObj = {};
this.traversalSuites(suiteItem, suiteObj, configService);
if (!configService.filterSuite(suiteItem.description)) {
suiteArray.push(suiteObj);
}
}
obj.suites = suiteArray;
}
}
async dryRun(abilityDelegator) {
const configService = this.coreContext.getDefaultService('config');
let testSuitesObj = {};
let suitesArray = [];
for (const suiteItem of this.rootSuite.childSuites) {
let obj = {};
this.traversalSuites(suiteItem, obj, configService);
if (!configService.filterSuite(suiteItem.description)) {
suitesArray.push(obj);
}
}
testSuitesObj['suites'] = suitesArray;
let strJson = JSON.stringify(testSuitesObj);
let strLen = strJson.length;
let maxLen = 500;
let maxCount = Math.floor(strLen / maxLen);
for (let count = 0; count <= maxCount; count++) {
await SysTestKit.print(strJson.substring(count * maxLen, (count + 1) * maxLen));
}
console.info('dryRun print success');
abilityDelegator.finishTest('dry run finished!!!', 0, () => { });
}
execute() {
const configService = this.coreContext.getDefaultService('config');
if (configService.filterValid.length !== 0) {
this.coreContext.fireEvents('task', 'incorrectFormat');
return;
}
if (configService.isRandom() && this.rootSuite.childSuites.length > 0) {
this.rootSuite.childSuites.sort(function () {
return Math.random().toFixed(1) > 0.5 ? -1 : 1;
});
this.currentRunningSuite = this.rootSuite.childSuites[0];
}
if (configService.isSupportAsync()) {
let asyncExecute = async () => {
await this.coreContext.fireEvents('task', 'taskStart');
await this.rootSuite.asyncRun(this.coreContext);
};
asyncExecute().then(async () => {
await this.coreContext.fireEvents('task', 'taskDone');
});
} else {
this.coreContext.fireEvents('task', 'taskStart');
this.rootSuite.run(this.coreContext);
this.coreContext.fireEvents('task', 'taskDone');
}
}
apis() {
const _this = this;
return {
describe: function (desc, func) {
return _this.describe(desc, func);
},
beforeAll: function (func) {
return _this.beforeAll(func);
},
beforeEach: function (func) {
return _this.beforeEach(func);
},
afterAll: function (func) {
return _this.afterAll(func);
},
afterEach: function (func) {
return _this.afterEach(func);
}
};
}
}
SuiteService.Suite = class {
constructor(attrs) {
this.description = attrs.description || '';
this.childSuites = [];
this.specs = [];
this.beforeAll = [];
this.afterAll = [];
this.beforeEach = [];
this.afterEach = [];
this.duration = 0;
}
pushSpec(spec) {
this.specs.push(spec);
}
removeSpec(desc) {
this.specs = this.specs.filter((item, index) => {
return item.description !== desc;
});
}
getSpecsNum() {
return this.specs.length;
}
isRun(coreContext) {
const configService = coreContext.getDefaultService('config');
const suiteService = coreContext.getDefaultService('suite');
const specService = coreContext.getDefaultService('spec');
let breakOnError = configService.isBreakOnError();
let isError = specService.getStatus();
return breakOnError && isError;
}
run(coreContext) {
const suiteService = coreContext.getDefaultService('suite');
suiteService.setCurrentRunningSuite(this);
if (this.description !== '') {
coreContext.fireEvents('suite', 'suiteStart', this);
}
this.runHookFunc('beforeAll');
if (this.specs.length > 0) {
const configService = coreContext.getDefaultService('config');
if (configService.isRandom()) {
this.specs.sort(function () {
return Math.random().toFixed(1) > 0.5 ? -1 : 1;
});
}
for (let spec in this.specs) {
let isBreakOnError = this.isRun(coreContext);
if (isBreakOnError) {
break;
}
this.runHookFunc('beforeEach');
spec.run(coreContext);
this.runHookFunc('afterEach');
}
}
if (this.childSuites.length > 0) {
for (let suite in this.childSuites) {
let isBreakOnError = this.isRun(coreContext);
if (isBreakOnError) {
break;
}
suite.run(coreContext);
suiteService.setCurrentRunningSuite(suite);
}
}
this.runHookFunc('afterAll');
if (this.description !== '') {
coreContext.fireEvents('suite', 'suiteDone');
}
}
async asyncRun(coreContext) {
const suiteService = coreContext.getDefaultService('suite');
suiteService.setCurrentRunningSuite(this);
suiteService.suitesStack.push(this);
if (this.description !== '') {
await coreContext.fireEvents('suite', 'suiteStart', this);
}
await this.runAsyncHookFunc('beforeAll');
if (this.specs.length > 0) {
const configService = coreContext.getDefaultService('config');
if (configService.isRandom()) {
this.specs.sort(function () {
return Math.random().toFixed(1) > 0.5 ? -1 : 1;
});
}
for (let i = 0; i < this.specs.length; i++) {
// 遇错即停模式,发现用例有问题直接返回不在执行后面的it
let isBreakOnError = this.isRun(coreContext);
if (isBreakOnError) {
console.log("break description :" + this.description);
break;
}
await this.runAsyncHookFunc('beforeEach');
await this.specs[i].asyncRun(coreContext);
await this.runAsyncHookFunc('afterEach');
}
}
if (this.childSuites.length > 0) {
for (let i = 0; i < this.childSuites.length; i++) {
// 遇错即停模式, 发现用例有问题直接返回不在执行后面的description
let isBreakOnError = this.isRun(coreContext);
if (isBreakOnError) {
console.log("break description :" + this.description);
break;
}
await this.childSuites[i].asyncRun(coreContext);
}
}
await this.runAsyncHookFunc('afterAll');
if (this.description !== '') {
await coreContext.fireEvents('suite', 'suiteDone');
let childSuite = suiteService.suitesStack.pop();
if (suiteService.suitesStack.length === 0) {
suiteService.suitesStack.push(childSuite);
}
if (suiteService.suitesStack.length > 1) {
suiteService.setCurrentRunningSuite(suiteService.suitesStack.pop());
} else {
let currentRunningSuite = suiteService.suitesStack.pop();
suiteService.setCurrentRunningSuite(currentRunningSuite);
suiteService.suitesStack.push(currentRunningSuite);
}
}
}
runHookFunc(hookName) {
if (this[hookName] && this[hookName].length > 0) {
this[hookName].forEach(func => {
try {
func();
} catch (e) {
console.error(e);
}
});
}
}
runAsyncHookFunc(hookName) {
if (this[hookName] && this[hookName].length > 0) {
return new Promise(async resolve => {
for (let i = 0; i < this[hookName].length; i++) {
try {
await this[hookName][i]();
} catch (e) {
console.error(e);
}
}
resolve();
});
}
}
};
class SpecService {
constructor(attr) {
this.id = attr.id;
this.totalTest = 0;
this.hasError = false;
}
init(coreContext) {
this.coreContext = coreContext;
}
setCurrentRunningSpec(spec) {
this.currentRunningSpec = spec;
}
setStatus(obj) {
this.hasError = obj;
}
getStatus() {
return this.hasError;
}
getTestTotal() {
return this.totalTest;
}
getCurrentRunningSpec() {
return this.currentRunningSpec;
}
it(desc, filter, func) {
const configService = this.coreContext.getDefaultService('config');
const currentSuiteName = this.coreContext.getDefaultService('suite').getCurrentRunningSuite().description;
if (configService.filterDesc(currentSuiteName, desc, filter, this.coreContext)) {
console.info('filter it :' + desc);
} else {
let processedFunc = processFunc(this.coreContext, func);
const spec = new SpecService.Spec({description: desc, fi: filter, fn: processedFunc});
const suiteService = this.coreContext.getDefaultService('suite');
if (typeof this.coreContext.getServices('dataDriver') !== 'undefined' && configService['dryRun'] !== 'true') {
let specStress = this.coreContext.getServices('dataDriver').dataDriver.getSpecStress(desc);
for (let i = 1; i < specStress; i++) {
this.totalTest++;
suiteService.getCurrentRunningSuite().pushSpec(spec);
}
}
// dryRun 状态下不统计压力测试重复数据
if (configService['dryRun'] !== 'true') {
let stress = configService.getStress(); // 命令配置压力测试
console.info('stress length :' + stress);
for (let i = 1; i < stress; i++) {
this.totalTest++;
suiteService.getCurrentRunningSuite().pushSpec(spec);
}
}
this.totalTest++;
suiteService.getCurrentRunningSuite().pushSpec(spec);
}
}
apis() {
const _this = this;
return {
it: function (desc, filter, func) {
return _this.it(desc, filter, func);
}
};
}
}
SpecService.Spec = class {
constructor(attrs) {
this.description = attrs.description || '';
this.fi = attrs.fi;
this.fn = attrs.fn || function () {
};
this.result = {
failExpects: [],
passExpects: []
};
this.error = undefined;
this.duration = 0;
this.startTime = 0;
this.isExecuted = false; // 当前用例是否执行
}
setResult(coreContext) {
const specService = coreContext.getDefaultService('spec');
if (this.result.failExpects.length > 0) {
this.result.pass = false;
specService.setStatus(true);
} else {
this.result.pass = true;
}
console.info('testcase ' + this.description + ' result:' + this.result.pass);
}
run(coreContext) {
const specService = coreContext.getDefaultService('spec');
specService.setCurrentRunningSpec(this);
coreContext.fireEvents('spec', 'specStart', this);
this.isExecuted = true;
try {
let dataDriver = coreContext.getServices('dataDriver');
if (typeof dataDriver === 'undefined') {
this.fn();
} else {
let suiteParams = dataDriver.dataDriver.getSuiteParams();
let specParams = dataDriver.dataDriver.getSpecParams();
console.info('[suite params] ' + JSON.stringify(suiteParams));
console.info('[spec params] ' + JSON.stringify(specParams));
if (this.fn.length === 0) {
this.fn();
} else if (specParams.length === 0) {
this.fn(suiteParams);
} else {
specParams.forEach(paramItem => this.fn(Object.assign({}, paramItem, suiteParams)));
}
}
this.setResult(coreContext);
} catch (e) {
this.error = e;
specService.setStatus(true);
}
coreContext.fireEvents('spec', 'specDone', this);
}
async asyncRun(coreContext) {
const specService = coreContext.getDefaultService('spec');
specService.setCurrentRunningSpec(this);
await coreContext.fireEvents('spec', 'specStart', this);
try {
let dataDriver = coreContext.getServices('dataDriver');
if (typeof dataDriver === 'undefined') {
await this.fn();
this.setResult(coreContext);
} else {
let suiteParams = dataDriver.dataDriver.getSuiteParams();
let specParams = dataDriver.dataDriver.getSpecParams();
console.info('[suite params] ' + JSON.stringify(suiteParams));
console.info('[spec params] ' + JSON.stringify(specParams));
if (this.fn.length === 0) {
await this.fn();
this.setResult(coreContext);
} else if (specParams.length === 0) {
await this.fn(suiteParams);
this.setResult(coreContext);
} else {
for (const paramItem of specParams) {
await this.fn(Object.assign({}, paramItem, suiteParams));
this.setResult(coreContext);
}
}
}
} catch (e) {
if (e instanceof AssertException) {
this.fail = e;
specService.setStatus(true);
} else {
this.error = e;
specService.setStatus(true);
}
}
this.isExecuted = true;
await coreContext.fireEvents('spec', 'specDone', this);
}
filterCheck(coreContext) {
const specService = coreContext.getDefaultService('spec');
specService.setCurrentRunningSpec(this);
return true;
}
addExpectationResult(expectResult) {
if (this.result.failExpects.length === 0) {
this.result.failExpects.push(expectResult);
}
throw new AssertException(expectResult.message);
}
};
class ExpectService {
constructor(attr) {
this.id = attr.id;
this.matchers = {};
}
expect(actualValue) {
return this.wrapMatchers(actualValue);
}
init(coreContext) {
this.coreContext = coreContext;
this.addMatchers(this.basicMatchers());
}
addMatchers(matchers) {
for (const matcherName in matchers) {
if (Object.prototype.hasOwnProperty.call(matchers, matcherName)) {
this.matchers[matcherName] = matchers[matcherName];
}
}
}
basicMatchers() {
return {
assertTrue: function (actualValue) {
return {
pass: (actualValue) === true,
message: 'expect true, actualValue is ' + actualValue
};
},
assertEqual: function (actualValue, args) {
return {
pass: (actualValue) === args[0],
expectValue: args[0],
message: 'expect ' + actualValue + ' equals ' + args[0]
};
},
assertThrow: function (actual, args) {
const result = {
pass: false
};
if (typeof actual !== 'function') {
result.message = 'toThrow\'s Actual should be a Function';
} else {
let hasThrow = false;
let throwError;
try {
actual();
} catch (e) {
hasThrow = true;
throwError = e;
}
if (!hasThrow) {
result.message = 'function did not throw an exception';
} else if (throwError && throwError.message === args[0]) {
result.pass = true;
} else {
result.message = `expect to throw ${args[0]} , actual throw ${throwError.message}`;
}
}
return result;
}
};
}
wrapMatchers(actualValue) {
const _this = this;
const wrappedMatchers = {
// 翻转标识
isNot: false,
// 翻转方法
not: function () {
this.isNot = true;
return this;
}
};
const specService = _this.coreContext.getDefaultService('spec');
const currentRunningSpec = specService.getCurrentRunningSpec();
for (const matcherName in this.matchers) {
let result = Object.prototype.hasOwnProperty.call(this.matchers, matcherName);
if (!result) {
continue;
}
if (matcherName.search('assertPromise') == 0) {
wrappedMatchers[matcherName] = async function () {
await _this.matchers[matcherName](actualValue, arguments).then(function (result) {
if (wrappedMatchers.isNot) {
result.pass = !result.pass;
}
result.actualValue = actualValue;
result.checkFunc = matcherName;
if (!result.pass) {
currentRunningSpec.addExpectationResult(result);
}
});
};
} else {
wrappedMatchers[matcherName] = function () {
const result = _this.matchers[matcherName](actualValue, arguments);
if (wrappedMatchers.isNot) {
result.pass = !result.pass;
}
result.actualValue = actualValue;
result.checkFunc = matcherName;
if (!result.pass) {
currentRunningSpec.addExpectationResult(result);
}
};
}
}
return wrappedMatchers;
}
apis() {
const _this = this;
return {
expect: function (actualValue) {
return _this.expect(actualValue);
}
};
}
}
class ReportService {
constructor(attr) {
this.id = attr.id;
}
init(coreContext) {
this.coreContext = coreContext;
this.specService = this.coreContext.getDefaultService('spec');
this.suiteService = this.coreContext.getDefaultService('suite');
this.duration = 0;
}
taskStart() {
console.info('[start] start run suites');
}
async suiteStart() {
console.info('[suite start]' + this.suiteService.getCurrentRunningSuite().description);
}
async specStart() {
console.info('start running case \'' + this.specService.currentRunningSpec.description + '\'');
this.index = this.index + 1;
let spec = this.specService.currentRunningSpec;
spec.startTime = await SysTestKit.getRealTime();
}
async specDone() {
let msg = '';
let spec = this.specService.currentRunningSpec;
let suite = this.suiteService.currentRunningSuite;
spec.duration = await SysTestKit.getRealTime() - spec.startTime;
suite.duration += spec.duration;
if (spec.error) {
this.formatPrint('error', spec.description + ' ; consuming ' + spec.duration + 'ms');
this.formatPrint('errorDetail', spec.error);
} else if (spec.result) {
if (spec.result.failExpects.length > 0) {
this.formatPrint('fail', spec.description + ' ; consuming ' + spec.duration + 'ms');
spec.result.failExpects.forEach(failExpect => {
msg = failExpect.message || ('expect ' + failExpect.actualValue + ' '
+ failExpect.checkFunc + ' ' + (failExpect.expectValue));
this.formatPrint('failDetail', msg);
});
} else {
this.formatPrint('pass', spec.description + ' ; consuming ' + spec.duration + 'ms');
}
}
this.formatPrint(this.specService.currentRunningSpec.error, msg);
}
suiteDone() {
let suite = this.suiteService.currentRunningSuite;
console.info(`[suite end] ${suite.description} consuming ${suite.duration} ms`);
}
taskDone() {
let msg = '';
let summary = this.suiteService.getSummary();
msg = 'total cases:' + summary.total + ';failure ' + summary.failure + ',' + 'error ' + summary.error;
msg += ',pass ' + summary.pass + '; consuming ' + summary.duration + 'ms';
console.info(msg);
console.info('[end] run suites end');
}
incorrectFormat() {
if (this.coreContext.getDefaultService('config').filterValid.length !== 0) {
this.coreContext.getDefaultService('config').filterValid.forEach(function (item) {
console.info('this param ' + item + ' is invalid');
});
}
}
formatPrint(type, msg) {
switch (type) {
case 'pass':
console.info('[pass]' + msg);
break;
case 'fail':
console.info('[fail]' + msg);
break;
case 'failDetail':
console.info('[failDetail]' + msg);
break;
case 'error':
console.info('[error]' + msg);
break;
case 'errorDetail':
console.info('[errorDetail]' + msg);
break;
}
}
sleep(numberMillis) {
var now = new Date();
var exitTime = now.getTime() + numberMillis;
while (true) {
now = new Date();
if (now.getTime() > exitTime) {
return;
}
}
}
}
export {
SuiteService,
SpecService,
ExpectService,
ReportService
};

View File

@ -0,0 +1 @@
../../@ohos+hypium@1.0.6/oh_modules/@ohos/hypium

View File

@ -0,0 +1 @@
../.ohpm/@ohos+hypium@1.0.6/oh_modules/@ohos/hypium

View File

@ -11,7 +11,6 @@
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
@ -34,17 +33,12 @@
]
}
],
"requestPermissions":[
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.GET_NETWORK_INFO"
},
{
"name": "ohos.permission.CAMERA",
},
{
"name": "ohos.permission.GET_WIFI_INFO"
@ -70,32 +64,32 @@
{
"name": "ohos.permission.MEDIA_LOCATION"
},
{
"name": "ohos.permission.WRITE_MEDIA"
},
{
"name": "ohos.permission.READ_MEDIA"
},
// {
// "name": "ohos.permission.READ_MEDIA",
// "reason": "$string:module_desc",
// "usedScene": {
// "abilities": [
// "MainAbility"
// ],
// "when": "always"
// }
// },
// {
// "name": "ohos.permission.WRITE_MEDIA",
// "reason": "$string:module_desc",
// "usedScene": {
// "abilities": [
// "MainAbility"
// ],
// "when": "always"
// }
// },
{
"name": "ohos.permission.WRITE_MEDIA"
},
{
"name": "ohos.permission.READ_MEDIA"
},
// {
// "name": "ohos.permission.READ_MEDIA",
// "reason": "$string:module_desc",
// "usedScene": {
// "abilities": [
// "MainAbility"
// ],
// "when": "always"
// }
// },
// {
// "name": "ohos.permission.WRITE_MEDIA",
// "reason": "$string:module_desc",
// "usedScene": {
// "abilities": [
// "MainAbility"
// ],
// "when": "always"
// }
// },
{
"name": "ohos.permission.FILE_ACCESS_MANAGER",
"reason": "$string:module_desc",

View File

@ -37,14 +37,6 @@
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.GET_WIFI_INFO"
}, {
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.GET_WIFI_INFO",
},
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC",
},

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD>2\&3<><06><> <20><>¢<EFBFBD>

Binary file not shown.

View File

@ -0,0 +1 @@
σΣT&Η cFw*¬Χ'aυ

View File

@ -0,0 +1 @@
\<5C><><EFBFBD>P,<2C>{<0E>U<EFBFBD><55><EFBFBD>"<22>

View File

@ -0,0 +1 @@
■╕7╙▄и⌠╣≤Жv(еБ╕