第一次提交
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Use these variables when you tailor your ArkTS code. They must be of the const type.
|
||||
*/
|
||||
export const HAR_VERSION = '1.0.21';
|
||||
export const BUILD_MODE_NAME = 'debug';
|
||||
export const DEBUG = true;
|
||||
export const TARGET_NAME = 'default';
|
||||
|
||||
/**
|
||||
* BuildProfile Class is used only for compatibility purposes.
|
||||
*/
|
||||
export default class BuildProfile {
|
||||
static readonly HAR_VERSION = HAR_VERSION;
|
||||
static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
|
||||
static readonly DEBUG = DEBUG;
|
||||
static readonly TARGET_NAME = TARGET_NAME;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
## 1.0.21
|
||||
- mock支持多参数
|
||||
- describe中异步函数抛出日志信息
|
||||
- 修复多测试套时,执行单个测试套会打印其他测试套的日志信息
|
||||
## 1.0.14
|
||||
- 堆栈信息打印到cmd
|
||||
## 1.0.15
|
||||
- 支持获取测试代码的失败堆栈信息
|
||||
- mock代码迁移至harmock包
|
||||
- 适配arkts语法
|
||||
- 修复覆盖率数据容易截断的bug
|
||||
## 1.0.16
|
||||
- 修改覆盖率文件生成功能
|
||||
- 修改静态方法无法ignoreMock函数
|
||||
- ## 1.0.17
|
||||
- 修改not断言失败提示日志
|
||||
- 自定义错误message信息
|
||||
- 添加xdescribe, xit API功能
|
||||
- ## 1.0.18
|
||||
- 添加全局变量存储API get set
|
||||
- 自定义断言功能
|
||||
## 1.0.18-rc.0
|
||||
添加框架worker执行能力
|
||||
## 1.0.19
|
||||
规范日志格式
|
||||
# 1.0.20
|
||||
代码告警整改
|
||||
@@ -0,0 +1,177 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -0,0 +1,224 @@
|
||||
<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后缀
|
||||
```
|
||||
|
||||
## 安装使用
|
||||
|
||||
```javascript
|
||||
ohpm install @ohos/hypium
|
||||
```
|
||||
|
||||
***
|
||||
- 在DevEco Studio内使用Hypium
|
||||
- 工程级package.json内配置:
|
||||
```json
|
||||
"dependencies": {
|
||||
"@ohos/hypium": "1.0.21"
|
||||
}
|
||||
```
|
||||
注:
|
||||
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。
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
string page_show 0x02000000
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"apiType": "stageMode",
|
||||
"buildOption": {
|
||||
},
|
||||
"buildOptionSet": [
|
||||
{
|
||||
"name": "release",
|
||||
"arkOptions": {
|
||||
"obfuscation": {
|
||||
"ruleOptions": {
|
||||
"enable": true,
|
||||
"files": [
|
||||
"./obfuscation-rules.txt"
|
||||
]
|
||||
},
|
||||
"consumerFiles": [
|
||||
"./consumer-rules.txt"
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"name": "default"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { harTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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 { xdescribe, xit, describe, it } from './index';
|
||||
|
||||
|
||||
|
||||
export function beforeItSpecified(testCaseNames: Array<string> | string, callback: Function): void
|
||||
|
||||
export function afterItSpecified(testCaseNames: Array<string> | 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 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 | Function): void
|
||||
assertUndefined(): void
|
||||
assertLargerOrEqual(expectValue: number): void
|
||||
assertLessOrEqual(expectValue: number): void
|
||||
assertNaN(): void
|
||||
assertNegUnlimited(): void
|
||||
assertPosUnlimited(): void
|
||||
not(): Assert;
|
||||
assertDeepEquals(expectValue: any): void
|
||||
assertPromiseIsPending(): Promise<void>
|
||||
assertPromiseIsRejected(): Promise<void>
|
||||
assertPromiseIsRejectedWith(expectValue?: any): Promise<void>
|
||||
assertPromiseIsRejectedWithError(...expectValue): Promise<void>
|
||||
assertPromiseIsResolved(): Promise<void>
|
||||
assertPromiseIsResolvedWith(expectValue?: any): Promise<void>
|
||||
message(msg: string): Assert
|
||||
}
|
||||
|
||||
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 getDescribeName(): string;
|
||||
static getItName(): string;
|
||||
static getItAttribute(): TestType | Size | Level
|
||||
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
|
||||
static set(key: string, value: any): void
|
||||
static get(key: string): any
|
||||
static registerAssert(customAssertion: Function): void
|
||||
static unregisterAssert(customAssertion: string | Function): void
|
||||
static hypiumWorkerTest(abilityDelegator: Object, abilityDelegatorArguments: Object, testsuite: Function, workerPort: Object): void;
|
||||
static hypiumInitWorkers(abilityDelegator: Object, scriptURL: string, workerNum: number, params: Object): void;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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 {TestType, Size, Level, DEFAULT} 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';
|
||||
export { xdescribe, xit, describe, it } from './index.ts';
|
||||
|
||||
export declare class Hypium {
|
||||
static setData(data: Object): void
|
||||
static setTimeConfig(systemTime: Object): void
|
||||
static hypiumTest(abilityDelegator: Object, abilityDelegatorArguments: Object, testsuite: Function): void
|
||||
static set(key: string, value: Object): void
|
||||
static get(key: string): Object
|
||||
static registerAssert(customAssertion: Function): void
|
||||
static unregisterAssert(customAssertion: string | Function): void
|
||||
static hypiumWorkerTest(abilityDelegator: Object, abilityDelegatorArguments: Object,
|
||||
testsuite: Function, workerPort: Object): void;
|
||||
static hypiumInitWorkers(abilityDelegator: Object, scriptURL: string, workerNum: number, params: Object): void;
|
||||
}
|
||||
|
||||
export {
|
||||
Core,
|
||||
DataDriver,
|
||||
ExpectExtend,
|
||||
OhReport,
|
||||
TestType,
|
||||
Size,
|
||||
Level,
|
||||
DEFAULT
|
||||
};
|
||||
|
||||
type allExpectType = Object | undefined | null
|
||||
|
||||
export declare function beforeItSpecified(testCaseNames: Array<string> | string, callback: Function): void
|
||||
|
||||
export declare function afterItSpecified(testCaseNames: Array<string> | string, callback: Function): void
|
||||
|
||||
export declare function beforeEach(callback: Function): void
|
||||
|
||||
export declare function afterEach(callback: Function): void
|
||||
|
||||
export declare function beforeAll(callback: Function): void
|
||||
|
||||
export declare function afterAll(callback: Function): void
|
||||
|
||||
export declare interface Assert {
|
||||
assertClose(expectValue: number, precision: number): void
|
||||
assertContain(expectValue: allExpectType): void
|
||||
assertEqual(expectValue: allExpectType): void
|
||||
assertFail(): void
|
||||
assertFalse(): void
|
||||
assertTrue(): void
|
||||
assertInstanceOf(expectValue: string): void
|
||||
assertLarger(expectValue: number): void
|
||||
assertLess(expectValue: number): void
|
||||
assertNull(): void
|
||||
assertThrowError(expectValue: string | Function): void
|
||||
assertUndefined(): void
|
||||
assertLargerOrEqual(expectValue: number):void
|
||||
assertLessOrEqual(expectValue: number):void
|
||||
assertNaN():void
|
||||
assertNegUnlimited(): void
|
||||
assertPosUnlimited(): void
|
||||
not(): Assert;
|
||||
assertDeepEquals(expectValue: allExpectType):void
|
||||
assertPromiseIsPending(): Promise<void>
|
||||
assertPromiseIsRejected(): Promise<void>
|
||||
assertPromiseIsRejectedWith(expectValue?: allExpectType): Promise<void>
|
||||
assertPromiseIsRejectedWithError(...expectValue: allExpectType[]): Promise<void>
|
||||
assertPromiseIsResolved(): Promise<void>
|
||||
assertPromiseIsResolvedWith(expectValue?: allExpectType): Promise<void>
|
||||
message(msg: string): Assert
|
||||
}
|
||||
|
||||
export declare function expect(actualValue?: allExpectType): Assert
|
||||
|
||||
export declare class ArgumentMatchers {
|
||||
public static any: allExpectType;
|
||||
public static anyString: string;
|
||||
public static anyBoolean: Boolean;
|
||||
public static anyNumber: Number;
|
||||
public static anyObj: Object;
|
||||
public static anyFunction: Function;
|
||||
public static matchRegexs(regex: RegExp): void
|
||||
}
|
||||
|
||||
declare interface whenResult {
|
||||
afterReturn: (value: allExpectType) => allExpectType
|
||||
afterReturnNothing: () => undefined
|
||||
afterAction: (action: allExpectType) => allExpectType
|
||||
afterThrow: (e_msg: string) => string
|
||||
}
|
||||
|
||||
export declare function when(f:Function): (...args: (allExpectType | void)[]) => whenResult
|
||||
|
||||
export declare interface VerificationMode {
|
||||
times(count: Number): void
|
||||
never(): void
|
||||
once(): void
|
||||
atLeast(count: Number): void
|
||||
atMost(count: Number): void
|
||||
}
|
||||
|
||||
export declare class MockKit {
|
||||
constructor()
|
||||
mockFunc(obj: Object, func: Function): Function
|
||||
mockObject(obj: Object): Object
|
||||
verify(methodName: String, argsArray: Array<allExpectType>): VerificationMode
|
||||
ignoreMock(obj: Object, func: Function): void
|
||||
clear(obj: Object): void
|
||||
clearAll(): void
|
||||
}
|
||||
|
||||
export declare class SysTestKit {
|
||||
static getDescribeName(): string;
|
||||
static getItName(): string;
|
||||
static getItAttribute(): TestType | Size | Level
|
||||
static actionStart(tag: string): void
|
||||
static actionEnd(tag: string): void
|
||||
static existKeyword(keyword: string, timeout?: number): boolean
|
||||
}
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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, TAG, PrintTag } 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, beforeItSpecified, afterItSpecified, xdescribe, xit } from './src/main/interface';
|
||||
import { MockKit, when } from './src/main/module/mock/MockKit';
|
||||
import ArgumentMatchers from './src/main/module/mock/ArgumentMatchers';
|
||||
import worker from '@ohos.worker';
|
||||
|
||||
class Hypium {
|
||||
static context = new Map();
|
||||
static setData(data) {
|
||||
const core = Core.getInstance();
|
||||
const dataDriver = new DataDriver({ data });
|
||||
core.addService('dataDriver', dataDriver);
|
||||
}
|
||||
|
||||
static setTimeConfig(systemTime) {
|
||||
SysTestKit.systemTime = systemTime;
|
||||
}
|
||||
|
||||
static set(key, value) {
|
||||
Hypium.context.set(key, value);
|
||||
}
|
||||
|
||||
static get(key) {
|
||||
return Hypium.context.get(key);
|
||||
}
|
||||
|
||||
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');
|
||||
if (abilityDelegatorArguments !== null) {
|
||||
let testParameters = configService.translateParams(abilityDelegatorArguments.parameters);
|
||||
console.info(`${TAG}parameters:${JSON.stringify(testParameters)}`);
|
||||
configService.setConfig(testParameters);
|
||||
}
|
||||
testsuite();
|
||||
core.execute(abilityDelegator);
|
||||
}
|
||||
static async hypiumInitWorkers(abilityDelegator, scriptURL, workerNum = 8, params) {
|
||||
console.info(`${TAG}, hypiumInitWorkers call,${scriptURL}`);
|
||||
let workerPromiseArray = [];
|
||||
|
||||
// 开始统计时间
|
||||
let startTime = await SysTestKit.getRealTime();
|
||||
for (let i = 0; i < workerNum; i++) {
|
||||
// 创建worker线程
|
||||
const workerPromise = Hypium.createWorkerPromise(scriptURL, i, params);
|
||||
workerPromiseArray.push(workerPromise);
|
||||
}
|
||||
const ret = {total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0};
|
||||
Promise.all(workerPromiseArray).then(async (items) => {
|
||||
console.info(`${TAG}, all result from workers, ${JSON.stringify(items)}`);
|
||||
let allItemList = new Array();
|
||||
// 统计执行结果
|
||||
Hypium.handleWorkerTestResult(ret, allItemList, items);
|
||||
console.info(`${TAG}, all it result, ${JSON.stringify(allItemList)}`);
|
||||
// 统计用例执行结果
|
||||
const retResult = {total: 0, failure: 0, error: 0, pass: 0, ignore: 0, duration: 0};
|
||||
// 标记用例执行结果
|
||||
Hypium.configWorkerItTestResult(retResult, allItemList);
|
||||
// 打印用例结果
|
||||
Hypium.printWorkerTestResult(abilityDelegator, allItemList);
|
||||
// 用例执行完成统计时间
|
||||
let endTime = await SysTestKit.getRealTime();
|
||||
const taskConsuming = endTime - startTime;
|
||||
const message =
|
||||
`\n${PrintTag.OHOS_REPORT_ALL_RESULT}: stream=Test run: runTimes: ${ret.total},total: ${retResult.total}, Failure: ${retResult.failure}, Error: ${retResult.error}, Pass: ${retResult.pass}, Ignore: ${retResult.ignore}` +
|
||||
`\n${PrintTag.OHOS_REPORT_ALL_CODE}: ${retResult.failure > 0 || retResult.error > 0 ? -1 : 0}` +
|
||||
`\n${PrintTag.OHOS_REPORT_ALL_STATUS}: taskconsuming=${taskConsuming > 0 ? taskConsuming : ret.duration}`;
|
||||
abilityDelegator.printSync(message);
|
||||
console.info(`${TAG}, [end] you worker test`);
|
||||
abilityDelegator.finishTest('you worker test finished!!!', 0, () => {});
|
||||
}).catch((e) => {
|
||||
console.info(`${TAG}, [end] error you worker test, ${JSON.stringify(e)}`);
|
||||
abilityDelegator.finishTest('you worker test error finished!!!', 0, () => {});
|
||||
}).finally(() => {
|
||||
console.info(`${TAG}, all promise finally end`);
|
||||
});
|
||||
}
|
||||
// 创建worker线程
|
||||
static createWorkerPromise(scriptURL, i, params) {
|
||||
console.info(`${TAG}, createWorkerPromiser, ${scriptURL}, ${i}`);
|
||||
const workerPromise = new Promise((resolve, reject) => {
|
||||
const workerInstance = new worker.ThreadWorker(scriptURL, {name: `worker_${i}`});
|
||||
console.info(`${TAG}, send data to worker`);
|
||||
// 发送数据到worker线程中
|
||||
workerInstance.postMessage(params);
|
||||
workerInstance.onmessage = function (e) {
|
||||
let currentThreadName = e.data?.currentThreadName;
|
||||
console.info(`${TAG}, receview data from ${currentThreadName}, ${JSON.stringify(e.data)}`);
|
||||
//
|
||||
resolve(e.data?.summary);
|
||||
console.info(`${TAG}, ${currentThreadName} finish`);
|
||||
workerInstance.terminate();
|
||||
};
|
||||
workerInstance.onerror = function (e) {
|
||||
console.info(`${TAG}, worker error, ${JSON.stringify(e)}`);
|
||||
reject(e);
|
||||
workerInstance.terminate();
|
||||
};
|
||||
workerInstance.onmessageerror = function (e) {
|
||||
console.info(`${TAG}, worker message error, ${JSON.stringify(e)}`);
|
||||
reject(e);
|
||||
workerInstance.terminate();
|
||||
};
|
||||
});
|
||||
return workerPromise;
|
||||
}
|
||||
static handleWorkerTestResult(ret, allItemList, items) {
|
||||
console.info(`${TAG}, handleWorkerTestResult, ${JSON.stringify(items)}`);
|
||||
for (const {total, failure, error, pass, ignore, duration, itItemList} of items) {
|
||||
ret.total += total;
|
||||
ret.failure += failure;
|
||||
ret.error += error;
|
||||
ret.pass += pass;
|
||||
ret.ignore += ignore;
|
||||
ret.duration += duration;
|
||||
Hypium.handleItResult(allItemList, itItemList);
|
||||
}
|
||||
}
|
||||
static handleItResult(allItemList, itItemList) {
|
||||
// 遍历所有的用例结果统计最终结果
|
||||
for (const {currentThreadName, description, result} of itItemList) {
|
||||
let item = allItemList.find((it) => it.description === description);
|
||||
if (item) {
|
||||
let itResult = item.result;
|
||||
// 当在worker中出现一次failure就标记为failure, 出现一次error就标记为error, 所有线程都pass才标记为pass
|
||||
if (itResult === 0) {
|
||||
item.result = result;
|
||||
item.currentThreadName = currentThreadName;
|
||||
}
|
||||
} else {
|
||||
let it = {
|
||||
description: description,
|
||||
currentThreadName: currentThreadName,
|
||||
result: result
|
||||
};
|
||||
allItemList.push(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
static configWorkerItTestResult(retResult, allItemList) {
|
||||
console.info(`${TAG}, configWorkerItTestResult, ${JSON.stringify(allItemList)}`);
|
||||
for (const {currentThreadName, description, result} of allItemList) {
|
||||
console.info(`${TAG}, description, ${description}, result,${result}`);
|
||||
retResult.total ++;
|
||||
if (result === 0) {
|
||||
retResult.pass ++;
|
||||
} else if (result === -1) {
|
||||
retResult.error ++;
|
||||
} else if (result === -2) {
|
||||
retResult.failure ++;
|
||||
} else {
|
||||
retResult.ignore ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
static printWorkerTestResult(abilityDelegator, allItemList) {
|
||||
console.info(`${TAG}, printWorkerTestResult, ${JSON.stringify(allItemList)}`);
|
||||
let index = 1;
|
||||
for (const {currentThreadName, description, result} of allItemList) {
|
||||
console.info(`${TAG}, description print, ${description}, result,${result}`);
|
||||
let itArray = description.split('#');
|
||||
let des;
|
||||
let itName;
|
||||
if (itArray.length > 1) {
|
||||
des = itArray[0];
|
||||
itName = itArray[1];
|
||||
} else if (itArray.length > 1) {
|
||||
des = itArray[0];
|
||||
itName = itArray[0];
|
||||
} else {
|
||||
des = 'undefined';
|
||||
itName = 'undefined';
|
||||
}
|
||||
|
||||
let msg = `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: class=${des}`;
|
||||
msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: test=${itName}`;
|
||||
msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: current=${index}`;
|
||||
msg += `\n${PrintTag.OHOS_REPORT_WORKER_STATUS}: CODE=${result}`;
|
||||
abilityDelegator.printSync(msg);
|
||||
index ++;
|
||||
}
|
||||
}
|
||||
static hypiumWorkerTest(abilityDelegator, abilityDelegatorArguments, testsuite, workerPort) {
|
||||
console.info(`${TAG}, hypiumWorkerTest call`);
|
||||
SysTestKit.workerPort = workerPort;
|
||||
let currentWorkerName = workerPort.name;
|
||||
console.info(`${TAG}, hypiumWorkerTest_currentWorkerName: ${currentWorkerName}`);
|
||||
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
|
||||
|
||||
}
|
||||
|
||||
static registerAssert(customAssertion) {
|
||||
const core = Core.getInstance();
|
||||
const expectService = core.getDefaultService('expect');
|
||||
let matchers = {};
|
||||
matchers[customAssertion.name] = customAssertion;
|
||||
expectService.addMatchers(matchers);
|
||||
expectService.customMatchers.push(customAssertion.name);
|
||||
console.info(`${TAG}success to register the ${customAssertion.name}`);
|
||||
}
|
||||
|
||||
static unregisterAssert(customAssertion) {
|
||||
const core = Core.getInstance();
|
||||
const expectService = core.getDefaultService('expect');
|
||||
let customAssertionName = typeof customAssertion === 'function' ? customAssertion.name : customAssertion;
|
||||
expectService.removeMatchers(customAssertionName);
|
||||
console.info(`${TAG}success to unregister the ${customAssertionName}`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export {
|
||||
Hypium,
|
||||
Core,
|
||||
DEFAULT,
|
||||
TestType,
|
||||
Size,
|
||||
Level,
|
||||
DataDriver,
|
||||
ExpectExtend,
|
||||
OhReport,
|
||||
SysTestKit,
|
||||
describe, beforeAll, beforeEach, afterEach, afterAll, it, expect, beforeItSpecified, afterItSpecified, xdescribe, xit,
|
||||
MockKit, when,
|
||||
ArgumentMatchers
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 { TestType, Size, Level } from "./src/main/Constant";
|
||||
|
||||
export declare function xdescribe(testSuiteName: string, func: Function): void;
|
||||
|
||||
export declare namespace xdescribe {
|
||||
function reason(reason: string): any;
|
||||
};
|
||||
|
||||
export declare function describe(testSuiteName: string, func: Function): void;
|
||||
|
||||
export declare function xit(testCaseName: string, attribute: TestType | Size | Level, func: Function): void;
|
||||
|
||||
export declare namespace xit {
|
||||
function reason(reason: string): any;
|
||||
};
|
||||
|
||||
export declare function it(testCaseName: string, attribute: TestType | Size | Level, func: Function): void;
|
||||
@@ -0,0 +1,18 @@
|
||||
# Define project specific obfuscation rules here.
|
||||
# You can include the obfuscation configuration files in the current module's build-profile.json5.
|
||||
#
|
||||
# For more details, see
|
||||
# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
|
||||
|
||||
# Obfuscation options:
|
||||
# -disable-obfuscation: disable all obfuscations
|
||||
# -enable-property-obfuscation: obfuscate the property names
|
||||
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
|
||||
# -compact: remove unnecessary blank spaces and all line feeds
|
||||
# -remove-log: remove all console.* statements
|
||||
# -print-namecache: print the name cache that contains the mapping from the old names to new names
|
||||
# -apply-namecache: reuse the given cache file
|
||||
|
||||
# Keep options:
|
||||
# -keep-property-name: specifies property names that you want to keep
|
||||
# -keep-global-name: specifies names that you want to keep in the global scope
|
||||
@@ -0,0 +1 @@
|
||||
{"name":"@ohos/hypium","version":"1.0.21","description":"A unit test framework for OpenHarmony application","main":"index.js","keywords":["测试框架","except","mock"],"author":"huawei","license":"Apache-2.0","repository":"https://gitee.com/openharmony/testfwk_arkxtest","homepage":"https://gitee.com/openharmony/testfwk_arkxtest","dependencies":{},"metadata":{"sourceRoots":["./src/main"],"debug":true},"compatibleSdkVersion":11,"compatibleSdkType":"OpenHarmony","obfuscated":false}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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 TAG = '[Hypium]';
|
||||
|
||||
export const DEFAULT = 0B0000;
|
||||
|
||||
export class PrintTag {
|
||||
static OHOS_REPORT_WORKER_STATUS = 'OHOS_REPORT_WORKER_STATUS';
|
||||
static OHOS_REPORT_ALL_RESULT = 'OHOS_REPORT_ALL_RESULT';
|
||||
static OHOS_REPORT_ALL_CODE = 'OHOS_REPORT_ALL_CODE';
|
||||
static OHOS_REPORT_ALL_STATUS = 'OHOS_REPORT_ALL_STATUS';
|
||||
static OHOS_REPORT_RESULT = 'OHOS_REPORT_RESULT';
|
||||
static OHOS_REPORT_CODE = 'OHOS_REPORT_CODE';
|
||||
static OHOS_REPORT_STATUS = 'OHOS_REPORT_STATUS';
|
||||
static OHOS_REPORT_SUM = 'OHOS_REPORT_SUM';
|
||||
static OHOS_REPORT_STATUS_CODE = 'OHOS_REPORT_STATUS_CODE';
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
export const 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,
|
||||
};
|
||||
|
||||
export const LEVEL = {
|
||||
'0': 1 << 24,
|
||||
'1': 1 << 25,
|
||||
'2': 1 << 26,
|
||||
'3': 1 << 27,
|
||||
'4': 1 << 28,
|
||||
};
|
||||
|
||||
export const SIZE = {
|
||||
'small': 1 << 16,
|
||||
'medium': 1 << 17,
|
||||
'large': 1 << 18,
|
||||
};
|
||||
|
||||
export const KEYSET = [
|
||||
'-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', '-s skipMessage', '-s runSkipped',
|
||||
'class', 'notClass', 'suite', 'itName',
|
||||
'level', 'testType', 'size', 'timeout', 'dryRun', 'random',
|
||||
'breakOnError', 'stress', 'coverage', 'skipMessage', 'runSkipped'
|
||||
];
|
||||
@@ -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;
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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']();
|
||||
}
|
||||
}
|
||||
|
||||
incorrectTestSuiteFormat() {
|
||||
for (const monitor of this.eventMonitors) {
|
||||
monitor.incorrectTestSuiteFormat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { SpecEvent, TaskEvent, SuiteEvent };
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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 beforeItSpecified = function (itDescs, func) {
|
||||
return Reflect.has(core, 'beforeItSpecified') ? core.beforeItSpecified(itDescs, func) : (itDescs, func) => { };
|
||||
};
|
||||
|
||||
const afterItSpecified = function (itDescs, func) {
|
||||
return Reflect.has(core, 'afterItSpecified') ? core.afterItSpecified(itDescs, func) : (itDescs, 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) => { };
|
||||
};
|
||||
|
||||
const xdescribe = function (desc, func) {
|
||||
return Reflect.has(core, 'xdescribe') ? core.xdescribe(desc, func, null) : (desc, func, reason) => { };
|
||||
};
|
||||
xdescribe.reason = (reason) => {
|
||||
return (desc, func) => {
|
||||
return Reflect.has(core, 'xdescribe') ? core.xdescribe(desc, func, reason) : (desc, func, reason) => { };
|
||||
};
|
||||
};
|
||||
const xit = function (desc, filter, func) {
|
||||
return Reflect.has(core, 'xit') ? core.xit(desc, filter, func, null) : (desc, filter, func, reason) => { };
|
||||
};
|
||||
xit.reason = (reason) => {
|
||||
return (desc, filter, func) => {
|
||||
return Reflect.has(core, 'xit') ? core.xit(desc, filter, func, reason) : (desc, filter, func, reason) => { };
|
||||
};
|
||||
};
|
||||
|
||||
export {
|
||||
describe, it, beforeAll, beforeEach, afterEach, afterAll, expect, beforeItSpecified, afterItSpecified, xdescribe, xit
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"app": {
|
||||
"bundleName": "com.ohos.myapplication",
|
||||
"debug": true,
|
||||
"versionCode": 1000000,
|
||||
"versionName": "1.0.0",
|
||||
"minAPIVersion": 11,
|
||||
"targetAPIVersion": 11,
|
||||
"apiReleaseType": "Release",
|
||||
"compileSdkVersion": "4.1.7.5",
|
||||
"compileSdkType": "OpenHarmony",
|
||||
"appEnvironments": [],
|
||||
"bundleType": "app"
|
||||
},
|
||||
"module": {
|
||||
"name": "hypium",
|
||||
"type": "har",
|
||||
"deviceTypes": [
|
||||
"default",
|
||||
"tablet",
|
||||
"tv",
|
||||
"wearable",
|
||||
"car"
|
||||
],
|
||||
"packageName": "@ohos/hypium",
|
||||
"installationFree": false,
|
||||
"virtualMachine": "ark11.0.2.0",
|
||||
"compileMode": "esmodule",
|
||||
"dependencies": []
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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;
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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) {
|
||||
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;
|
||||
+35
@@ -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;
|
||||
+23
@@ -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;
|
||||
+23
@@ -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;
|
||||
+29
@@ -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;
|
||||
+23
@@ -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;
|
||||
+23
@@ -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;
|
||||
+23
@@ -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;
|
||||
+23
@@ -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;
|
||||
+23
@@ -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;
|
||||
+23
@@ -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;
|
||||
+23
@@ -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;
|
||||
+23
@@ -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;
|
||||
+42
@@ -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;
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.'};
|
||||
});
|
||||
}
|
||||
return actualPromise.then(
|
||||
function (got) {
|
||||
return {
|
||||
pass: false,
|
||||
message: 'expect isRejected, but actualValue is resolve'
|
||||
};
|
||||
},
|
||||
function () {
|
||||
return {pass: true, message: 'actualValue is isRejected'};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default assertPromiseIsRejected;
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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]));
|
||||
}
|
||||
|
||||
return actualPromise.then(
|
||||
function (got) {
|
||||
return {
|
||||
pass: false,
|
||||
message: tips(false) + ' but actualValue is 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;
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 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.'};
|
||||
});
|
||||
}
|
||||
return actualPromise.then(
|
||||
function (got) {
|
||||
return {
|
||||
pass: false,
|
||||
message: 'Expected a promise to be rejected but actualValue is 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 + '.'};
|
||||
}
|
||||
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}.`};
|
||||
}
|
||||
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.'};
|
||||
}
|
||||
return {pass: true, message: 'not equal type'};
|
||||
}
|
||||
|
||||
export default assertPromiseIsRejectedWithError;
|
||||
+40
@@ -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 assertPromiseIsResolved(actualPromise) {
|
||||
if (!isPromiseLike(actualPromise)) {
|
||||
return Promise.reject().then(function () {
|
||||
}, function () {
|
||||
return {pass: false, message: 'Expected not be called on a promise.'};
|
||||
});
|
||||
}
|
||||
|
||||
return actualPromise.then(
|
||||
function (got) {
|
||||
return {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;
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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]));
|
||||
}
|
||||
|
||||
return actualPromise.then(
|
||||
function (got) {
|
||||
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;
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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 message = '';
|
||||
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) {
|
||||
let type = typeof expected[0];
|
||||
if (type === 'function') {
|
||||
result = err.constructor.name === expected[0].name;
|
||||
message = 'expected throw failed , ' + err.constructor.name + ' is not ' + expected[0].name;
|
||||
} else if (type === 'string') {
|
||||
result = err.message.includes(expected[0]);
|
||||
message = 'expected throw failed , ' + err.message + ' is not ' + expected[0];
|
||||
}
|
||||
}
|
||||
return {
|
||||
pass: result,
|
||||
message: message
|
||||
};
|
||||
}
|
||||
|
||||
export default assertThrowError;
|
||||
+23
@@ -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;
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 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) {
|
||||
// obj.propertyIsEnumerable(sym)
|
||||
if (Object.prototype.propertyIsEnumerable.call(obj, sym)) {
|
||||
keys.push(sym);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
}
|
||||
export default DeepTypeUtils;
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 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) {
|
||||
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 if (aClassName == '[object BigInt]') {
|
||||
actualMsg = actualValue;
|
||||
} else if (aClassName == '[object Error]') {
|
||||
actualMsg = actualValue.message;
|
||||
} else if (aClassName == '[object ArrayBuffer]') {
|
||||
actualMsg = actualValue.byteLength;
|
||||
}
|
||||
else {
|
||||
actualMsg = JSON.stringify(actualValue);
|
||||
}
|
||||
if (bClassName == '[object Function]') {
|
||||
expectMsg = 'expected Function';
|
||||
} else if (bClassName == '[object Promise]') {
|
||||
expectMsg = 'expected Promise';
|
||||
} else if (bClassName == '[object Set]' || bClassName == '[object Map]') {
|
||||
expectMsg = JSON.stringify(Array.from(expected));
|
||||
} else if (bClassName == '[object RegExp]') {
|
||||
expectMsg = JSON.stringify(expected.source.replace('\\', ''));
|
||||
} else if (bClassName == '[object BigInt]') {
|
||||
expectMsg = expected;
|
||||
} else if (bClassName == '[object Error]') {
|
||||
expectMsg = expected.message;
|
||||
} else if (bClassName == '[object ArrayBuffer]') {
|
||||
expectMsg = expected.byteLength;
|
||||
}
|
||||
else {
|
||||
expectMsg = JSON.stringify(expected);
|
||||
}
|
||||
return actualMsg + ' is not deep equal ' + expectMsg;
|
||||
}
|
||||
|
||||
function eq(a, b) {
|
||||
let result = true;
|
||||
|
||||
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);
|
||||
// 不同类型不同对象
|
||||
if (aClassName !== bClassName) {
|
||||
return false;
|
||||
}
|
||||
if (aClassName === '[object String]' || aClassName === '[object Number]' || aClassName === '[object Date]' ||
|
||||
aClassName === '[object Boolean]' || aClassName === '[object ArrayBuffer]' ||
|
||||
aClassName === '[object RegExp]' || aClassName === '[object Error]') {
|
||||
result = isEqualSampleObj(a, b);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (typeof a !== 'object' || typeof b !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DeepTypeUtils.isDomNode(a) || DeepTypeUtils.isPromise(a) || DeepTypeUtils.isFunction(a)) {
|
||||
result = isEqualNodeOrPromiseOrFunction(a, b);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (aClassName === '[object Array]' || aClassName === '[object Map]' || aClassName === '[object Set]') {
|
||||
result = isEqualCollection(a, b);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = isEqualObj(a, b);
|
||||
return result;
|
||||
}
|
||||
|
||||
function isEqualNodeOrPromiseOrFunction(a, b) {
|
||||
let equalNodeOrPromiseOrFunction = true;
|
||||
if (DeepTypeUtils.isDomNode(a) && DeepTypeUtils.isDomNode(b)) {
|
||||
const aIsDomNode = DeepTypeUtils.isDomNode(a);
|
||||
const bIsDomNode = DeepTypeUtils.isDomNode(b);
|
||||
if (aIsDomNode && bIsDomNode) {
|
||||
// At first try to use DOM3 method isEqualNode
|
||||
equalNodeOrPromiseOrFunction = a.isEqualNode(b);
|
||||
return equalNodeOrPromiseOrFunction;
|
||||
}
|
||||
if (aIsDomNode || bIsDomNode) {
|
||||
equalNodeOrPromiseOrFunction = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (DeepTypeUtils.isPromise(a) && DeepTypeUtils.isPromise(b)) {
|
||||
const aIsPromise = DeepTypeUtils.isPromise(a);
|
||||
const bIsPromise = DeepTypeUtils.isPromise(b);
|
||||
// 俩个Promise对象
|
||||
if (aIsPromise && bIsPromise) {
|
||||
equalNodeOrPromiseOrFunction = a === b;
|
||||
return a === b;
|
||||
}
|
||||
}
|
||||
if (DeepTypeUtils.isFunction(a) && DeepTypeUtils.isFunction(b)) {
|
||||
// 俩个函数对象
|
||||
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)
|
||||
) {
|
||||
equalNodeOrPromiseOrFunction = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return equalNodeOrPromiseOrFunction;
|
||||
}
|
||||
|
||||
function isEqualCollection(a, b) {
|
||||
let equalCollection = true;
|
||||
// 获取a的对象名称
|
||||
const aClassName = Object.prototype.toString.call(a);
|
||||
const bClassName = Object.prototype.toString.call(b);
|
||||
// 都是数组
|
||||
if (aClassName === '[object Array]') {
|
||||
equalCollection = isEqualArray(a, b);
|
||||
return equalCollection;
|
||||
}
|
||||
|
||||
// 都是Map
|
||||
if (DeepTypeUtils.isMap(a) && DeepTypeUtils.isMap(b)) {
|
||||
equalCollection = isEqualMap(a, b);
|
||||
return equalCollection;
|
||||
}
|
||||
|
||||
// 都是Set
|
||||
if (DeepTypeUtils.isSet(a) && DeepTypeUtils.isSet(b)) {
|
||||
equalCollection = isEqualSet(a, b);
|
||||
return equalCollection;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function isEqualSampleObj(a, b) {
|
||||
let equalSampleObj = true;
|
||||
const aClassName = Object.prototype.toString.call(a);
|
||||
const bClassName = Object.prototype.toString.call(b);
|
||||
// 俩个string对象
|
||||
if (aClassName === '[object String]') {
|
||||
equalSampleObj = a === String(b);
|
||||
return equalSampleObj;
|
||||
}
|
||||
// 俩个Number对象
|
||||
if (aClassName === '[object Number]') {
|
||||
equalSampleObj = a !== +a ? b !== +b : a === 0 && b === 0 ? 1 / a === 1 / b : a === +b;
|
||||
return equalSampleObj;
|
||||
}
|
||||
|
||||
// 俩个Date对象/ boolean对象
|
||||
if (aClassName === '[object Date]' || aClassName === '[object Boolean]') {
|
||||
equalSampleObj = +a === +b;
|
||||
return equalSampleObj;
|
||||
}
|
||||
|
||||
// 俩个ArrayBuffer
|
||||
if (aClassName === '[object ArrayBuffer]') {
|
||||
equalSampleObj = eq(new Uint8Array(a), new Uint8Array(b));
|
||||
return equalSampleObj;
|
||||
}
|
||||
|
||||
// 正则表达式
|
||||
if (aClassName === '[object RegExp]') {
|
||||
return (
|
||||
a.source === b.source &&
|
||||
a.global === b.global &&
|
||||
a.multiline === b.multiline &&
|
||||
a.ignoreCase === b.ignoreCase
|
||||
);
|
||||
}
|
||||
|
||||
if (a instanceof Error && b instanceof Error) {
|
||||
equalSampleObj = a.message === b.message;
|
||||
return equalSampleObj;
|
||||
}
|
||||
|
||||
return equalSampleObj;
|
||||
}
|
||||
|
||||
function isEqualObj(a, b) {
|
||||
let equalObj = true;
|
||||
const aClassName = Object.prototype.toString.call(a);
|
||||
const bClassName = Object.prototype.toString.call(b);
|
||||
const aKeys = DeepTypeUtils.keys(a, aClassName === '[object Array]');
|
||||
let size = aKeys.length;
|
||||
|
||||
// 俩个对象属性长度不一致, 俩对象不相同
|
||||
if (DeepTypeUtils.keys(b, bClassName === '[object Array]').length !== size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 俩对象属性数量相同, 递归比较每个属性值得值
|
||||
for (const key of aKeys) {
|
||||
// b 没有 key 属性
|
||||
if (!DeepTypeUtils.has(b, key)) {
|
||||
equalObj = false;
|
||||
continue;
|
||||
}
|
||||
if (!eq(a[key], b[key])) {
|
||||
equalObj = false;
|
||||
}
|
||||
}
|
||||
return equalObj;
|
||||
}
|
||||
|
||||
function isEqualArray(a, b) {
|
||||
let equalArray = true;
|
||||
const aLength = a.length;
|
||||
const bLength = b.length;
|
||||
if (aLength !== bLength) {
|
||||
// 数组长度不同,不是同一个对象
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < aLength || i < bLength; i++) {
|
||||
// 递归每一个元素是否相同
|
||||
equalArray = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0) && equalArray;
|
||||
}
|
||||
return equalArray;
|
||||
}
|
||||
|
||||
function isEqualMap(a, b) {
|
||||
let equalMap = true;
|
||||
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; equalMap && i < mapKeys.length; i++) {
|
||||
const mapIter = mapKeys[i];
|
||||
const cmpIter = cmpKeys[i];
|
||||
|
||||
for (let j = 0; equalMap && j < mapIter.length; j++) {
|
||||
const mapKey = mapIter[j];
|
||||
const cmpKey = cmpIter[j];
|
||||
const mapValueA = a.get(mapKey);
|
||||
let mapValueB;
|
||||
if (eq(mapKey, cmpKey)) {
|
||||
mapValueB = b.get(cmpKey);
|
||||
} else {
|
||||
mapValueB = b.get(mapKey);
|
||||
}
|
||||
equalMap = eq(mapValueA, mapValueB);
|
||||
}
|
||||
}
|
||||
return equalMap;
|
||||
}
|
||||
|
||||
function isEqualSet(a, b) {
|
||||
let equalSet = true;
|
||||
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]];
|
||||
for (let i = 0; equalSet && i < setPairs.length; i++) {
|
||||
const baseValues = setPairs[i][0];
|
||||
const otherValues = setPairs[i][1];
|
||||
for (const baseValue of baseValues) {
|
||||
let found = false;
|
||||
for (let j = 0; !found && j < otherValues.length; j++) {
|
||||
const otherValue = otherValues[j];
|
||||
// 深度比较对象
|
||||
found = eq(baseValue, otherValue);
|
||||
}
|
||||
equalSet = equalSet && found;
|
||||
}
|
||||
}
|
||||
return equalSet;
|
||||
}
|
||||
|
||||
export default assertDeepEquals;
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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;
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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');
|
||||
}
|
||||
|
||||
getSpecParamsValue(specs) {
|
||||
let specParams = [];
|
||||
let specDesc = this.specService.getCurrentRunningSpec().description;
|
||||
if (specs === null || specs === undefined) {
|
||||
return specParams;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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, []);
|
||||
return this.getSpecParamsValue(specs);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
getStressNum(specs, specDesc) {
|
||||
let stress = 1;
|
||||
if (specs === null || specs === undefined) {
|
||||
return stress;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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, []);
|
||||
return this.getStressNum(specs, specDesc);
|
||||
}
|
||||
}
|
||||
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;
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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 { LEVEL, SIZE, TESTTYPE } from '../../Constant';
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
class NestFilter {
|
||||
filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc) {
|
||||
let targetSuiteName = '';
|
||||
for (let key in suiteStack) {
|
||||
targetSuiteName = targetSuiteName + '.' + suiteStack[key].description;
|
||||
}
|
||||
targetSuiteName = targetSuiteName.substring(2);
|
||||
const targetSpecName = targetSuiteName + '#' + desc;
|
||||
let isFilter = true;
|
||||
if (targetSpecArray.includes(targetSpecName)) {
|
||||
return false;
|
||||
}
|
||||
for (let index in targetSuiteArray) {
|
||||
if (targetSuiteName.startsWith(targetSuiteArray[index])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return isFilter;
|
||||
}
|
||||
|
||||
filterNotClass(notClass, suiteStack, desc) {
|
||||
let filterNotClass = false;
|
||||
if (notClass != null) {
|
||||
let notClassArray = notClass.split(',');
|
||||
let targetSuiteName = '';
|
||||
for (let key in suiteStack) {
|
||||
targetSuiteName = targetSuiteName + '.' + suiteStack[key].description;
|
||||
}
|
||||
targetSuiteName = targetSuiteName.substring(2);
|
||||
const targetSpecName = targetSuiteName + '#' + desc;
|
||||
if (notClassArray.includes(targetSpecName) || notClassArray.some(key => targetSpecName.startsWith(key))) {
|
||||
filterNotClass = true;
|
||||
}
|
||||
}
|
||||
return filterNotClass;
|
||||
}
|
||||
|
||||
filterLevelOrSizeOrTestType(level, size, testType, filter) {
|
||||
let result = false;
|
||||
if (filter === 0 || filter === '0') {
|
||||
return result;
|
||||
}
|
||||
if (level == null && size == null && testType == null) {
|
||||
return result;
|
||||
}
|
||||
if (level != null) {
|
||||
let levelFilter = LEVEL[`${level}`];
|
||||
result = result || filter === levelFilter;
|
||||
}
|
||||
if (size != null) {
|
||||
let sizeFilter = SIZE[`${size}`];
|
||||
result = result || filter === sizeFilter;
|
||||
}
|
||||
if (testType != null) {
|
||||
let testTypeFilter = TESTTYPE[`${testType}`];
|
||||
result = result || filter === testTypeFilter;
|
||||
}
|
||||
return !result;
|
||||
}
|
||||
}
|
||||
export { ClassFilter, NotClassFilter, SuiteAndItNameFilter, TestTypesFilter, NestFilter };
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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, NestFilter } from './Filter';
|
||||
import { TAG, TESTTYPE, LEVEL, SIZE, KEYSET } from '../../Constant';
|
||||
const STRESS_RULE = /^[1-9]\d*$/;
|
||||
|
||||
class ConfigService {
|
||||
constructor(attr) {
|
||||
this.id = attr.id;
|
||||
this.supportAsync = true; // 默认异步处理测试用例
|
||||
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;
|
||||
this.skipMessage = false;
|
||||
this.runSkipped = '';
|
||||
this.filterXdescribe = [];
|
||||
}
|
||||
|
||||
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', 'skipMessage'];
|
||||
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.skipMessage = params.skipMessage;
|
||||
this.runSkipped = params.runSkipped;
|
||||
this.filterParam = {
|
||||
testType: TESTTYPE,
|
||||
level: LEVEL,
|
||||
size: SIZE
|
||||
};
|
||||
this.parseParams();
|
||||
} catch (err) {
|
||||
console.info(`${TAG}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(`${TAG}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;
|
||||
}
|
||||
|
||||
filterWithNest(desc, filter) {
|
||||
let filterArray = [];
|
||||
const nestFilter = new NestFilter();
|
||||
const targetSuiteArray = this.coreContext.getDefaultService('suite').targetSuiteArray;
|
||||
const targetSpecArray = this.coreContext.getDefaultService('suite').targetSpecArray;
|
||||
const suiteStack = this.coreContext.getDefaultService('suite').suitesStack;
|
||||
let isFilter = nestFilter.filterNestName(targetSuiteArray, targetSpecArray, suiteStack, desc);
|
||||
const isFullRun = this.coreContext.getDefaultService('suite').fullRun;
|
||||
if (typeof (this.filter) !== 'undefined' && this.filter !== 0 && filter !== 0) {
|
||||
filterArray.push(new TestTypesFilter('', '', filter, this.filter));
|
||||
return filterArray.map(item => item.filterIt()).reduce((pre, cur) => pre || cur, false);
|
||||
}
|
||||
if (isFilter && !isFullRun) {
|
||||
return true;
|
||||
}
|
||||
return nestFilter.filterNotClass(this.notClass, suiteStack, desc);
|
||||
|
||||
}
|
||||
|
||||
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(KEYSET);
|
||||
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(KEYSET);
|
||||
let targetParams = '';
|
||||
for (const key in parameters) {
|
||||
if (keySet.has(key)) {
|
||||
targetParams += ' ' + key + ' ' + parameters[key];
|
||||
}
|
||||
}
|
||||
return targetParams.trim();
|
||||
}
|
||||
|
||||
execute() {
|
||||
}
|
||||
|
||||
checkIfSuiteInSkipRun(desc) {
|
||||
return this.runSkipped.split(',').some(item => {
|
||||
return item === desc || item.startsWith(desc + '.') || item.startsWith(desc + '#') || desc.startsWith(item + '.') || this.runSkipped === 'skipped';
|
||||
});
|
||||
}
|
||||
|
||||
checkIfSpecInSkipRun(desc) {
|
||||
return this.runSkipped.split(',').some(item => {
|
||||
if (item.includes('#')) {
|
||||
return item === desc;
|
||||
} else {
|
||||
return desc.startsWith(item + '.') || desc.startsWith(item + '#') || this.runSkipped === 'skipped';
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ConfigService
|
||||
};
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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';
|
||||
import fs from '@ohos.file.fs';
|
||||
import {TAG} from '../../Constant';
|
||||
|
||||
const jsCoverageFileName = 'js_coverage.json';
|
||||
|
||||
export async function collectCoverageData() {
|
||||
if (globalThis.__coverage__ === undefined) {
|
||||
console.info(`${TAG} globalThis not have coverage`);
|
||||
return;
|
||||
}
|
||||
const strJson = JSON.stringify(globalThis.__coverage__);
|
||||
let testMode = globalThis.__testMode__;
|
||||
console.info(`${TAG} coverage data testMode: ${testMode}`);
|
||||
let savePath = globalThis.__savePath__;
|
||||
console.info(`${TAG} write coverage data to: ${savePath}`);
|
||||
let readPath = globalThis.__readPath__;
|
||||
console.info(`${TAG} read coverage data in: ${readPath}`);
|
||||
|
||||
// run callback mode if local test or (save path and read path ) is not defined
|
||||
if (!testMode || !isCoveragePathValid(savePath)) {
|
||||
console.info(`${TAG} run coverage data in call back mode`);
|
||||
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++) {
|
||||
console.info(`${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}`);
|
||||
await SysTestKit.print(`${OHOS_REPORT_COVERAGE_DATA} ${strJson.substring(count * maxLen, (count + 1) * maxLen)}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
console.info(`${TAG} run coverage data in save file mode`);
|
||||
if (fs.accessSync(savePath)) {
|
||||
fs.unlinkSync(savePath);
|
||||
}
|
||||
|
||||
let inputPathDir = savePath.substring(0, savePath.length - jsCoverageFileName.length);
|
||||
if (!fs.accessSync(inputPathDir)) {
|
||||
console.info(`${TAG} coverage data create dir: ${inputPathDir}`);
|
||||
fs.mkdirSync(inputPathDir);
|
||||
}
|
||||
|
||||
let file = fs.openSync(savePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
|
||||
let writeLen = fs.writeSync(file.fd, strJson, {encoding:'utf-8'});
|
||||
console.info(`${TAG} write coverage data success: ${writeLen}`);
|
||||
fs.closeSync(file);
|
||||
const OHOS_REPORT_COVERAGE_PATH = 'OHOS_REPORT_COVERAGE_PATH:';
|
||||
await SysTestKit.print(`${OHOS_REPORT_COVERAGE_PATH} ${readPath}`);
|
||||
console.info(`${OHOS_REPORT_COVERAGE_PATH} ${readPath}`);
|
||||
}
|
||||
|
||||
function isCoveragePathValid(inputPath) {
|
||||
if (!inputPath) {
|
||||
return false;
|
||||
}
|
||||
if (inputPath.indexOf(jsCoverageFileName) === -1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2022-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 {TAG} from '../../Constant';
|
||||
import Core from '../../core.js';
|
||||
|
||||
export default class SysTestKit {
|
||||
|
||||
static delegator = null;
|
||||
static systemTime = null;
|
||||
static workerPort = null;
|
||||
|
||||
constructor() {
|
||||
this.id = 'sysTestKit';
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
static getDescribeName() {
|
||||
return Core.getInstance().getDefaultService('suite').getCurrentRunningSuite().description;
|
||||
}
|
||||
|
||||
static getItName() {
|
||||
return Core.getInstance().getDefaultService('spec').getCurrentRunningSpec().description;
|
||||
}
|
||||
|
||||
static getItAttribute() {
|
||||
return Core.getInstance().getDefaultService('spec').getCurrentRunningSpec().fi;
|
||||
}
|
||||
|
||||
static actionStart(tag) {
|
||||
console.info(`${TAG}${JSON.stringify(tag)}`);
|
||||
var message = '\n' + 'OHOS_REPORT_ACTIONSTART: ' + JSON.stringify(tag) + '\n';
|
||||
SysTestKit.print(message);
|
||||
console.info(`${TAG}${JSON.stringify(tag)} actionStart print success`);
|
||||
}
|
||||
|
||||
static actionEnd(tag) {
|
||||
console.info(`${TAG}${JSON.stringify(tag)}`);
|
||||
var message = '\n' + 'OHOS_REPORT_ACTIONEND: ' + JSON.stringify(tag) + '\n';
|
||||
SysTestKit.print(message);
|
||||
console.info(`${TAG}${JSON.stringify(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.info(`${TAG}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(`${TAG}systemTime.getRealTime success data: ${JSON.stringify(time)}`);
|
||||
currentTime = time;
|
||||
}).catch((error) => {
|
||||
console.error(`${TAG}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(`${TAG}existKeyword CallBack: err : ${JSON.stringify(error)}`);
|
||||
console.info(`${TAG}existKeyword CallBack: data : ${JSON.stringify(data)}`);
|
||||
resolve(parseInt(data.stdResult) > 3 ? true : false);
|
||||
});
|
||||
});
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 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;
|
||||
+57
@@ -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;
|
||||
+347
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 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 = new Map();
|
||||
this.mockObj = null;
|
||||
this.recordMockedMethod = new Map();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.mFunctions = [];
|
||||
this.stubs = {};
|
||||
this.recordCalls = {};
|
||||
this.currentSetKey = new Map();
|
||||
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' && typeof obj !== 'function') {
|
||||
throw new Error('Not a object or static class');
|
||||
}
|
||||
this.recordMockedMethod.forEach(function (value, key, map) {
|
||||
if (key) {
|
||||
obj[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ignoreMock(obj, method) {
|
||||
if (typeof obj !== 'object' && typeof obj !== 'function') {
|
||||
throw new Error('Not a object or static class');
|
||||
}
|
||||
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;
|
||||
} else {
|
||||
key = [];
|
||||
const matcher = new ArgumentMatchers();
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const param = params[i];
|
||||
const matchKey = matcher.matcheStubKey(param);
|
||||
if (matchKey) {
|
||||
key.push(matchKey);
|
||||
} else {
|
||||
key.push(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
values.set(key, returnInfo);
|
||||
this.stubs.set(f, values);
|
||||
}
|
||||
|
||||
getReturnInfo(f, params) {
|
||||
let values = this.stubs.get(f);
|
||||
if (!values) {
|
||||
return undefined;
|
||||
}
|
||||
let returnKet = params[0];
|
||||
const anonymousName = 'anonymous-mock-' + f.propName;
|
||||
if (typeof returnKet === 'undefined') {
|
||||
returnKet = anonymousName;
|
||||
} else {
|
||||
returnKet = this.getReturnKet(values, params, returnKet, anonymousName);
|
||||
}
|
||||
|
||||
return values.get(returnKet);
|
||||
}
|
||||
|
||||
getReturnKet(values, params, defaultValue, anonymousName) {
|
||||
let flag = true;
|
||||
let returnKet = defaultValue;
|
||||
values.forEach((value, paramsKey, map) => {
|
||||
if (
|
||||
flag &&
|
||||
paramsKey !== anonymousName &&
|
||||
paramsKey.length === params.length &&
|
||||
this.checkIsRightValue(paramsKey, params)
|
||||
) {
|
||||
returnKet = paramsKey;
|
||||
flag = false;
|
||||
}
|
||||
});
|
||||
return returnKet;
|
||||
}
|
||||
|
||||
checkIsRightValue(paramsKey, params) {
|
||||
const matcher = new ArgumentMatchers();
|
||||
return paramsKey.every((key, j) => {
|
||||
if (ArgumentMatchers.isRegExp(key) && typeof params[j] === 'string') {
|
||||
return key.test(params[j]);
|
||||
}
|
||||
const matchKey = matcher.matcheReturnKey(params[j], undefined, key);
|
||||
if (matchKey && matchKey === key) {
|
||||
return true;
|
||||
} else if (this.checkIsEqual(params[j], key)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
checkIsEqual(value1, value2) {
|
||||
if (value1 === value2) {
|
||||
return true;
|
||||
}
|
||||
if (typeof value1 !== typeof value2) {
|
||||
return false;
|
||||
}
|
||||
if (Array.isArray(value1) && Array.isArray(value2)) {
|
||||
if (value1.length !== value2.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < value1.length; i++) {
|
||||
if (!this.checkIsEqual(value1[i], value2[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (Object.prototype.toString.call(value1) === '[object Object]' &&
|
||||
Object.prototype.toString.call(value2) === '[object Object]') {
|
||||
const keys1 = Object.keys(value1);
|
||||
const keys2 = Object.keys(value2);
|
||||
if (keys1.length !== keys2.length) {
|
||||
return false;
|
||||
}
|
||||
for (let key of keys1) {
|
||||
if (!keys2.includes(key) || !this.checkIsEqual(value1[key], value2[key])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (Object.prototype.toString.call(value1) === '[object Date]' &&
|
||||
Object.prototype.toString.call(value2) === '[object Date]' &&
|
||||
value1.getTime() === value2.getTime()) {
|
||||
return true;
|
||||
}
|
||||
if (Object.prototype.toString.call(value1) === '[object RegExp]' &&
|
||||
Object.prototype.toString.call(value2) === '[object RegExp]' &&
|
||||
value1.toString() === value2.toString()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
findName(obj, value) {
|
||||
let properties = this.findProperties(obj);
|
||||
let name = null;
|
||||
properties
|
||||
.filter((item) => item !== 'caller' && item !== 'arguments')
|
||||
.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(newObj) {
|
||||
if (newObj.__proto__ === null) {
|
||||
return [];
|
||||
}
|
||||
let properties = Object.getOwnPropertyNames(newObj);
|
||||
return [...properties, ...getProperty(newObj.__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)) {
|
||||
throw Error('not a mock function');
|
||||
}
|
||||
return f.stub.bind(f);
|
||||
}
|
||||
|
||||
export { MockKit, when };
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2022-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 {expect} from '../../interface';
|
||||
|
||||
class VerificationMode {
|
||||
constructor(times) {
|
||||
this.doTimes = times;
|
||||
}
|
||||
|
||||
times(count) {
|
||||
expect(count).assertEqual(this.doTimes);
|
||||
}
|
||||
|
||||
never() {
|
||||
console.info(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;
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 LogExpectError {
|
||||
static getErrorMsg(matcherName, actualValue, expect, originMsg) {
|
||||
if (matcherName === 'assertNull') {
|
||||
return 'expect not null, actualValue is ' + (actualValue);
|
||||
}
|
||||
if (matcherName === 'assertTrue') {
|
||||
return 'expect not true, actualValue is ' + (actualValue);
|
||||
}
|
||||
if (matcherName === 'assertFalse') {
|
||||
return 'expect not false, actualValue is ' + (actualValue);
|
||||
}
|
||||
if (matcherName === 'assertEqual') {
|
||||
return 'expect not Equal, actualValue is ' + actualValue + ' equals ' + expect;
|
||||
}
|
||||
if (matcherName === 'assertContain') {
|
||||
return 'expect not have, ' + actualValue + ' have ' + expect;
|
||||
}
|
||||
if (matcherName === 'assertInstanceOf') {
|
||||
return 'expect not InstanceOf, ' + actualValue + ' is ' +
|
||||
Object.prototype.toString.call(actualValue) + expect;
|
||||
}
|
||||
if (matcherName === 'assertLarger') {
|
||||
return 'expect not Larger, ' +
|
||||
(actualValue) + ' is larger than ' + expect;
|
||||
}
|
||||
if (matcherName === 'assertLargerOrEqual') {
|
||||
return 'expect not LargerOrEqual, ' + (actualValue) + ' larger than ' + expect;
|
||||
}
|
||||
if (matcherName === 'assertLess') {
|
||||
return 'expect not Less, ' + (actualValue) + ' less than ' + expect;
|
||||
}
|
||||
if (matcherName === 'assertLessOrEqual') {
|
||||
return 'expect not LessOrEqual, ' + (actualValue) + ' is less than ' + expect;
|
||||
}
|
||||
if (matcherName === 'assertNaN') {
|
||||
return 'expect not NaN, actualValue is ' + (actualValue);
|
||||
}
|
||||
if (matcherName === 'assertNegUnlimited') {
|
||||
return 'expect not NegUnlimited, actualValue is ' + (actualValue);
|
||||
}
|
||||
if (matcherName === 'assertPosUnlimited') {
|
||||
return 'expect not PosUnlimited, actualValue is ' + (actualValue);
|
||||
}
|
||||
if (matcherName === 'assertUndefined') {
|
||||
return 'expect not Undefined, actualValue is ' + (actualValue);
|
||||
}
|
||||
return originMsg;
|
||||
}
|
||||
}
|
||||
export default LogExpectError;
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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';
|
||||
import { TAG, PrintTag } from '../../Constant';
|
||||
|
||||
class OhReport {
|
||||
constructor(attr) {
|
||||
this.delegator = attr.delegator;
|
||||
this.abilityDelegatorArguments = attr.abilityDelegatorArguments;
|
||||
this.id = 'report';
|
||||
this.index = 0;
|
||||
this.duration = 0;
|
||||
this.currentThreadName = 'mainThread';
|
||||
}
|
||||
|
||||
init(coreContext) {
|
||||
this.coreContext = coreContext;
|
||||
this.suiteService = this.coreContext.getDefaultService('suite');
|
||||
this.specService = this.coreContext.getDefaultService('spec');
|
||||
if (SysTestKit.workerPort !== null) {
|
||||
this.currentThreadName = SysTestKit.workerPort.name;
|
||||
}
|
||||
}
|
||||
|
||||
taskStart() {
|
||||
}
|
||||
|
||||
async taskDone() {
|
||||
let summary = this.suiteService.getSummary();
|
||||
if (this.abilityDelegatorArguments !== null) {
|
||||
this.taskDoneTime = new Date().getTime();
|
||||
const configService = this.coreContext.getDefaultService('config');
|
||||
const suiteService = this.coreContext.getDefaultService('suite');
|
||||
const specService = this.coreContext.getDefaultService('spec');
|
||||
if (configService['coverage'] === 'true') {
|
||||
await collectCoverageData();
|
||||
}
|
||||
let message = '\n' + `${PrintTag.OHOS_REPORT_RESULT}: stream=Tests run: ` + summary.total + ', Failure: ' + summary.failure;
|
||||
message += ', Error: ' + summary.error;
|
||||
message += ', Pass: ' + summary.pass;
|
||||
message += ', Ignore: ' + summary.ignore;
|
||||
if (specService.skipSpecNum > 0) {
|
||||
message += ', SkipSpec: ' + specService.skipSpecNum;
|
||||
}
|
||||
message += '\n' + `${PrintTag.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' + `${PrintTag.OHOS_REPORT_RESULT}: breakOnError model, Stopping whole test suite if one specific test case failed or error` + '\n';
|
||||
}
|
||||
message += `${PrintTag.OHOS_REPORT_STATUS}: taskconsuming=` + summary.duration + '\n';
|
||||
console.info(`${message}`);
|
||||
await SysTestKit.print(message);
|
||||
}
|
||||
if (SysTestKit.workerPort === null || SysTestKit.workerPort === undefined) {
|
||||
// 主线程执行完成 结束任务。
|
||||
console.info(`${TAG}report print success`);
|
||||
this.delegator.finishTest('your test finished!!!', 0, () => { });
|
||||
} else {
|
||||
// worker线程执行完成将数据发送到主线程中。
|
||||
let sendData = {
|
||||
currentThreadName: this.currentThreadName,
|
||||
summary: summary
|
||||
};
|
||||
console.info(`${TAG}, send data to mainThread, ${this.currentThreadName}, ${JSON.stringify(sendData)}`);
|
||||
SysTestKit.workerPort.postMessage(sendData);
|
||||
}
|
||||
}
|
||||
|
||||
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, () => {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
incorrectTestSuiteFormat() {
|
||||
if (this.coreContext.getDefaultService('config').filterXdescribe.length !== 0) {
|
||||
let value = this.coreContext.getDefaultService('config').filterXdescribe;
|
||||
let message = 'xdescribe ' + value.join(',') + ' should not contain it' + '\n';
|
||||
this.delegator.finishTest(message, 0, () => {
|
||||
});
|
||||
}
|
||||
}
|
||||
async suiteStart() {
|
||||
if (this.abilityDelegatorArguments !== null) {
|
||||
let specArr = [];
|
||||
this.suiteService.getAllChildSuiteNum(this.suiteService.getCurrentRunningSuite(), specArr);
|
||||
let message = '\n' + `${PrintTag.OHOS_REPORT_SUM}: ` + specArr.length;
|
||||
this.suiteService.setCurrentRunningSuiteDesc(this.suiteService.getRootSuite(), this.suiteService.getCurrentRunningSuite(), '');
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc() + '\n';
|
||||
if (this.suiteService.currentRunningSuite.isSkip) {
|
||||
message += `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.suiteService.currentRunningSuite.skipReason + '\n';
|
||||
}
|
||||
if (SysTestKit.workerPort !== null) {
|
||||
message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
|
||||
}
|
||||
console.info(`${message}`);
|
||||
await SysTestKit.print(message);
|
||||
console.info(`${TAG}${this.suiteService.getCurrentRunningSuite().description} suiteStart print success`);
|
||||
}
|
||||
}
|
||||
|
||||
async suiteDone() {
|
||||
if (this.abilityDelegatorArguments !== null) {
|
||||
const currentRunningSuite = this.suiteService.getCurrentRunningSuite();
|
||||
this.suiteService.setCurrentRunningSuiteDesc(this.suiteService.getRootSuite(), currentRunningSuite, '');
|
||||
let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
|
||||
if (this.suiteService.currentRunningSuite.isSkip && this.suiteService.currentRunningSuite.skipReason !== '') {
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.suiteService.currentRunningSuite.skipReason;
|
||||
}
|
||||
const isPromiseError = currentRunningSuite.isPromiseError;
|
||||
if (isPromiseError) {
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: shortMsg=Promise(async, await) in describe is not allowed!`;
|
||||
}
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: suiteconsuming=` + currentRunningSuite.duration;
|
||||
if (currentRunningSuite.hookError) {
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: ${currentRunningSuite.hookError.message}`;
|
||||
}
|
||||
message += '\n';
|
||||
if (SysTestKit.workerPort !== null) {
|
||||
message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
|
||||
}
|
||||
console.info(`${message}`);
|
||||
await SysTestKit.print(message);
|
||||
console.info(`${TAG}${currentRunningSuite.description} suiteDone print success`);
|
||||
}
|
||||
}
|
||||
|
||||
async specStart() {
|
||||
if (this.abilityDelegatorArguments !== null) {
|
||||
let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: current=` + (++this.index);
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: id=JS`;
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: numtests=` + this.specService.getTestTotal();
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: 1` + '\n';
|
||||
if (this.specService.currentRunningSpec.isSkip) {
|
||||
message += `${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.specService.currentRunningSpec.skipReason + '\n';
|
||||
}
|
||||
if (SysTestKit.workerPort !== null) {
|
||||
message += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
|
||||
}
|
||||
console.info(`${message}`);
|
||||
await SysTestKit.print(message);
|
||||
console.info(`${TAG}${this.specService.currentRunningSpec.description} specStart start print success`);
|
||||
}
|
||||
}
|
||||
|
||||
async specDone() {
|
||||
if (this.abilityDelegatorArguments !== null) {
|
||||
let message = '\n' + `${PrintTag.OHOS_REPORT_STATUS}: class=` + this.suiteService.getCurrentRunningSuiteDesc();
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: current=` + (this.index);
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: id=JS`;
|
||||
message += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: numtests=` + this.specService.getTestTotal();
|
||||
let messageStack = '';
|
||||
let messageCode = '';
|
||||
if (this.specService.currentRunningSpec.error) {
|
||||
messageStack = `${PrintTag.OHOS_REPORT_STATUS}: stack=` + this.specService.currentRunningSpec.error?.stack?.slice(0, -1);
|
||||
messageCode += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
|
||||
messageCode += this.specService.currentRunningSpec.expectMsg !== '' ?
|
||||
`message: ${this.specService.currentRunningSpec.expectMsg}, Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.error?.message}` :
|
||||
`Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.error?.message}`;
|
||||
messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
|
||||
messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: -1` + '\n';
|
||||
} else if (this.specService.currentRunningSpec) {
|
||||
if (this.specService.currentRunningSpec.fail) {
|
||||
messageStack += `${PrintTag.OHOS_REPORT_STATUS}: stack=` + this.specService.currentRunningSpec.fail?.stack?.slice(0, -1);
|
||||
messageCode += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
|
||||
messageCode += this.specService.currentRunningSpec.expectMsg !== '' ?
|
||||
`message: ${this.specService.currentRunningSpec.expectMsg}, Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.fail?.message}` :
|
||||
`Error in ${this.specService.currentRunningSpec.description}, ${this.specService.currentRunningSpec.fail?.message}`;
|
||||
messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
|
||||
messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: -2` + '\n';
|
||||
} else {
|
||||
messageStack += `${PrintTag.OHOS_REPORT_STATUS}: stream=`;
|
||||
messageCode += `${PrintTag.OHOS_REPORT_STATUS}: test=` + this.specService.currentRunningSpec.description;
|
||||
messageCode += '\n' + `${PrintTag.OHOS_REPORT_STATUS_CODE}: 0` + '\n';
|
||||
messageCode += this.specService.currentRunningSpec.isSkip ? (`${PrintTag.OHOS_REPORT_STATUS}: skipReason=` + this.specService.currentRunningSpec.skipReason + '\n') : '';
|
||||
}
|
||||
} else {
|
||||
messageCode += '\n';
|
||||
}
|
||||
messageCode += `${PrintTag.OHOS_REPORT_STATUS}: consuming=` + this.specService.currentRunningSpec.duration + '\n';
|
||||
if (SysTestKit.workerPort !== null) {
|
||||
messageCode += `${PrintTag.OHOS_REPORT_STATUS}: currentWorkerName=` + this.currentThreadName;
|
||||
}
|
||||
console.info(`${message}`);
|
||||
console.info(`\n${messageStack}`);
|
||||
console.info(`\n${messageCode}`);
|
||||
await SysTestKit.print(message);
|
||||
await SysTestKit.print(messageStack);
|
||||
await SysTestKit.print(messageCode);
|
||||
console.info(`${TAG}${this.specService.currentRunningSpec.description} specDone end print success`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default OhReport;
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2024 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() {
|
||||
|
||||
}
|
||||
|
||||
handleSpecs(specs, report, suiteReport, testsuite) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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'];
|
||||
this.handleSpecs(specs, report, suiteReport, testsuite);
|
||||
report.children.push(suiteReport);
|
||||
}
|
||||
}
|
||||
|
||||
writeXmlReport(report);
|
||||
}
|
||||
}
|
||||
|
||||
function writeXmlReport(report) {
|
||||
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 handleChild(json, key, hasChildren, childrenStr) {
|
||||
if (json[key].length > 0) {
|
||||
hasChildren = true;
|
||||
for (let child of json[key]) {
|
||||
childrenStr += json2xml(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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') {
|
||||
handleChild(json, key, hasChildren, childrenStr);
|
||||
} else {
|
||||
attrStr += ` ${key}="${json[key]}"`;
|
||||
}
|
||||
}
|
||||
let xml = `<${tagName}${attrStr}`;
|
||||
xml += hasChildren ? `>${childrenStr}</${tagName}>` : '/>';
|
||||
return xml;
|
||||
}
|
||||
|
||||
export default ReportExtend;
|
||||
File diff suppressed because it is too large
Load Diff
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2024 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 { abilityDelegatorRegistry, TestRunner } from '@kit.TestKit';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
import { resourceManager } from '@kit.LocalizationKit';
|
||||
import { util } from '@kit.ArkTS';
|
||||
import { Hypium } from '@ohos/hypium';
|
||||
import testsuite from '../test/List.test';
|
||||
|
||||
let abilityDelegator: abilityDelegatorRegistry.AbilityDelegator;
|
||||
let abilityDelegatorArguments: abilityDelegatorRegistry.AbilityDelegatorArgs;
|
||||
let jsonPath: string = 'mock/mock-config.json';
|
||||
let domain: number = 0x0000; //日志标识,0x0000作为测试框架的业务标识
|
||||
let tag: string = 'testTag'; //日志标识字符串,作为tag标识当前runner类下的测试行为
|
||||
|
||||
export default class OpenHarmonyTestRunner implements TestRunner {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
onPrepare() {
|
||||
hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner OnPrepare');
|
||||
}
|
||||
|
||||
async onRun() {
|
||||
hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner onRun run');
|
||||
abilityDelegatorArguments = abilityDelegatorRegistry.getArguments();
|
||||
abilityDelegator = abilityDelegatorRegistry.getAbilityDelegator();
|
||||
let moduleName = abilityDelegatorArguments.parameters['-m'];
|
||||
let context = abilityDelegator.getAppContext().getApplicationContext().createModuleContext(moduleName);
|
||||
let mResourceManager = context.resourceManager;
|
||||
await checkMock(abilityDelegator, mResourceManager);
|
||||
hilog.info(domain, tag, '%{public}s', 'start run testcase!!!');
|
||||
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
|
||||
hilog.info(domain, tag, '%{public}s', 'OpenHarmonyTestRunner onRun end');
|
||||
}
|
||||
}
|
||||
|
||||
async function checkMock(abilityDelegator: abilityDelegatorRegistry.AbilityDelegator, resourceManager: resourceManager.ResourceManager) {
|
||||
let rawFile: Uint8Array;
|
||||
try {
|
||||
rawFile = resourceManager.getRawFileContentSync(jsonPath);
|
||||
hilog.info(domain, tag, 'MockList file exists');
|
||||
let mockStr: string = util.TextDecoder.create("utf-8", { ignoreBOM: true }).decodeWithStream(rawFile);
|
||||
let mockMap: Record<string, string> = getMockList(mockStr);
|
||||
try {
|
||||
abilityDelegator.setMockList(mockMap);
|
||||
} catch (error) {
|
||||
let code = (error as BusinessError).code;
|
||||
let message = (error as BusinessError).message;
|
||||
hilog.error(domain, tag, `abilityDelegator.setMockList failed, error code: ${code}, message: ${message}.`);
|
||||
}
|
||||
} catch (error) {
|
||||
let code = (error as BusinessError).code;
|
||||
let message = (error as BusinessError).message;
|
||||
hilog.error(domain, tag, `ResourceManager:callback getRawFileContent failed, error code: ${code}, message: ${message}.`);
|
||||
}
|
||||
}
|
||||
|
||||
function getMockList(jsonStr: string) {
|
||||
let jsonObj: Record<string, Object> = JSON.parse(jsonStr);
|
||||
let map: Map<string, object> = new Map<string, object>(Object.entries(jsonObj));
|
||||
let mockList: Record<string, string> = {};
|
||||
map.forEach((value: object, key: string) => {
|
||||
let realValue: string = value['source'].toString();
|
||||
mockList[key] = realValue;
|
||||
});
|
||||
hilog.info(domain, tag, '%{public}s', 'mock-json value:' + JSON.stringify(mockList) ?? '');
|
||||
return mockList;
|
||||
}
|
||||
Reference in New Issue
Block a user