mirror of
https://github.com/web-infra-dev/midscene.git
synced 2025-07-08 17:43:49 +00:00

* 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>
212 lines
6.6 KiB
TypeScript
212 lines
6.6 KiB
TypeScript
import path from 'node:path';
|
|
import { PuppeteerAgent } from '@/puppeteer';
|
|
import { sleep } from '@midscene/core/utils';
|
|
import { vlLocateMode } from '@midscene/shared/env';
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
import { launchPage } from './utils';
|
|
|
|
describe(
|
|
'puppeteer integration',
|
|
() => {
|
|
let resetFn: () => Promise<void>;
|
|
afterEach(async () => {
|
|
if (resetFn) {
|
|
try {
|
|
await resetFn();
|
|
} catch (e) {
|
|
console.warn('resetFn error');
|
|
console.warn(e);
|
|
}
|
|
}
|
|
});
|
|
|
|
it('Sauce Demo by Swag Lab', async () => {
|
|
const { originPage, reset } = await launchPage(
|
|
'https://www.saucedemo.com/',
|
|
);
|
|
resetFn = reset;
|
|
const onTaskStartTip = vi.fn();
|
|
const agent = new PuppeteerAgent(originPage, {
|
|
cacheId: 'puppeteer(Sauce Demo by Swag Lab)',
|
|
onTaskStartTip,
|
|
});
|
|
|
|
await sleep(10 * 1000);
|
|
|
|
const flag = await agent.aiBoolean('this is a login page');
|
|
expect(flag).toBe(true);
|
|
|
|
await agent.aiAction(
|
|
'type "standard_user" in user name input, type "secret_sauce" in password',
|
|
);
|
|
|
|
await agent.aiTap('Login');
|
|
|
|
expect(onTaskStartTip.mock.calls.length).toBeGreaterThan(1);
|
|
|
|
await expect(async () => {
|
|
await agent.aiWaitFor('there is a cookie prompt in the UI', {
|
|
timeoutMs: 10 * 1000,
|
|
});
|
|
}).rejects.toThrowError();
|
|
|
|
// find the items
|
|
const items = await agent.aiQuery(
|
|
'"{name: string, price: number, actionBtnName: string}[], return item name, price and the action button name on the lower right corner of each item (like "Remove")',
|
|
);
|
|
console.log('item list', items);
|
|
expect(items.length).toBeGreaterThanOrEqual(2);
|
|
|
|
await agent.aiAssert('The price of "Sauce Labs Backpack" is 29.99');
|
|
});
|
|
|
|
it('extract the Github service status', async () => {
|
|
const { originPage, reset } = await launchPage(
|
|
'https://www.githubstatus.com/',
|
|
);
|
|
resetFn = reset;
|
|
const agent = new PuppeteerAgent(originPage);
|
|
|
|
const result = await agent.aiQuery(
|
|
'this is a service status page. Extract all status data with this scheme: {[serviceName]: [statusText]}',
|
|
);
|
|
console.log('Github service status', result);
|
|
|
|
expect(async () => {
|
|
// there is no food delivery service on Github
|
|
await agent.aiAssert(
|
|
'there is a "food delivery" service on page and is in normal state',
|
|
);
|
|
});
|
|
});
|
|
|
|
it.skipIf(process.env.CI)('find widgets in antd', async () => {
|
|
const { originPage, reset } = await launchPage(
|
|
'https://ant.design/components/form/', // will be banned by the website on CI
|
|
);
|
|
resetFn = reset;
|
|
const agent = new PuppeteerAgent(originPage);
|
|
|
|
// await agent.aiAction('If pop-ups are displayed click seven days out alert');
|
|
await sleep(8000);
|
|
await agent.aiAction(
|
|
'Click the password input in the demo section on page, type "abc"',
|
|
);
|
|
|
|
await agent.aiAction(
|
|
'click the "icon" on the categories on the left, sleep 5s, in the newly loaded page, type "pause" in the icon search box(it shows "search icon here")',
|
|
);
|
|
|
|
const names = await agent.aiQuery(
|
|
'find all component names in the page, return in string[]',
|
|
);
|
|
|
|
expect(names.length).toBeGreaterThan(5);
|
|
});
|
|
|
|
it.skipIf(!vlLocateMode())(
|
|
'search engine with specific actions',
|
|
async () => {
|
|
const { originPage, reset } = await launchPage(
|
|
'https://www.baidu.com/',
|
|
);
|
|
resetFn = reset;
|
|
const agent = new PuppeteerAgent(originPage);
|
|
|
|
await agent.aiInput('AI 101', 'the search bar input');
|
|
await agent.aiTap('the search button');
|
|
|
|
await sleep(3000);
|
|
|
|
await agent.aiScroll({
|
|
direction: 'down',
|
|
scrollType: 'untilBottom',
|
|
});
|
|
|
|
await sleep(3000);
|
|
|
|
await agent.aiTap('the settings button', {
|
|
deepThink: true,
|
|
});
|
|
|
|
await agent.aiTap('搜索设置', {
|
|
deepThink: true,
|
|
});
|
|
|
|
await agent.aiTap('the close button of the popup', {
|
|
deepThink: true,
|
|
});
|
|
|
|
await agent.aiAssert('there is NOT a popup shown in the page');
|
|
},
|
|
);
|
|
|
|
it(
|
|
'search engine',
|
|
async () => {
|
|
const { originPage, reset } = await launchPage('https://www.bing.com/');
|
|
resetFn = reset;
|
|
const agent = new PuppeteerAgent(originPage);
|
|
await agent.aiAction('type "AI 101" in search box');
|
|
await agent.aiAction(
|
|
'type "Hello world" in search box, hit Enter, wait 2s',
|
|
);
|
|
|
|
await agent.aiWaitFor(
|
|
'there are some search results about "Hello world"',
|
|
);
|
|
},
|
|
3 * 60 * 1000,
|
|
);
|
|
|
|
it('scroll', async () => {
|
|
const htmlPath = path.join(__dirname, 'scroll.html');
|
|
const { originPage, reset } = await launchPage(`file://${htmlPath}`);
|
|
resetFn = reset;
|
|
const agent = new PuppeteerAgent(originPage);
|
|
await agent.aiAction(
|
|
'find the "Vertical 2" element, scroll down 200px, find the "Horizontal 2" element, scroll right 100px',
|
|
);
|
|
await agent.aiAssert(
|
|
'the "Horizontal 2", "Horizontal 4" and "Vertical 5" elements are visible',
|
|
);
|
|
});
|
|
|
|
it('not tracking active tab', async () => {
|
|
const { originPage, reset } = await launchPage('https://www.baidu.com/');
|
|
resetFn = reset;
|
|
const agent = new PuppeteerAgent(originPage, {
|
|
forceSameTabNavigation: false,
|
|
});
|
|
await agent.aiAction('Tap hao123 in the navigation bar');
|
|
await sleep(6000);
|
|
|
|
expect(async () => {
|
|
await agent.aiAssert('There is a weather forecast in the page');
|
|
}).rejects.toThrowError();
|
|
});
|
|
|
|
it('tracking active tab', async () => {
|
|
const { originPage, reset } = await launchPage('https://www.baidu.com/');
|
|
resetFn = reset;
|
|
const agent = new PuppeteerAgent(originPage, {
|
|
forceSameTabNavigation: true,
|
|
});
|
|
await agent.aiAction('Tap hao123 in the navigation bar');
|
|
|
|
await agent.aiWaitFor('There is a weather forecast in the page');
|
|
});
|
|
|
|
it.skip('Playground', async () => {
|
|
const { originPage, reset } = await launchPage('https://www.baidu.com/');
|
|
resetFn = reset;
|
|
const agent = new PuppeteerAgent(originPage);
|
|
// await agent.aiAction('Close the cookie prompt');
|
|
await agent.aiAction(
|
|
'Type "AI 101" in search box, hit Enter, wait 2s. If there is a cookie prompt, close it',
|
|
);
|
|
});
|
|
},
|
|
4 * 60 * 1000,
|
|
);
|