Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions harmony/javascript-sdk-demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
midscene_run/
37 changes: 37 additions & 0 deletions harmony/javascript-sdk-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# HarmonyOS demo (JavaScript SDK)

This is a demo to show how to use `@midscene/harmony` JavaScript SDK to control HarmonyOS devices.

## Steps

### Preparation

Create `.env` file

```shell
# Replace with your own API key
MIDSCENE_MODEL_BASE_URL="https://.../compatible-mode/v1"
MIDSCENE_MODEL_API_KEY="sk-abcdefghijklmnopqrstuvwxyz"
MIDSCENE_MODEL_NAME="qwen3-vl-plus"
MIDSCENE_MODEL_FAMILY="qwen3-vl"
```

Connect a HarmonyOS device with [HDC](https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V5/ide-hdc-V5)

Refer to this document if you want to use other models like Qwen: https://midscenejs.com/model-strategy.html

### Install

```bash
npm install
```

### Run

```bash
npm test
```

## Reference

https://midscenejs.com/harmony-api-reference
57 changes: 57 additions & 0 deletions harmony/javascript-sdk-demo/demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {
HarmonyAgent,
HarmonyDevice,
getConnectedDevices,
} from '@midscene/harmony';
import 'dotenv/config';

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

Promise.resolve(
(async () => {
const devices = await getConnectedDevices();
const device = new HarmonyDevice(devices[0].deviceId);

// 👀 init Midscene agent
const agent = new HarmonyAgent(device);
await device.connect();
await agent.aiAct('open Browser and go to https://www.ebay.com');

await sleep(5000);

// 👀 type keywords, perform a search
await agent.aiAct('type "Headphones" in search box, click search button');

// 👀 wait for the loading
await agent.aiWaitFor('there is at least one headphone item on page');

// 👀 understand the page content, find the items
const items = await agent.aiQuery(
'{itemTitle: string, price: Number}[], find item in list and corresponding price',
);
console.log('headphones in stock', items);

const isMoreThan1000 = await agent.aiBoolean(
'Is the price of the headphones more than 1000?',
);
console.log('isMoreThan1000', isMoreThan1000);

const price = await agent.aiNumber(
'What is the price of the first headphone?',
);
console.log('price', price);

const name = await agent.aiString(
'What is the name of the first headphone?',
);
console.log('name', name);

const location = await agent.aiLocate(
'What is the location of the first headphone?',
);
console.log('location', location);

// 👀 assert by AI
await agent.aiAssert('There is a category filter on the left');
})(),
);
18 changes: 18 additions & 0 deletions harmony/javascript-sdk-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "harmony-demo",
"private": true,
"version": "1.0.0",
"description": "> quick start",
"main": "index.js",
"type": "module",
"scripts": {
"test": "tsx demo.ts"
},
"author": "",
"license": "MIT",
"devDependencies": {
"@midscene/harmony": "latest",
"dotenv": "^16.4.5",
"tsx": "4.20.1"
}
}
2 changes: 2 additions & 0 deletions harmony/vitest-demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
midscene_run/
45 changes: 45 additions & 0 deletions harmony/vitest-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# HarmonyOS demo (vitest)

This is a demo to show how to use HDC to control HarmonyOS devices for automation tasks.

## Steps

### Preparation

Create `.env` file

```shell
# Replace with your own API key
MIDSCENE_MODEL_BASE_URL="https://.../compatible-mode/v1"
MIDSCENE_MODEL_API_KEY="sk-abcdefghijklmnopqrstuvwxyz"
MIDSCENE_MODEL_NAME="qwen3-vl-plus"
MIDSCENE_MODEL_FAMILY="qwen3-vl"
```

Connect a HarmonyOS device with [HDC](https://developer.huawei.com/consumer/en/doc/harmonyos-guides-V5/ide-hdc-V5)

Refer to this document if you want to use other models like Qwen: https://midscenejs.com/model-strategy.html

### Install

```bash
npm install
```

### Run

case1: Settings page scroll demo

```bash
npm run test -- setting.test.ts
```

case2: Todo app demo

```bash
npm run test -- todo.test.ts
```

## Reference

https://midscenejs.com/harmony-api-reference
18 changes: 18 additions & 0 deletions harmony/vitest-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "harmony-with-vitest-demo",
"private": true,
"version": "1.0.0",
"main": "index.js",
"type": "module",
"scripts": {
"test": "vitest --run"
},
"author": "",
"license": "MIT",
"devDependencies": {
"@midscene/harmony": "latest",
"@types/node": "^18.0.0",
"dotenv": "^16.4.5",
"vitest": "^2.1.8"
}
}
27 changes: 27 additions & 0 deletions harmony/vitest-demo/tests/setting.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { agentFromHdcDevice, getConnectedDevices } from '@midscene/harmony';
import { describe, it, vi } from 'vitest';
import 'dotenv/config';

vi.setConfig({
testTimeout: 90 * 1000,
});

describe(
'harmony integration',
async () => {
await it('HarmonyOS settings page demo for scroll', async () => {
const devices = await getConnectedDevices();
const agent = await agentFromHdcDevice(devices[0].deviceId);

await agent.launch('Settings');

await agent.aiAct('scroll list to bottom');
await agent.aiAct('open "Bluetooth" settings');
await agent.aiAct('scroll list to bottom');
await agent.aiAct('scroll list to top');
await agent.aiAct('swipe down one screen');
await agent.aiAct('swipe up one screen');
});
},
360 * 1000,
);
81 changes: 81 additions & 0 deletions harmony/vitest-demo/tests/todo.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import {
HarmonyAgent,
HarmonyDevice,
getConnectedDevices,
} from '@midscene/harmony';
import { beforeAll, describe, expect, it, vi } from 'vitest';
import 'dotenv/config';

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

vi.setConfig({
testTimeout: 240 * 1000,
hookTimeout: 240 * 1000,
});

const pageUrl = 'https://todomvc.com/examples/react/dist/';

describe('Test todo list', () => {
let agent: HarmonyAgent;

beforeAll(async () => {
const devices = await getConnectedDevices();
const device = new HarmonyDevice(devices[0].deviceId);
agent = new HarmonyAgent(device);
await device.connect();
await agent.aiAct(`open Browser and go to ${pageUrl}`);
await sleep(3000);
});

it(
'ai todo',
async () => {
await agent.aiAct(
"type 'Study JS today' in the task box input and press the Enter key",
);
await agent.aiAct(
"type 'Study Rust tomorrow' in the task box input and press the Enter key",
);
await agent.aiAct(
"type 'Study AI the day after tomorrow' in the task box input and press the Enter key",
);
await agent.aiAct(
'move the mouse to the second item in the task list and click the delete button on the right of the second task',
);
await agent.aiAct(
'click the check button on the left of the second task',
);
await agent.aiAct(
"click the 'completed' status button below the task list",
);

const list = await agent.aiQuery('string[], the complete task list');
expect(list.length).toEqual(1);

await agent.aiAssert(
'Near the bottom of the list, there is a tip shows "1 item left".',
);

const name = await agent.aiString(
'What is the name of the first todo?',
);
console.log('name', name);

const todoCount = await agent.aiNumber(
'How many todos are there in the list?',
);
console.log('todoCount', todoCount);

const isAllCompleted = await agent.aiBoolean(
'Is all todos completed?',
);
console.log('isAllCompleted', isAllCompleted);

const location = await agent.aiLocate(
'What is the location of the first todo?',
);
console.log('location', location);
},
720 * 1000,
);
});