191 lines
5.0 KiB
TypeScript
Raw Normal View History

import { join } from 'node:path';
import { assert } from '@midscene/shared/utils';
import { randomUUID } from 'node:crypto';
import { existsSync } from 'node:fs';
feat(web-integration): add support for new agent method(aiBoolean, aiString, aiNumber, aiLocate) (#658) * feat(web-integration): add support for new agent method(aiBoolean, aiString, aiNumber, aiLocate) * fix(core, web-integration): update data extraction logic and refine return types for agent methods * feat(site): add detailed descriptions and examples * fix(web-integration): remove unused properties from aiLocate return type and update UI titles * fix(core): enhance agent methods for better extraction and querying * fix(core): update test scripts and refine data extraction prompts * fix(core): refine return type in ExecutionTaskApply and remove unused import in inspect * fix(core): update data extraction logic and enhance type handling in Insight class * fix(web-integration): update import path for puppeteerAgentForTarget in player test file * fix(core): tests fix * fix(core): fix tests * fix(shared): enhance imageInfo tests by validating individual properties and updating snapshots * fix(site): remove waitForNavigationTimeout from Playwright integration examples * fix(site): update timeout configuration examples in FAQ for clarity * test(web-integration): remove unused client-extractor test and related snapshots * chore(core): fix query implementation * fix(report): improve data handling in DetailSide component and enhance output display * fix(core): refine data extraction prompts and improve error handling in PageTaskExecutor * fix(core): update data extraction prompt for clarity and type validation --------- Co-authored-by: yutao <yutao.tao@bytedance.com>
2025-04-29 13:36:49 +08:00
import { puppeteerAgentForTarget } from '@/puppeteer/agent-launcher';
import { ScriptPlayer, buildYaml, parseYamlScript } from '@/yaml';
import type { MidsceneYamlScriptWebEnv } from '@midscene/core';
import { describe, expect, test, vi } from 'vitest';
const serverRoot = join(__dirname, 'server_root');
const runYaml = async (yamlString: string, ignoreStatusAssertion = false) => {
const script = parseYamlScript(yamlString);
const statusUpdate = vi.fn();
const player = new ScriptPlayer<MidsceneYamlScriptWebEnv>(
script,
puppeteerAgentForTarget,
statusUpdate,
);
await player.run();
if (!ignoreStatusAssertion) {
assert(
player.status === 'done',
player.errorInSetup?.message || 'unknown error',
);
expect(statusUpdate).toHaveBeenCalled();
}
return {
player,
statusUpdate,
};
};
const shouldRunAITest =
process.platform !== 'linux' || process.env.AITEST === 'true';
describe('yaml utils', () => {
test('basic build && load', () => {
const script = buildYaml(
{
feat(web): use xpath and yaml as cache (#711) * feat(web-integration): use xpath for cache instead of id * feat(web-integration): enhance TaskCache to support xpaths for cache matching and add new test cases * feat(web-integration): add debug log for unknown page types in TaskCache * feat(web-integration): update caching logic and cache hit conditions for Plan and Locate tasks * chore(core): update debug log * feat(web-integration): update rspress.config and enhance TaskCache structure with new properties * feat(web-integration): recalculate id when hit cache * fix(web-integration): update mock implementation in task-cache test to use evaluate method * feat(web-integration): enhance element caching by adding XPath support and improving cache hit logic * chore(core): lint * feat(web-integration): improve XPath handling in web-extractor * test(web-integration): fix tests * feat(core, web-integration): add attributes to LocateResultElement and enhance element handling * fix(core): lint * feat(web-integration): add midsceneVersion to TaskCache and update cache validation logic * fix(core): test * fix(web-integration): update cache validation logic to prevent reading outdated midscene cache files * feat(web-integration): enhance TaskCache to track used cache items and improve cache retrieval logic * fix(core): xpath logic (#710) * feat(core): resue context for locate * feat(core): build yamlFlow from aiAction * feat(core): refine task-cache * feat(core): update cache * feat(core): refine task-cache * feat(core): refine task-cache * feat(core): remove unused checkElementExistsByXPath * feat(core): use yaml file as cache * chore(core): fix lint * chore(core): print warning for previous cache * refactor(core): remove quickAnswer references and improve element matching logic * fix(core): update import path for buildYamlFlowFromPlans * chore(web-integration): update output image and skip task error test * fix(web-integration): update test snapshots to handle beta versions * fix(web-integration): adjust test snapshots for version consistency * fix(web-integration): track original cache length and adjust matching logic in tests * fix(web-integration): update test URLs to reflect new target site and enable previously skipped test * chore(core): update cache docs * fix(core): test * feat(core): try to match element from plan * fix(web-integration): cache id stable when retry in palywright * fix(web-integration): typo * style(web-integration): lint * fix(web-integration): stable cacheid in tests * fix(web-integration): cache id --------- Co-authored-by: quanruzhuoxiu <quanruzhuoxiu@gmail.com>
2025-05-16 17:16:56 +08:00
url: 'https://bing.com',
waitForNetworkIdle: {
timeout: 1000,
continueOnNetworkIdleError: true,
},
},
[
{
name: 'search',
flow: [
{
aiAction: 'type "hello" in search box, hit enter',
},
],
},
],
);
expect(script).toMatchSnapshot();
const loadedScript = parseYamlScript(script);
expect(loadedScript).toMatchSnapshot();
});
test('load error with filePath', () => {
expect(() => {
parseYamlScript(
`
target:
a: 1
`,
'some_error_path',
);
}).toThrow(/some_error_path/);
});
test('player - bad params', async () => {
expect(async () => {
await runYaml(`
target:
serve: ${serverRoot}
`);
}).rejects.toThrow();
expect(async () => {
await runYaml(`
target:
serve: ${serverRoot}
viewportWidth: 0
`);
}).rejects.toThrow();
});
});
describe.skipIf(!shouldRunAITest)(
'player - e2e',
() => {
test('flush output even if assertion failed', async () => {
const outputPath = `./midscene_run/output/${randomUUID()}.json`;
const yamlString = `
target:
url: https://www.bing.com
output: ${outputPath}
tasks:
- name: local page
flow:
- aiQuery: >
the background color of the page, { color: 'white' | 'black' | 'red' | 'green' | 'blue' | 'yellow' | 'purple' | 'orange' | 'pink' | 'brown' | 'gray' | 'black'
- name: check content
flow:
- aiAssert: this is a food delivery service app
`;
await expect(async () => {
await runYaml(yamlString);
}).rejects.toThrow();
expect(existsSync(outputPath)).toBe(true);
});
test('cookie', async () => {
const yamlString = `
target:
url: http://httpbin.dev/cookies
cookie: ./tests/unit-test/fixtures/cookie/httpbin.dev_cookies.json
tasks:
- name: check cookie
flow:
- aiAssert: the value of midscene_foo is "bar"
`;
await runYaml(yamlString);
});
test('online server - lazy response', async () => {
const yamlString = `
target:
url: https://httpbin.org/delay/60000
waitForNetworkIdle:
timeout: 10
continueOnNetworkIdleError: false
tasks:
- name: check content
flow:
- aiAssert: the response is "Hello, world!"
`;
expect(async () => {
await runYaml(yamlString);
}).rejects.toThrow(/TimeoutError/i);
});
test('stop on task error', async () => {
const yamlString = `
target:
feat(web): use xpath and yaml as cache (#711) * feat(web-integration): use xpath for cache instead of id * feat(web-integration): enhance TaskCache to support xpaths for cache matching and add new test cases * feat(web-integration): add debug log for unknown page types in TaskCache * feat(web-integration): update caching logic and cache hit conditions for Plan and Locate tasks * chore(core): update debug log * feat(web-integration): update rspress.config and enhance TaskCache structure with new properties * feat(web-integration): recalculate id when hit cache * fix(web-integration): update mock implementation in task-cache test to use evaluate method * feat(web-integration): enhance element caching by adding XPath support and improving cache hit logic * chore(core): lint * feat(web-integration): improve XPath handling in web-extractor * test(web-integration): fix tests * feat(core, web-integration): add attributes to LocateResultElement and enhance element handling * fix(core): lint * feat(web-integration): add midsceneVersion to TaskCache and update cache validation logic * fix(core): test * fix(web-integration): update cache validation logic to prevent reading outdated midscene cache files * feat(web-integration): enhance TaskCache to track used cache items and improve cache retrieval logic * fix(core): xpath logic (#710) * feat(core): resue context for locate * feat(core): build yamlFlow from aiAction * feat(core): refine task-cache * feat(core): update cache * feat(core): refine task-cache * feat(core): refine task-cache * feat(core): remove unused checkElementExistsByXPath * feat(core): use yaml file as cache * chore(core): fix lint * chore(core): print warning for previous cache * refactor(core): remove quickAnswer references and improve element matching logic * fix(core): update import path for buildYamlFlowFromPlans * chore(web-integration): update output image and skip task error test * fix(web-integration): update test snapshots to handle beta versions * fix(web-integration): adjust test snapshots for version consistency * fix(web-integration): track original cache length and adjust matching logic in tests * fix(web-integration): update test URLs to reflect new target site and enable previously skipped test * chore(core): update cache docs * fix(core): test * feat(core): try to match element from plan * fix(web-integration): cache id stable when retry in palywright * fix(web-integration): typo * style(web-integration): lint * fix(web-integration): stable cacheid in tests * fix(web-integration): cache id --------- Co-authored-by: quanruzhuoxiu <quanruzhuoxiu@gmail.com>
2025-05-16 17:16:56 +08:00
url: https://bing.com/
tasks:
- name: assert1
flow:
- aiAssert: this is a food delivery service app
- name: assert2
flow:
- aiAssert: this is a search engine
`;
const { player } = await runYaml(yamlString, true);
expect(player.status).toBe('error');
expect(player.taskStatusList[0].status).toBe('error');
expect(player.taskStatusList[1].status).toBe('init');
});
test('allow continue on task error', async () => {
const yamlString = `
target:
feat(web): use xpath and yaml as cache (#711) * feat(web-integration): use xpath for cache instead of id * feat(web-integration): enhance TaskCache to support xpaths for cache matching and add new test cases * feat(web-integration): add debug log for unknown page types in TaskCache * feat(web-integration): update caching logic and cache hit conditions for Plan and Locate tasks * chore(core): update debug log * feat(web-integration): update rspress.config and enhance TaskCache structure with new properties * feat(web-integration): recalculate id when hit cache * fix(web-integration): update mock implementation in task-cache test to use evaluate method * feat(web-integration): enhance element caching by adding XPath support and improving cache hit logic * chore(core): lint * feat(web-integration): improve XPath handling in web-extractor * test(web-integration): fix tests * feat(core, web-integration): add attributes to LocateResultElement and enhance element handling * fix(core): lint * feat(web-integration): add midsceneVersion to TaskCache and update cache validation logic * fix(core): test * fix(web-integration): update cache validation logic to prevent reading outdated midscene cache files * feat(web-integration): enhance TaskCache to track used cache items and improve cache retrieval logic * fix(core): xpath logic (#710) * feat(core): resue context for locate * feat(core): build yamlFlow from aiAction * feat(core): refine task-cache * feat(core): update cache * feat(core): refine task-cache * feat(core): refine task-cache * feat(core): remove unused checkElementExistsByXPath * feat(core): use yaml file as cache * chore(core): fix lint * chore(core): print warning for previous cache * refactor(core): remove quickAnswer references and improve element matching logic * fix(core): update import path for buildYamlFlowFromPlans * chore(web-integration): update output image and skip task error test * fix(web-integration): update test snapshots to handle beta versions * fix(web-integration): adjust test snapshots for version consistency * fix(web-integration): track original cache length and adjust matching logic in tests * fix(web-integration): update test URLs to reflect new target site and enable previously skipped test * chore(core): update cache docs * fix(core): test * feat(core): try to match element from plan * fix(web-integration): cache id stable when retry in palywright * fix(web-integration): typo * style(web-integration): lint * fix(web-integration): stable cacheid in tests * fix(web-integration): cache id --------- Co-authored-by: quanruzhuoxiu <quanruzhuoxiu@gmail.com>
2025-05-16 17:16:56 +08:00
url: https://bing.com/
tasks:
- name: assert1
continueOnError: true
flow:
- aiAssert: this is a food delivery service app
- name: assert2
flow:
- aiAssert: this is a search engine
`;
const { player } = await runYaml(yamlString, true);
expect(player.status).toBe('done');
expect(player.taskStatusList[0].status).toBe('error');
expect(player.taskStatusList[1].status).toBe('done');
});
},
60 * 1000,
);