1# arkXtest 2 3## Introduction 4arkXtest, the automated test framework of OpenHarmony, consists of the JS unit test framework (JsUnit) and UI test framework (UiTest). 5 6JsUnit provides APIs for writing test cases for system or application interfaces, executing unit test cases, and generating test reports. 7 8UiTest provides simple and easy-to-use APIs for locating and operating UI components, helping users to develop automatic test scripts based on UI operations. 9 10## Directory Structure 11 12``` 13arkXtest 14 |-----jsunit Unit test framework 15 |-----uitest UI test framework 16``` 17## Constraints 18The initial APIs of this module are supported since API version 8. Newly added APIs will be marked with a superscript to indicate their earliest API version. 19 20## JsUnit Features 21 22| No. | Feature | Description | 23| ---- | -------- | ------------------------------------------------------------ | 24| 1 | Basic process support| Provides APIs for writing and executing test cases. | 25| 2 | Assertion library | Provides APIs for checking whether the actual value of a test case is the same as the expected value. | 26| 3 | Mock| Provides APIs for mocking functions to return the specified value or perform the specified action.| 27| 4 | Data driving| Provides APIs for reusing a test script with different input data.| 28 29### How to Use 30 31#### Basic Process Support 32 33Test cases use the common syntax in the industry. **describe** defines a test suite, and **it** specifies a test case. 34 35| No. | API | Description | 36| ---- | ---------- | ------------------------------------------------------------ | 37| 1 | describe | Defines a test suite. This API supports two parameters: test suite name and test suite function. | 38| 2 | beforeAll | Presets an action, which is performed only once before all test cases of the test suite start. This API supports only one parameter: preset action function.| 39| 3 | beforeEach | Presets an action, which is performed before each unit test case starts. The number of execution times is the same as the number of test cases defined by **it**. This API supports only one parameter: preset action function.| 40| 4 | afterEach | Presets a clear action, which is performed after each unit test case ends. The number of execution times is the same as the number of test cases defined by **it**. This API supports only one parameter: clear action function.| 41| 5 | afterAll | Presets a clear action, which is performed after all test cases of the test suite end. This API supports only one parameter: clear action function.| 42| 6 | it | Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.| 43| 7 | expect | Defines a variety of assertion methods, which are used to declare expected Boolean conditions. | 44 45The sample code is as follows: 46 47```javascript 48import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium' 49import demo from '@ohos.bundle' 50 51export default async function abilityTest() { 52 describe('ActsAbilityTest', function () { 53 it('String_assertContain_success', 0, function () { 54 let a = 'abc' 55 let b = 'b' 56 expect(a).assertContain(b) 57 expect(a).assertEqual(a) 58 }) 59 it('getBundleInfo_0100', 0, async function () { 60 const NAME1 = "com.example.MyApplicationStage" 61 await demo.getBundleInfo(NAME1, 62 demo.BundleFlag.GET_BUNDLE_WITH_ABILITIES | demo.BundleFlag.GET_BUNDLE_WITH_REQUESTED_PERMISSION) 63 .then((value) => { 64 console.info(value.appId) 65 }) 66 .catch((err) => { 67 console.info(err.code) 68 }) 69 }) 70 }) 71} 72``` 73 74 75 76#### Assertion Library 77 78Available APIs: 79 80 81| No. | API | Description | 82| :--- | :--------------- | ------------------------------------------------------------ | 83| 1 | assertClose | Checks whether the proximity between the actual value and the expected value (0) is the expected value (1). | 84| 2 | assertContain | Checks whether the actual value contains the expected value. | 85| 3 | assertEqual | Checks whether the actual value is equal to the expected value. | 86| 4 | assertFail | Throws an error. | 87| 5 | assertFalse | Check whether the actual value is **false**. | 88| 6 | assertTrue | Checks whether the actual value is **true**. | 89| 7 | assertInstanceOf | Checks whether the actual value is of the type specified by the expected value,basic types are supported. | 90| 8 | assertLarger | Checks whether the actual value is greater than the expected value. | 91| 9 | assertLess | Checks whether the actual value is less than the expected value. | 92| 10 | assertNull | Checks whether the actual value is null. | 93| 11 | assertThrowError | Checks whether the error thrown by the actual value is the expected value. | 94| 12 | assertUndefined | Checks whether the actual value is **undefined**. | 95 96The sample code is as follows: 97 98```javascript 99import { describe, it, expect } from '@ohos/hypium' 100export default async function abilityTest() { 101 describe('assertClose', function () { 102 it('assertBeClose_success', 0, function () { 103 let a = 100 104 let b = 0.1 105 expect(a).assertClose(99, b) 106 }) 107 it('assertBeClose_fail', 0, function () { 108 let a = 100 109 let b = 0.1 110 expect(a).assertClose(1, b) 111 }) 112 it('assertBeClose_fail', 0, function () { 113 let a = 100 114 let b = 0.1 115 expect(a).assertClose(null, b) 116 }) 117 it('assertBeClose_fail', 0, function () { 118 expect(null).assertClose(null, 0) 119 }) 120 it('assertInstanceOf_success', 0, function () { 121 let a = 'strTest' 122 expect(a).assertInstanceOf('String') 123 }) 124 }) 125} 126``` 127 128 129#### Mock 130 131##### Constraints 132 133JsUnit provides the mock capability since npm [1.0.1](https://repo.harmonyos.com/#/en/application/atomService/@ohos%2Fhypium). You must modify the npm version in **package.info** of the source code project before using the mock capability. 134 135- **Available APIs** 136 137| No. | API | Description| 138| --- | --- | --- | 139| 1 | mockFunc(obj: object, f: function())| Mocks a function in the object of a class. The parameters **obj** and **f** must be passed in. This API supports asynchronous functions. <br>**NOTE**: This API does not focus on the implementation of the original function. Therefore, it does not matter whether the original function is implemented synchronously or asynchronously.| 140| 2 | when(mockedfunc: function)| Checks whether the input function is mocked and marked. A function declaration is returned.| 141| 3 | afterReturn(x: value)| Sets an expected return value, for example, a string or promise.| 142| 4 | afterReturnNothing() | Sets the expected return value to **undefined**, that is, no value will be returned.| 143| 5 | afterAction(x: action)| Sets the expected return value to be an action executed by a function.| 144| 6 | afterThrow(x: msg)| Sets an exception to throw and the error message.| 145| 7 | clear() | Restores the mocked object after the test case is complete (restores the original features of the object).| 146| 8 | any | Returns the expected value if a parameter of any type (except **undefined** and **null**) is passed in. This API must be called by **ArgumentMatchers.any**.| 147| 9 | anyString | Returns the expected value if a string is passed in. This API must be called by **ArgumentMatchers.anyString**.| 148| 10 | anyBoolean | Returns the expected value if a Boolean value is passed in. This API must be called by **ArgumentMatchers.anyBoolean**.| 149| 11 | anyFunction | Returns the expected value if a function is passed in. This API must be called by **ArgumentMatchers.anyFunction**.| 150| 12 | anyNumber | Returns the expected value if a number is passed in. This API must be called by **ArgumentMatchers.anyNumber**.| 151| 13 | anyObj | Returns the expected value if an object is passed in. This API must be called by **ArgumentMatchers.anyObj**.| 152| 14 | matchRegexs(Regex) | Returns the expected value if a regular expression is passed in. This API must be called by **ArgumentMatchers.matchRegexs(Regex)**.| 153| 15 | verify(methodName, argsArray) | Verifies whether a function and its parameters are processed as expected. This API returns a **VerificationMode**, which is a class that provides the verification mode. This class provides functions such as **times(count)**, **once()**, **atLeast(x)**, **atMost(x)**, and **never()**.| 154| 16 | times(count) | Verifies whether the function was executed the specified number of times.| 155| 17 | once() | Verifies whether the function was executed only once.| 156| 18 | atLeast(count) | Verifies whether the function was executed at least **count** times.| 157| 19 | atMost(count) | Verifies whether the function was executed at most **count** times.| 158| 20 | never | Verifies whether the function has never been executed.| 159| 21 | ignoreMock(obj, method) | Restores the mocked function in the object. This API is valid for mocked functions.| 160| 22 | clearAll() | Clears all data and memory after the test cases are complete.| 161 162- **Examples** 163 164You can refer to the following examples to import the mock module and write test cases. 165 166- **NOTICE**<br> 167You must import **MockKit** and **when**. You can import other assertion APIs based on the test cases. 168Example: `import {describe, expect, it, MockKit, when} from '@ohos/hypium'` 169 170Example 1: Use **afterReturn**. 171 172```javascript 173import {describe, expect, it, MockKit, when} from '@ohos/hypium'; 174 175export default function ActsAbilityTest() { 176 describe('ActsAbilityTest', function () { 177 it('testMockfunc', 0, function () { 178 console.info("it1 begin"); 179 180 // 1. Create a MockKit object. 181 let mocker = new MockKit(); 182 183 // 2. Define the ClassName class, which contains two functions, and then create a claser object. 184 class ClassName { 185 constructor() { 186 } 187 188 method_1(arg) { 189 return '888888'; 190 } 191 192 method_2(arg) { 193 return '999999'; 194 } 195 } 196 197 let claser = new ClassName(); 198 199 // 3. Mock method_1 of the ClassName class. 200 let mockfunc = mocker.mockFunc(claser, claser.method_1); 201 when(mockfunc)('test').afterReturn('1'); 202 203 // 4. Assert whether the mocked function is implemented as expected. 204 // The operation is successful if 'test' is passed in. 205 expect(claser.method_1('test')).assertEqual('1'); // The operation is successful. 206 207 // The operation fails if 'abc' is passed in. 208 //expect(claser.method_1('abc')).assertEqual('1'); // The operation fails. 209 }); 210 }); 211} 212``` 213- **NOTICE**<br> 214In `when(mockfunc)('test').afterReturn('1');`, `('test')` is the value to pass in the mocked function. Currently, only one parameter is supported. `afterReturn('1')` is the expected return value. The expected value is returned only when `('test')` is passed in. 215 216Example 2: Use **afterReturnNothing**. 217 218```javascript 219import {describe, expect, it, MockKit, when} from '@ohos/hypium'; 220 221export default function ActsAbilityTest() { 222 describe('ActsAbilityTest', function () { 223 it('testMockfunc', 0, function () { 224 console.info("it1 begin"); 225 226 // 1. Create a MockKit object. 227 let mocker = new MockKit(); 228 229 // 2. Define the ClassName class, which contains two functions, and then create a claser object. 230 class ClassName { 231 constructor() { 232 } 233 234 method_1(arg) { 235 return '888888'; 236 } 237 238 method_2(arg) { 239 return '999999'; 240 } 241 } 242 243 let claser = new ClassName(); 244 245 // 3. Mock method_1 of the ClassName class. 246 let mockfunc = mocker.mockFunc(claser, claser.method_1); 247 248 // 4. Set the action to be performed when the test case ends. For example, set it to afterReturnNothing(), which returns no value. 249 when(mockfunc)('test').afterReturnNothing(); 250 251 // 5. Assert whether the mocked function is implemented as expected. Use the assertion APIs corresponding to Step 4. 252 // The operation is successful if 'test' is passed in. 253 // The mocked claser.method_1 does not return '888888'. Instead, afterReturnNothing() takes effect, that is, no value is returned. 254 expect(claser.method_1('test')).assertUndefined(); // The operation is successful. 255 256 // The operation fails if '123' is passed in. 257 // expect(method_1(123)).assertUndefined();// The operation fails. 258 }); 259 }); 260} 261``` 262 263Example 3: Set the parameter type to **any**, that is, allow any parameter value except **undefine** and **null**. 264 265 266- **NOTICE**<br> 267The **ArgumentMatchers** class, for example, **ArgumentMatchers.any**, must be imported. 268 269```javascript 270import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium'; 271 272export default function ActsAbilityTest() { 273 describe('ActsAbilityTest', function () { 274 it('testMockfunc', 0, function () { 275 console.info("it1 begin"); 276 277 // 1. Create a MockKit object. 278 let mocker = new MockKit(); 279 280 // 2. Define the ClassName class, which contains two functions, and then create a claser object. 281 class ClassName { 282 constructor() { 283 } 284 285 method_1(arg) { 286 return '888888'; 287 } 288 289 method_2(arg) { 290 return '999999'; 291 } 292 } 293 294 let claser = new ClassName(); 295 296 // 3. Mock method_1 of the ClassName class. 297 let mockfunc = mocker.mockFunc(claser, claser.method_1); 298 // Set the parameter matcher and expected return value as required. 299 when(mockfunc)(ArgumentMatchers.any).afterReturn('1'); 300 301 // 4. Assert whether the mocked function is implemented as expected. 302 // The operation is successful if a string is passed in. 303 expect(claser.method_1('test')).assertEqual('1'); // The operation is successful. 304 // The operation is successful if a number (for example '123') is passed in. 305 expect(claser.method_1(123)).assertEqual('1'); // The operation is successful. 306 // The operation is successful if a Boolean value (for example 'true') is passed in. 307 expect(claser.method_1(true)).assertEqual('1');// The operation is successful. 308 309 // The operation fails if an empty value is passed in. 310 //expect(claser.method_1()).assertEqual('1');// The operation fails. 311 }); 312 }); 313} 314``` 315 316Example 4: Set the parameter type to **anyString**. 317 318```javascript 319import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium'; 320 321export default function ActsAbilityTest() { 322 describe('ActsAbilityTest', function () { 323 it('testMockfunc', 0, function () { 324 console.info("it1 begin"); 325 326 // 1. Create a MockKit object. 327 let mocker = new MockKit(); 328 329 // 2. Define the ClassName class, which contains two functions, and then create a claser object. 330 class ClassName { 331 constructor() { 332 } 333 334 method_1(arg) { 335 return '888888'; 336 } 337 338 method_2(arg) { 339 return '999999'; 340 } 341 } 342 343 let claser = new ClassName(); 344 345 // 3. Mock method_1 of the ClassName class. 346 let mockfunc = mocker.mockFunc(claser, claser.method_1); 347 // Set the following parameters as required. 348 when(mockfunc)(ArgumentMatchers.anyString).afterReturn('1'); 349 350 // 4. Assert whether the mocked function is implemented as expected. 351 // The operation is successful if a string is passed in. 352 expect(claser.method_1('test')).assertEqual('1'); // The operation is successful. 353 expect(claser.method_1('abc')).assertEqual('1'); // The operation is successful. 354 355 // The operation fails if a number or a Boolean value is passed in. 356 //expect(claser.method_1(123)).assertEqual('1'); // The operation fails. 357 //expect(claser.method_1(true)).assertEqual('1'); // The operation fails. 358 }); 359 }); 360} 361``` 362 363Example 5: Set the parameter type to **matchRegexs (Regex)**. 364```javascript 365import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium'; 366 367export default function ActsAbilityTest() { 368 describe('ActsAbilityTest', function () { 369 it('testMockfunc', 0, function () { 370 console.info("it1 begin"); 371 372 // 1. Create a MockKit object. 373 let mocker = new MockKit(); 374 375 // 2. Define the ClassName class, which contains two functions, and then create a claser object. 376 class ClassName { 377 constructor() { 378 } 379 380 method_1(arg) { 381 return '888888'; 382 } 383 384 method_2(arg) { 385 return '999999'; 386 } 387 } 388 389 let claser = new ClassName(); 390 391 // 3. Mock method_1 of the ClassName class. 392 let mockfunc = mocker.mockFunc(claser, claser.method_1); 393 // Set a regular expression to match, for example, /123456/. 394 when(mockfunc)(ArgumentMatchers.matchRegexs(/123456/)).afterReturn('1'); 395 396 // 4. Assert whether the mocked function is implemented as expected. 397 // The operation is successful if a string, for example, '1234567898', is passed in. 398 expect(claser.method_1('1234567898')).assertEqual('1'); // The operation is successful. 399 // The string '1234567898' matches the regular expression /123456/. 400 401 // The operation fails if '1234' is passed in. 402 //expect(claser.method_1('1234').assertEqual('1'); // The operation fails because '1234' does not match the regular expression /123456/. 403 }); 404 }); 405} 406``` 407 408Example 6: Use **verify()**. 409```javascript 410import {describe, expect, it, MockKit, when} from '@ohos/hypium'; 411 412export default function ActsAbilityTest() { 413 describe('ActsAbilityTest', function () { 414 it('testMockfunc', 0, function () { 415 console.info("it1 begin"); 416 417 // 1. Create a MockKit object. 418 let mocker = new MockKit(); 419 420 // 2. Define the ClassName class, which contains two functions, and then create a claser object. 421 class ClassName { 422 constructor() { 423 } 424 425 method_1(...arg) { 426 return '888888'; 427 } 428 429 method_2(...arg) { 430 return '999999'; 431 } 432 } 433 434 let claser = new ClassName(); 435 436 // 3. Mock method_1 and method_2 of the ClassName class. 437 mocker.mockFunc(claser, claser.method_1); 438 mocker.mockFunc(claser, claser.method_2); 439 440 // 4. Call the following methods. 441 claser.method_1('abc', 'ppp'); 442 claser.method_1('abc'); 443 claser.method_1('xyz'); 444 claser.method_1(); 445 claser.method_1('abc', 'xxx', 'yyy'); 446 claser.method_1(); 447 claser.method_2('111'); 448 claser.method_2('111', '222'); 449 450 //5. Verify the mocked functions. 451 mocker.verify('method_1', []).atLeast(3); // The result is "failed". 452 // Verify whether 'method_1' with an empty parameter list was executed at least three times. 453 // The result is "failed" because 'method_1' with an empty parameter list was executed only twice in Step 4. 454 //mocker.verify('method_2',['111']).once(); // The result is "success". 455 //mocker.verify('method_2',['111',,'222']).once(); // The result is "success". 456 }); 457 }); 458} 459``` 460 461Example 7: Use **ignoreMock(obj, method)**. 462```javascript 463import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium'; 464 465export default function ActsAbilityTest() { 466 describe('ActsAbilityTest', function () { 467 it('testMockfunc', 0, function () { 468 console.info("it1 begin"); 469 470 // 1. Create a MockKit object. 471 let mocker = new MockKit(); 472 473 // 2. Define the ClassName class, which contains two functions, and then create a claser object. 474 class ClassName { 475 constructor() { 476 } 477 478 method_1(...arg) { 479 return '888888'; 480 } 481 482 method_2(...arg) { 483 return '999999'; 484 } 485 } 486 487 let claser = new ClassName(); 488 489 // 3. Mock method_1 and method_2 of the ClassName class. 490 let func_1 = mocker.mockFunc(claser, claser.method_1); 491 let func_2 = mocker.mockFunc(claser, claser.method_2); 492 493 // 4. Modify the mocked functions. 494 when(func_1)(ArgumentMatchers.anyNumber).afterReturn('4'); 495 when(func_2)(ArgumentMatchers.anyNumber).afterReturn('5'); 496 497 // 5. Call the following methods. 498 console.log(claser.method_1(123)); // The return value is 4, which is the same as the expected value in Step 4. 499 console.log(claser.method_2(456)); // The return value is 5, which is the same as the expected value in Step 4. 500 501 // 6. Restore method_1 using ignoreMock(). 502 mocker.ignoreMock(claser, claser.method_1); 503 // Call claser.method_1 and check the execution result. 504 console.log(claser.method_1(123)); // The return value is 888888, which is the same as that returned by the original function. 505 // Test with assertions. 506 expect(claser.method_1(123)).assertEqual('4'); // The return value is "failed", which meets the expected value of ignoreMock(). 507 claser.method_2(456); // The return value is 5, which is the same as the expected value in Step 4 because method_2 is not restored. 508 }); 509 }); 510} 511``` 512 513Example 8: Use **clear()**. 514 515```javascript 516import {describe, expect, it, MockKit, when, ArgumentMatchers} from '@ohos/hypium'; 517 518export default function ActsAbilityTest() { 519 describe('ActsAbilityTest', function () { 520 it('testMockfunc', 0, function () { 521 console.info("it1 begin"); 522 523 // 1. Create a MockKit object. 524 let mocker = new MockKit(); 525 526 // 2. Define the ClassName class, which contains two functions, and then create a claser object. 527 class ClassName { 528 constructor() { 529 } 530 531 method_1(...arg) { 532 return '888888'; 533 } 534 535 method_2(...arg) { 536 return '999999'; 537 } 538 } 539 let claser = new ClassName(); 540 541 // 3. Mock method_1 and method_2 of the ClassName class. 542 let func_1 = mocker.mockFunc(claser, claser.method_1); 543 let func_2 = mocker.mockFunc(claser, claser.method_2); 544 545 // 4. Modify the mocked functions. 546 when(func_1)(ArgumentMatchers.anyNumber).afterReturn('4'); 547 when(func_2)(ArgumentMatchers.anyNumber).afterReturn('5'); 548 549 // 5. Call the following methods. 550 //expect(claser.method_1(123)).assertEqual('4'); // The return value is the same as the expected value. 551 //expect(claser.method_2(456)).assertEqual('5'); // The return value is the same as the expected value. 552 553 // 6. Clear the mock operation. 554 mocker.clear(claser); 555 // Call claser.method_1 and check the execution result. 556 expect(claser.method_1(123)).assertEqual('4'); // The return value is "failed", which meets the expectation. 557 expect(claser.method_2(456)).assertEqual('5'); // The return value is "failed", which meets the expectation. 558 }); 559 }); 560} 561``` 562 563 564Example 9: Use **afterThrow(msg)**. 565 566```javascript 567import {describe, expect, it, MockKit, when} from '@ohos/hypium'; 568 569export default function ActsAbilityTest() { 570 describe('ActsAbilityTest', function () { 571 it('testMockfunc', 0, function () { 572 console.info("it1 begin"); 573 574 // 1. Create a MockKit object. 575 let mocker = new MockKit(); 576 577 // 2. Define the ClassName class, which contains two functions, and then create a claser object. 578 class ClassName { 579 constructor() { 580 } 581 582 method_1(arg) { 583 return '888888'; 584 } 585 } 586 587 let claser = new ClassName(); 588 589 // 3. Mock method_1 of the ClassName class. 590 let mockfunc = mocker.mockFunc(claser, claser.method_1); 591 592 // 4. Set the action to be performed when the test case ends. For example, set it to afterReturnNothing(), which returns no value. 593 when(mockfunc)('test').afterThrow('error xxx'); 594 595 // 5. Execute the mocked function, capture the exception, and use assertEqual() to check whether message meets the expectation. 596 try { 597 claser.method_1('test'); 598 } catch (e) { 599 expect(e).assertEqual('error xxx'); // The execution is successful. 600 } 601 }); 602 }); 603} 604``` 605 606Example 10: Mock asynchronous functions. 607 608```javascript 609import {describe, expect, it, MockKit, when} from '@ohos/hypium'; 610 611export default function ActsAbilityTest() { 612 describe('ActsAbilityTest', function () { 613 it('testMockfunc', 0, function () { 614 console.info("it1 begin"); 615 616 // 1. Create a MockKit object. 617 let mocker = new MockKit(); 618 619 // 2. Define the ClassName class, which contains two functions, and then create a claser object. 620 class ClassName { 621 constructor() { 622 } 623 624 async method_1(arg) { 625 return new Promise((res, rej) => { 626 // Perform asynchronous operations. 627 setTimeout(function () { 628 console.log ('Execute'); 629 res('Pass data'); 630 }, 2000); 631 }); 632 } 633 } 634 635 let claser = new ClassName(); 636 637 // 3. Mock method_1 of the ClassName class. 638 let mockfunc = mocker.mockFunc(claser, claser.method_1); 639 640 // 4. Set the action to be performed after the test case ends. For example, set it to afterRetrun(), which returns a custom promise. 641 when(mockfunc)('test').afterReturn(new Promise((res, rej) => { 642 console.log("do something"); 643 res('success something'); 644 })); 645 646 // 5. Execute the mocked function, that is, execute the promise. 647 claser.method_1('test').then(function (data) { 648 // Code for data processing 649 console.log('result : ' + data); 650 }); 651 }); 652 }); 653} 654``` 655 656Example 11: Mock a system function. 657 658```javascript 659export default function ActsAbilityTest() { 660 describe('ActsAbilityTest', function () { 661 it('test_systemApi', 0, function () { 662 // 1. Create a MockKit object. 663 let mocker = new MockKit(); 664 // 2. Mock the app.getInfo() function. 665 let mockf = mocker.mockFunc(app, app.getInfo); 666 when(mockf)('test').afterReturn('1'); 667 // The operation is successful. 668 expect(app.getInfo('test')).assertEqual('1'); 669 }); 670 }); 671} 672``` 673 674 675Example 12: Verify **times(count)**. 676 677```javascript 678import { describe, expect, it, MockKit, when } from '@ohos/hypium' 679 680export default function ActsAbilityTest() { 681 describe('ActsAbilityTest', function () { 682 it('test_verify_times', 0, function () { 683 // 1. Create a MockKit object. 684 let mocker = new MockKit(); 685 // 2. Define the class to be mocked. 686 class ClassName { 687 constructor() { 688 } 689 690 method_1(...arg) { 691 return '888888'; 692 } 693 } 694 // 3. Create an object of the class. 695 let claser = new ClassName(); 696 // 4. Mock a function, for example, method_1, of the object. 697 let func_1 = mocker.mockFunc(claser, claser.method_1); 698 // 5. Set the expected value to be returned by the mocked function. 699 when(func_1)('123').afterReturn('4'); 700 701 // 6. Execute the function several times, with parameters set as follows: 702 claser.method_1('123', 'ppp'); 703 claser.method_1('abc'); 704 claser.method_1('xyz'); 705 claser.method_1(); 706 claser.method_1('abc', 'xxx', 'yyy'); 707 claser.method_1('abc'); 708 claser.method_1(); 709 // 7. Check whether method_1 with the parameter of 'abc' was executed twice. 710 mocker.verify('method_1', ['abc']).times(2); 711 }); 712 }); 713} 714``` 715 716 717Example 13: Verify **atLeast(count)**. 718 719```javascript 720import { describe, expect, it, MockKit, when } from '@ohos/hypium' 721 722export default function ActsAbilityTest() { 723 describe('ActsAbilityTest', function () { 724 it('test_verify_atLeast', 0, function () { 725 // 1. Create a MockKit object. 726 let mocker = new MockKit(); 727 // 2. Define the class to be mocked. 728 class ClassName { 729 constructor() { 730 } 731 732 method_1(...arg) { 733 return '888888'; 734 } 735 } 736 737 // 3. Create an object of the class. 738 let claser = new ClassName(); 739 // 4. Mock a function, for example, method_1, of the object. 740 let func_1 = mocker.mockFunc(claser, claser.method_1); 741 // 5. Set the expected value to be returned by the mocked function. 742 when(func_1)('123').afterReturn('4'); 743 // 6. Execute the function several times, with parameters set as follows: 744 claser.method_1('123', 'ppp'); 745 claser.method_1('abc'); 746 claser.method_1('xyz'); 747 claser.method_1(); 748 claser.method_1('abc', 'xxx', 'yyy'); 749 claser.method_1(); 750 // 7. Check whether method_1 with an empty value was executed at least twice. 751 mocker.verify('method_1', []).atLeast(2); 752 }); 753 }); 754} 755``` 756 757#### Data Driving 758 759##### Constraints 760 761JsUnit provides the following data driving capability since [Hypium 1.0.2](https://repo.harmonyos.com/#/en/application/atomService/@ohos%2Fhypium): 762 763- Passes parameters for the specified test suite and test case. 764- Specifies the number of times that the test suite and test case are executed. 765 766The execution times of test cases and the parameters passed in each time are determined by the settings in **data.json**. The file content is as follows: 767 768>**NOTE**<br>The **data.json** file is in the same directory as the **.test.js** or **.test.ets** file. 769 770```json 771{ 772 "suites": [{ 773 "describe": ["actsAbilityTest"], 774 "stress": 2, 775 "params": { 776 "suiteParams1": "suiteParams001", 777 "suiteParams2": "suiteParams002" 778 }, 779 "items": [{ 780 "it": "testDataDriverAsync", 781 "stress": 2, 782 "params": [{ 783 "name": "tom", 784 "value": 5 785 }, { 786 "name": "jerry", 787 "value": 4 788 }] 789 }, { 790 "it": "testDataDriver", 791 "stress": 3 792 }] 793 }] 794} 795``` 796 797Parameter description: 798 799| | Name| Description | Mandatory| 800| :--- | :--------- | :------------------------------------ | ---- | 801| 1 | "suite" | Test suite configuration. | Yes | 802| 2 | "items" | Test case configuration. | Yes | 803| 3 | "describe" | Test suite name. | Yes | 804| 4 | "it" | Test case name. | Yes | 805| 5 | "params" | Parameters to be passed to the test suite or test case.| No | 806| 6 | "stress" | Number of times that the test suite or test case is executed. | No | 807 808The sample code is as follows: 809 810Import the **data.json** file to the **app.js** or **app.ets** file in the **TestAbility** directory, and set parameters before executing the **Hypium.hypiumTest()** method. 811 812```javascript 813import AbilityDelegatorRegistry from '@ohos.application.abilityDelegatorRegistry' 814import { Hypium } from '@ohos/hypium' 815import testsuite from '../test/List.test' 816import data from '../test/data.json'; 817 818... 819Hypium.setData(data); 820Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) 821... 822``` 823 824```javascript 825import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from '@ohos/hypium'; 826 827export default function abilityTest() { 828 describe('actsAbilityTest', function () { 829 it('testDataDriverAsync', 0, async function (done, data) { 830 console.info('name: ' + data.name); 831 console.info('value: ' + data.value); 832 done(); 833 }); 834 835 it('testDataDriver', 0, function () { 836 console.info('stress test'); 837 }); 838 }); 839} 840``` 841 842### How to Use 843 844JsUnit is released as an npm (hypium) package at the [service component official website](https://repo.harmonyos.com/#/en/application/atomService/@ohos%2Fhypium). You can download Deveco Studio, configure dependencies in the application project, and use JsUnit. For details about how to create a test project and execute test scripts, see the [OpenHarmony Test Framework](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001267284568). 845 846## UiTest Features 847 848| No. | Feature | Description | 849| ---- | ----------- | ------------------------------------------------------------ | 850| 1 | UiDriver | Provides the UI test entry. It provides APIs for locating a component, checking whether a component exists, and injecting a key.| 851| 2 | By | Describes the attributes (such as text, ID, and type) of UI components. `UiDriver` locates the component based on the attributes described by `By`.| 852| 3 | UiComponent | Provides the UI component object, which provides APIs for obtaining component attributes, clicking a component, and scrolling to search for a component.| 853| 4 | UiWindow | Provides the window object, which provides APIs for obtaining window attributes, dragging a window, and adjusting the window size.| 854 855Import the following to the test script: 856 857```typescript 858import {UiDriver,BY,UiComponent,Uiwindow,MatchPattern} from '@ohos.uitest' 859``` 860 861> **NOTICE**<br> 862> - All APIs provided by the `By` class are synchronous. You can use `builder` to call the APIs in chain mode to construct component filtering conditions. 863> - All the APIs provided by the `UiDriver` and `UiComponent` classes are asynchronous (in `Promise` mode), and `await` must be used. 864> - All UI test cases must be written in the asynchronous syntax and comply with the asynchronous test case specifications of JsUnit. 865 866 867 868Import the `By`, `UiDriver`, and `UiComponent` classes to the test case file, and then call the APIs to write test cases. 869 870```javascript 871import {describe, beforeAll, beforeEach, afterEach, afterAll, it, expect} from '@ohos/hypium' 872import {BY, UiDriver, UiComponent, MatchPattern} from '@ohos.uitest' 873 874export default async function abilityTest() { 875 describe('uiTestDemo', function() { 876 it('uitest_demo0', 0, async function() { 877 // create UiDriver 878 let driver = await UiDriver.create() 879 // find component by text 880 let button = await driver.findComponent(BY.text('hello').enabled(true)) 881 // click component 882 await button.click() 883 // get and assert component text 884 let content = await button.getText() 885 expect(content).assertEquals('clicked!') 886 }) 887 }) 888} 889``` 890 891### Using UiDriver 892 893As the main entry to UiTest, the `UiDriver` class provides APIs for component matching/search, key injection, coordinate clicking/swiping, and screenshot. 894 895| No. | API | Description | 896| ---- | ------------------------------------------------------------ | ------------------------ | 897| 1 | create():Promise<UiDriver> | Creates a **UiDriver** object. This API is a static method.| 898| 2 | findComponent(b:By):Promise<UiComponent> | Searches for a component. | 899| 3 | pressBack():Promise<void> | Presses the BACK button. | 900| 4 | click(x:number, y:number):Promise<void> | Clicks a specific point based on the given coordinates. | 901| 5 | swipe(x1:number, y1:number, x2:number, y2:number):Promise<void> | Swipes based on the given coordinates. | 902| 6 | assertComponentExist(b:By):Promise<void> | Asserts that the component matching the given attributes exists on the current page. | 903| 7 | delayMs(t:number):Promise<void> | Delays this **UiDriver** object for the specified duration. | 904| 8 | screenCap(s:path):Promise<void> | Captures the current screen. | 905| 9 | findWindow(filter: WindowFilter): Promise<UiWindow> | Searches for a window. | 906 907**assertComponentExist()** is an assertion API, which is used to assert that the target component exists on the current page. If the component does not exist, a JS exception will be thrown, causing the test case to fail. 908 909```javascript 910import {BY,UiDriver,UiComponent} from '@ohos.uitest' 911 912export default async function abilityTest() { 913 describe('UiTestDemo', function() { 914 it('Uitest_demo0', 0, async function(done) { 915 try{ 916 // create UiDriver 917 let driver = await UiDriver.create() 918 // assert text 'hello' exists on current Ui 919 await assertComponentExist(BY.text('hello')) 920 } finally { 921 done() 922 } 923 }) 924 }) 925} 926``` 927 928For details about the APIs of `UiDriver`, see [@ohos.uitest.d.ts](https://gitee.com/openharmony/interface_sdk-js/blob/master/api/@ohos.UiTest.d.ts) and [UiDriver](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-uitest.md#uidriver). 929 930### Using By 931 932UiTest provides a wide range of UI component feature description APIs in the `By` class to filter and match components. The APIs provided by `By` exhibit the following features: 933 934- Allow one or more attributes as the match conditions. For example, you can specify both the text and id attributes to find a component. 935- Provide a variety of match patterns (`EQUALS`, `CONTAINS`, `STARTS_WITH`, and `ENDS_WITH`) for component attributes. 936- Support relative positioning for components. APIs such as `isBefore` and `isAfter` can be used to specify the features of adjacent components to assist positioning. 937 938| No. | API | Description | 939| ---- | ---------------------------------- | ------------------------------------------------ | 940| 1 | id(i:number):By | Specifies the component ID. | 941| 2 | text(t:string, p?:MatchPattern):By | Specifies the component text. You can specify the match pattern. | 942| 3 | type(t:string)):By | Specifies the component type. | 943| 4 | enabled(e:bool):By | Specifies the component state, which can be enabled or disabled. | 944| 5 | clickable(c:bool):By | Specifies the clickable status of the component. | 945| 6 | focused(f:bool):By | Specifies the focused status of the component. | 946| 7 | scrollable(s:bool):By | Specifies the scrollable status of the component. | 947| 8 | selected(s:bool):By | Specifies the selected status of the component. | 948| 9 | isBefore(b:By):By | Specifies the attributes of the component that locates before the target component.| 949| 10 | isAfter(b:By):By | Specifies the attributes of the component that locates after the target component.| 950 951The `text` attribute supports match patterns `MatchPattern.EQUALS`, `MatchPattern.CONTAINS`, `MatchPattern.STARTS_WITH`, and `MatchPattern.ENDS_WITH`. The default match pattern is `MatchPattern.EQUALS`. 952 953For details about the APIs of `By`, see [@ohos.uitest.d.ts](https://gitee.com/openharmony/interface_sdk-js/blob/master/api/@ohos.UiTest.d.ts) and [By](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-uitest.md#by). 954 955#### Absolute Positioning of a Component 956 957Example 1: Search for component `Id_button`. 958 959```javascript 960let button = await driver.findComponent(BY.id(Id_button)) 961``` 962 963 Example 2: Search for component `Id_button` in the `enabled` state. Use this API when the component cannot be located based on a single attribute. 964 965```javascript 966let button = await driver.findComponent(BY.id(Id_button).enabled(true)) 967``` 968 969Use `By.id(x).enabled(y)` to specify multiple attributes of the target component. 970 971Example 3: Search for the component whose text contains `hello`. Use this API when the component attribute values cannot be completely determined. 972 973```javascript 974let txt = await driver.findComponent(BY.text("hello", MatchPattern.CONTAINS)) 975``` 976 977`By.text()` passes the second parameter `MatchPattern.CONTAINS` to specify the matching rule. The default rule is `MatchPattern.EQUALS`, that is, the text attribute of the target component must be equal to the specified value. 978 979#### Relative Positioning of a Component 980 981Example 1: Search for the switch component `ResourceTable.Id_switch` following the text component `Item3_3`. 982 983```javascript 984let switch = await driver.findComponent(BY.id(Id_switch).isAfter(BY.text("Item3_3"))) 985``` 986 987Use `By.isAfter` to specify the attributes of the feature component located before the target component for relative positioning. Generally, a feature component is a component that has a globally unique feature (for example, a unique ID or a unique text). 988 989Similarly, you can use `By.isBefore` to specify the attributes of the feature component located after the target component to implement relative positioning. 990 991### Using UiComponent 992 993The `UiComponent` class represents a UI component, which can be located by using `UiDriver.findComponent(by)`. It provides APIs for obtaining component attributes, clicking a component, scrolling to search for a component, and text injection. 994 995`UiComponent` provides the following APIs: 996 997| No. | API | Description | 998| ---- | --------------------------------- | ---------------------------------------------- | 999| 1 | click():Promise<void> | Clicks the component. | 1000| 2 | inputText(t:string):Promise<void> | Inputs text into the component. This API is applicable to text box components. | 1001| 3 | scrollSearch(s:By):Promise<bool> | Scrolls on this component to search for the target component. This API is applicable to the **List** components.| 1002| 4 | getText():Promise<string> | Obtains the component text. | 1003| 5 | getId():Promise<number> | Obtains the component ID. | 1004| 6 | getType():Promise<string> | Obtains the component type. | 1005| 7 | isEnabled():Promise<bool> | Obtains the component state, which can be enabled or disabled. | 1006 1007For details about the APIs of `UiComponent`, see [@ohos.uitest.d.ts](https://gitee.com/openharmony/interface_sdk-js/blob/master/api/@ohos.UiTest.d.ts) and [UiComponent](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-uitest.md#uicomponent). 1008 1009Example 1: Click a component. 1010 1011```javascript 1012let button = await driver.findComponent(BY.id(Id_button)) 1013await button.click() 1014``` 1015 1016Example 2: After obtaining component attributes, use **assert()** to make assertion. 1017 1018```javascript 1019let component = await driver.findComponent(BY.id(Id_title)) 1020expect(component !== null).assertTrue() 1021``` 1022 1023Example 3: Scroll on the **List** component to locate the child component with text `Item3_3`. 1024 1025```javascript 1026let list = await driver.findComponent(BY.id(Id_list)) 1027let found = await list.scrollSearch(BY.text("Item3_3")) 1028expect(found).assertTrue() 1029``` 1030 1031Example 4: Input text in a text box. 1032 1033```javascript 1034let editText = await driver.findComponent(BY.type('InputText')) 1035await editText.inputText("user_name") 1036``` 1037### Using UiWindow 1038 1039The `UiWindow` class represents a UI window, which can be located by using `UiDriver.findWindow(by)`. You can use the instance provided by this class to obtain window attributes, drag a window, and adjust the window size. 1040 1041`UiWindow` provides the following APIs: 1042 1043| No. | API | Description | 1044| ---- | ------------------------------------------------------------ | -------------------------------------------------- | 1045| 1 | getBundleName(): Promise<string> | Obtains the bundle name of the window. | 1046| 2 | getTitle(): Promise<string> | Obtains the window title. | 1047| 3 | focus(): Promise<bool> | Gives focus to the current window. | 1048| 4 | moveTo(x: number, y: number): Promise<bool>; | Moves the current window to the specified position. This API is applicable to the windows that can be moved.| 1049| 5 | resize(wide: number, height: number, direction: ResizeDirection): Promise<bool> | Adjusts the window size. This API is applicable to the windows that can be resized. | 1050| 6 | split(): Promise<bool> | Splits the current window. This API is applicable to the windows that support split-screen mode. | 1051| 7 | close(): Promise<bool> | Closes the current window. | 1052 1053For details about the APIs of `UiWindow`, see [@ohos.uitest.d.ts](https://gitee.com/openharmony/interface_sdk-js/blob/master/api/@ohos.UiTest.d.ts) and [UiWindow](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis/js-apis-uitest.md#uiwindow9). 1054 1055Example 1: Obtain the window attributes. 1056 1057```javascript 1058let window = await driver.findWindow({actived: true}) 1059let bundelName = await window.getBundleName() 1060``` 1061 1062Example 2: Move the window. 1063 1064```javascript 1065let window = await driver.findWindow({actived: true}) 1066await window.moveTo(500,500) 1067``` 1068 1069Example 3: Close the window. 1070 1071```javascript 1072let window = await driver.findWindow({actived: true}) 1073await window.close() 1074``` 1075 1076### How to Use 1077 1078 Download Deveco Studio, create a test project, and call the APIs provided by UiTest to perform related tests. For details about how to create a test project and execute test scripts, see [OpenHarmony Test Framework](https://developer.harmonyos.com/en/docs/documentation/doc-guides/ohos-openharmony-test-framework-0000001267284568). 1079 Run the following command to enable UiTest: 1080 1081>```shell 1082> hdc_std shell param set persist.ace.testmode.enabled 1 1083>``` 1084### Building UiTest 1085 1086> UiTest is not built with OpenHarmony 3.1 Release and needs to be manually built. 1087 1088If you want to modify UiTest code and verify the modification, use the following commands. 1089 1090#### Building UiTest 1091 1092```shell 1093./build.sh --product-name rk3568 --build-target uitestkit 1094``` 1095#### Sending UiTest 1096 1097```shell 1098hdc_std target mount 1099hdc_std shell mount -o rw,remount / 1100hdc_std file send uitest /system/bin/uitest 1101hdc_std file send libuitest.z.so /system/lib/module/libuitest.z.so 1102hdc_std shell chmod +x /system/bin/uitest 1103``` 1104 1105### Version Information 1106 1107| Version | Description | 1108| :------ | :----------------------------------------------------------- | 1109| 3.2.2.1 | 1. Added the APIs for obtaining and setting the screen orientation and flinging.<br>2. Added the window processing logic for unsupported scenarios. | 1110