Skip to content

Commit 69ddc74

Browse files
committed
fix: fix unit-test for executor
1 parent 863e5a5 commit 69ddc74

File tree

7 files changed

+69
-81
lines changed

7 files changed

+69
-81
lines changed

.github/workflows/ai.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
2323
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
2424
MIDSCENE_MODEL_NAME: gpt-4o-2024-08-06
25-
MIDSCENE_DEBUG_AI_PROFILE: 1
25+
# MIDSCENE_DEBUG_AI_PROFILE: 1
2626

2727
steps:
2828
- uses: actions/checkout@v4

packages/midscene/src/action/executor.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,19 @@ export class Executor {
2020
// status of executor
2121
status: 'init' | 'pending' | 'running' | 'completed' | 'error';
2222

23-
onFlushUpdate?: () => void;
23+
onTaskStart?: (task: ExecutionTask) => void;
2424

2525
constructor(
2626
name: string,
2727
description?: string,
2828
tasks?: ExecutionTaskApply[],
29-
onFlushUpdate?: () => void,
29+
onTaskStart?: () => void,
3030
) {
3131
this.status = tasks && tasks.length > 0 ? 'pending' : 'init';
3232
this.name = name;
3333
this.description = description;
3434
this.tasks = (tasks || []).map((item) => this.markTaskAsPending(item));
35-
this.onFlushUpdate = onFlushUpdate;
35+
this.onTaskStart = onTaskStart;
3636
}
3737

3838
private markTaskAsPending(task: ExecutionTaskApply): ExecutionTask {
@@ -85,11 +85,11 @@ export class Executor {
8585
while (taskIndex < this.tasks.length) {
8686
const task = this.tasks[taskIndex];
8787
try {
88-
if (this.onFlushUpdate) {
89-
this.onFlushUpdate();
88+
if (this.onTaskStart) {
89+
this.onTaskStart(task);
9090
}
9191
} catch (e) {
92-
// console.error('error in onFlushUpdate', e);
92+
// console.error('error in onTaskStart', e);
9393
}
9494
assert(
9595
task.status === 'pending',
@@ -162,9 +162,7 @@ export class Executor {
162162
} else {
163163
this.status = 'error';
164164
}
165-
if (this.onFlushUpdate) {
166-
await this.onFlushUpdate();
167-
}
165+
168166
if (this.tasks.length) {
169167
// return the last output
170168
const outputIndex = Math.min(taskIndex, this.tasks.length - 1);

packages/midscene/src/insight/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export default class Insight<
9696
const startTime = Date.now();
9797
const { parseResult, elementById, rawResponse, usage } =
9898
await AiInspectElement({
99-
callAI,
99+
callAI: callAI || this.aiVendorFn,
100100
context,
101101
multi: Boolean(multi),
102102
targetElementDescription: queryPrompt,

packages/midscene/tests/ai/extract/extract.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ vi.setConfig({
88
hookTimeout: 30 * 1000,
99
});
1010

11-
const useModel = undefined;
12-
1311
const modelList: Array<'openAI' | 'coze'> = ['openAI'];
1412

1513
if (preferCozeModel('coze')) {
File renamed without changes.

packages/midscene/tests/ai/executor/index.test.ts renamed to packages/midscene/tests/unit-test/executor/index.test.ts

Lines changed: 52 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const insightFindTask = (shouldThrow?: boolean) => {
2323
param: {
2424
prompt: 'test',
2525
},
26+
locate: null,
2627
async executor(param, taskContext) {
2728
if (shouldThrow) {
2829
const { task } = taskContext;
@@ -46,70 +47,58 @@ const insightFindTask = (shouldThrow?: boolean) => {
4647
return insightFindTask;
4748
};
4849

49-
vi.setConfig({
50-
testTimeout: 40 * 1000,
51-
});
52-
5350
describe('executor', () => {
54-
it(
55-
'insight - basic run',
56-
async () => {
57-
const insightTask1 = insightFindTask();
58-
const flushResultData = 'abcdef';
59-
const taskParam = {
60-
action: 'tap',
61-
anything: 'acceptable',
62-
};
63-
const tapperFn = vi.fn();
64-
const actionTask: ExecutionTaskActionApply = {
65-
type: 'Action',
66-
param: taskParam,
67-
executor: tapperFn,
68-
};
69-
const actionTask2: ExecutionTaskActionApply = {
70-
type: 'Action',
71-
param: taskParam,
72-
executor: async () => {
73-
return {
74-
output: flushResultData,
75-
} as any;
76-
},
77-
};
51+
it('insight - basic run', async () => {
52+
const insightTask1 = insightFindTask();
53+
const flushResultData = 'abcdef';
54+
const taskParam = {
55+
action: 'tap',
56+
anything: 'acceptable',
57+
};
58+
const tapperFn = vi.fn();
59+
const actionTask: ExecutionTaskActionApply = {
60+
type: 'Action',
61+
param: taskParam,
62+
locate: null,
63+
executor: tapperFn,
64+
};
65+
const actionTask2: ExecutionTaskActionApply = {
66+
type: 'Action',
67+
param: taskParam,
68+
locate: null,
69+
executor: async () => {
70+
return {
71+
output: flushResultData,
72+
} as any;
73+
},
74+
};
7875

79-
const inputTasks = [insightTask1, actionTask, actionTask2];
80-
81-
const executor = new Executor(
82-
'test',
83-
'hello, this is a test',
84-
inputTasks,
85-
);
86-
const flushResult = await executor.flush();
87-
const tasks = executor.tasks as ExecutionTaskInsightLocate[];
88-
const { element } = tasks[0].output || {};
89-
expect(element).toBeTruthy();
90-
91-
expect(tasks.length).toBe(inputTasks.length);
92-
expect(tasks[0].status).toBe('finished');
93-
expect(tasks[0].output).toMatchSnapshot();
94-
expect(tasks[0].log?.dump).toBeTruthy();
95-
expect(tasks[0].timing?.end).toBeTruthy();
96-
expect(tasks[0].cache).toBeTruthy();
97-
expect(tasks[0].cache?.hit).toEqual(false);
98-
99-
expect(tapperFn).toBeCalledTimes(1);
100-
expect(tapperFn.mock.calls[0][0]).toBe(taskParam);
101-
expect(tapperFn.mock.calls[0][1].element).toBe(element);
102-
expect(tapperFn.mock.calls[0][1].task).toBeTruthy();
103-
104-
const dump = executor.dump();
105-
expect(dump.logTime).toBeTruthy();
106-
107-
expect(flushResult).toBe(flushResultData);
108-
},
109-
{
110-
timeout: 999 * 1000,
111-
},
112-
);
76+
const inputTasks = [insightTask1, actionTask, actionTask2];
77+
78+
const executor = new Executor('test', 'hello, this is a test', inputTasks);
79+
const flushResult = await executor.flush();
80+
const tasks = executor.tasks as ExecutionTaskInsightLocate[];
81+
expect(executor.isInErrorState()).toBeFalsy();
82+
const { element } = tasks[0].output || {};
83+
expect(element).toBeTruthy();
84+
85+
expect(tasks.length).toBe(inputTasks.length);
86+
expect(tasks[0].status).toBe('finished');
87+
expect(tasks[0].output).toMatchSnapshot();
88+
expect(tasks[0].log?.dump).toBeTruthy();
89+
expect(tasks[0].timing?.end).toBeTruthy();
90+
expect(tasks[0].cache).toBeTruthy();
91+
expect(tasks[0].cache?.hit).toEqual(false);
92+
93+
expect(tapperFn).toBeCalledTimes(1);
94+
expect(tapperFn.mock.calls[0][0]).toBe(taskParam);
95+
expect(tapperFn.mock.calls[0][1].task).toBeTruthy();
96+
97+
const dump = executor.dump();
98+
expect(dump.logTime).toBeTruthy();
99+
100+
expect(flushResult).toBe(flushResultData);
101+
});
113102

114103
it('insight - init and append', async () => {
115104
const initExecutor = new Executor('test');
@@ -123,6 +112,7 @@ describe('executor', () => {
123112
action: 'tap',
124113
element: 'previous',
125114
},
115+
locate: null,
126116
executor: async () => {
127117
// delay 500
128118
await new Promise((resolve) => setTimeout(resolve, 500));

packages/midscene/tests/utils.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { readFileSync, writeFileSync } from 'node:fs';
2-
/* eslint-disable @typescript-eslint/no-magic-numbers */
32
import path, { join } from 'node:path';
43
import {
54
base64Encoded,
65
imageInfoOfBase64,
76
transformImgPathToBase64,
87
} from '@/image';
98
import Insight from '@/insight';
10-
import type { BaseElement, UIContext } from '@/types';
9+
import type { AIElementIdResponse, BaseElement, UIContext } from '@/types';
1110
import { vi } from 'vitest';
11+
import type { callAiFn } from '@/ai-model/common';
1212

1313
export function getFixture(name: string) {
1414
return join(__dirname, 'fixtures', name);
@@ -45,16 +45,18 @@ export function fakeInsight(content: string) {
4545
center: [250, 250],
4646
tap: vi.fn() as unknown,
4747
},
48-
// describer: basicPa
4948
] as unknown as BaseElement[],
5049
};
5150
const context: UIContext = {
5251
...basicContext,
5352
};
5453

55-
const aiVendor = () => ({
56-
elements: [{ id: '0' }],
57-
errors: [],
54+
const aiVendor: typeof callAiFn<AIElementIdResponse> = async () => ({
55+
content: {
56+
elements: [{ id: '0', reason: '', text: '' }],
57+
errors: [],
58+
},
59+
usage: undefined,
5860
});
5961

6062
const insight = new Insight(context, {

0 commit comments

Comments
 (0)