Skip to content

Commit

Permalink
define appium export in package.json & encapsulated screenshot pictur…
Browse files Browse the repository at this point in the history
…e path generation (#95)

* feat: define appium export in package.json

* feat: encapsulated screenshot picture path generation
  • Loading branch information
quanru authored Sep 23, 2024
1 parent 649d71d commit 43bf165
Show file tree
Hide file tree
Showing 13 changed files with 41 additions and 70 deletions.
2 changes: 0 additions & 2 deletions packages/midscene/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,6 @@ export async function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

export const commonScreenshotParam = { type: 'jpeg', quality: 75 } as any;

export function replacerForPageObject(key: string, value: any) {
if (value && value.constructor?.name === 'Page') {
return '[Page object]';
Expand Down
2 changes: 1 addition & 1 deletion packages/web-integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ then execute the command to start appium server:
appium --use-plugins=universal-xml
```

now you can use run tests for the iOS/Android device:
now you can use run tests for iOS/Android devices:

```bash
npm run test:ai -- appium
Expand Down
5 changes: 5 additions & 0 deletions packages/web-integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
"import": "./dist/es/playwright-report.js",
"require": "./dist/lib/playwright-report.js"
},
"./appium": {
"types": "./dist/types/appium.d.ts",
"import": "./dist/es/appium.js",
"require": "./dist/lib/appium.js"
},
"./debug": {
"types": "./dist/types/debug.d.ts",
"import": "./dist/es/debug.js",
Expand Down
17 changes: 7 additions & 10 deletions packages/web-integration/src/appium/page.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import fs from 'node:fs';
import { getTmpFile } from '@midscene/core/utils';
import { resizeImg } from '@midscene/shared/img';
import { DOMParser } from '@xmldom/xmldom';
import type { KeyInput as PuppeteerKeyInput } from 'puppeteer';
import type { Browser } from 'webdriverio';
import { type ElementInfo, clientExtractTextWithPosition } from '../extractor';
import type { AbstractPage, MouseButton, screenshotOptions } from '../page';
import type { AbstractPage, MouseButton } from '../page';

type WebKeyInput = PuppeteerKeyInput;

Expand Down Expand Up @@ -37,21 +38,17 @@ export class Page implements AbstractPage {
return infos;
}

async screenshot(options: screenshotOptions): Promise<void> {
if (!options.path) {
throw new Error('path is required for screenshot');
}

async screenshot(): Promise<string> {
const { width, height } = await this.browser.getWindowSize();
const screenshotBuffer = await this.browser.saveScreenshot(options.path);
const path = getTmpFile('png');
const screenshotBuffer = await this.browser.saveScreenshot(path);
const resizedScreenshotBuffer = await resizeImg(screenshotBuffer, {
width,
height,
});
fs.writeFileSync(path, resizedScreenshotBuffer);

if (options.path) {
fs.writeFileSync(options.path, resizedScreenshotBuffer);
}
return path;
}

get mouse() {
Expand Down
10 changes: 3 additions & 7 deletions packages/web-integration/src/common/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import Insight, {
type PlanningActionParamWaitFor,
type PlanningActionParamError,
} from '@midscene/core';
import { commonScreenshotParam, getTmpFile, sleep } from '@midscene/core/utils';
import { sleep } from '@midscene/core/utils';
import { base64Encoded } from '@midscene/shared/img';
import type { KeyInput } from 'puppeteer';
import type { ElementInfo } from '../extractor';
Expand Down Expand Up @@ -56,15 +56,11 @@ export class PageTaskExecutor {
}

private async recordScreenshot(timing: ExecutionRecorderItem['timing']) {
const file = getTmpFile('png');
await this.page.screenshot({
...commonScreenshotParam,
path: file,
});
const file = await this.page.screenshot();
const item: ExecutionRecorderItem = {
type: 'screenshot',
ts: Date.now(),
screenshot: base64Encoded(file),
screenshot: base64Encoded(file as string),
timing,
};
return item;
Expand Down
4 changes: 1 addition & 3 deletions packages/web-integration/src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ export async function parseContextFromWebPage(
assert(page, 'page is required');

const url = page.url();
const file = getTmpFile('jpeg');
await page.screenshot({ path: file });

const file = await page.screenshot();
const screenshotBuffer = readFileSync(file);
const screenshotBase64 = base64Encoded(file);
const captureElementSnapshot = await page.getElementInfos();
Expand Down
4 changes: 1 addition & 3 deletions packages/web-integration/src/debug/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import path from 'node:path';
import type { WebPage } from '@/common/page';
import type { ElementInfo } from '@/extractor';
import { NodeType } from '@/extractor/constants';
import { getTmpFile } from '@midscene/core/utils';
import {
processImageElementInfo,
resizeImg,
Expand All @@ -21,8 +20,7 @@ export async function generateExtractData(
disableSnapshot: boolean;
},
) {
const file = getTmpFile('png');
await page.screenshot({ path: file });
const file = await page.screenshot();
const screenshotBuffer = readFileSync(file);

const inputImgBase64 = screenshotBuffer.toString('base64');
Expand Down
2 changes: 1 addition & 1 deletion packages/web-integration/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ export type { PlayWrightAiFixtureType } from './playwright';

export { PuppeteerAgent } from './puppeteer';
export { PlaywrightAgent } from './playwright';
export { AppiumAgent } from './appium';
export { AppiumAgent, AppiumPage } from './appium';

export { generateExtractData } from './debug';
11 changes: 1 addition & 10 deletions packages/web-integration/src/page.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
import type { WebKeyInput } from './common/page';
import type { ElementInfo } from './extractor';

type imageType = 'jpeg' | 'png';
type encodingType = 'base64' | 'binary';

export type screenshotOptions = {
path?: string;
encoding?: encodingType;
type?: imageType;
quality?: number;
};
export type MouseButton = 'left' | 'right' | 'middle';

export abstract class AbstractPage {
abstract pageType: string;
abstract screenshot(options?: screenshotOptions): Promise<void>;
abstract screenshot(): Promise<string>;
abstract getElementInfos(): Promise<ElementInfo[]>;
abstract url(): string;

Expand Down
25 changes: 6 additions & 19 deletions packages/web-integration/src/puppeteer/base-page.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { readFileSync, writeFileSync } from 'node:fs';
import { getTmpFile } from '@midscene/core/utils';
import { resizeImg } from '@midscene/shared/img';
import type { Page as PlaywrightPage } from 'playwright';
import type { Page as PuppeteerPage } from 'puppeteer';
import type { WebKeyInput } from '../common/page';
import { getExtraReturnLogic } from '../common/utils';
import type { ElementInfo } from '../extractor';
import type { AbstractPage, screenshotOptions } from '../page';
import type { AbstractPage } from '../page';
import type { MouseButton } from '../page';

export class Page<
Expand Down Expand Up @@ -37,12 +38,7 @@ export class Page<
return captureElementSnapshot as ElementInfo[];
}

async screenshot(options: screenshotOptions): Promise<void> {
const { path } = options;
if (!path) {
throw new Error('path is required for screenshot');
}

async screenshot(): Promise<string> {
// get viewport size from page
const viewportSize: {
width: number;
Expand All @@ -56,6 +52,8 @@ export class Page<
};
});

const path = getTmpFile('jpeg');

await this.page.screenshot({
path,
type: 'jpeg',
Expand All @@ -71,18 +69,7 @@ export class Page<
writeFileSync(path, buf);
}

// return await this.page.screenshot({
// path,
// type: 'jpeg',
// quality: 75,
// clip: {
// x: 0,
// y: 0,
// width: viewportSize.width,
// height: viewportSize.height,
// scale: 1 / viewportSize.deviceScaleFactor,
// },
// });
return path;
}

url(): string {
Expand Down
14 changes: 10 additions & 4 deletions packages/web-integration/tests/ai/native/appium/dongchedi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const IOS_OPTIONS = {

const ANDROID_OPTIONS = {
port: 4723,
waitforTimeout: 10000,
connectionRetryTimeout: 120000,
connectionRetryCount: 3,
capabilities: {
platformName: 'Android',
'appium:automationName': 'UiAutomator2',
Expand All @@ -39,13 +42,16 @@ describe(
'appium integration',
() => {
it('懂车帝查找小米 SU7', async () => {
const page = await launchPage(IOS_OPTIONS);
const page = await launchPage(ANDROID_OPTIONS);
const mid = new AppiumAgent(page);
await mid.aiAction('点击同意按钮');
await sleep(3000);
await mid.aiAction('点击允许获取应用位置信息');
await sleep(3000);
await mid.aiAction('点击顶部输入框');
// await generateExtractData(page, './tmp');
await mid.aiAction('在输入框里输入"小米SU7",并点击搜索');
// await sleep(3000);
await sleep(3000);
await mid.aiAction('在输入框里输入"SU7",并点击搜索');
await sleep(3000);
const items = await mid.aiQuery(
'"{carName: string, price: number }[], return item name, price',
);
Expand Down
8 changes: 3 additions & 5 deletions packages/web-integration/tests/ai/web/playwright/tool.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import type { WebPage } from '@/common/page';
import { getElementInfos } from '@/debug';
Expand All @@ -16,10 +16,8 @@ export async function generateExtractData(
disableSnapshot: boolean;
},
) {
const buffer = await page.screenshot({
encoding: 'base64',
});
const inputImgBase64 = buffer.toString('base64');
const filePath = await page.screenshot();
const inputImgBase64 = readFileSync(filePath).toString('base64');

const {
elementsPositionInfo,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import path, { join } from 'node:path';
import { parseContextFromWebPage } from '@/common/utils';
import { generateExtractData } from '@/debug';
import { getTmpFile } from '@midscene/core/utils';
import { imageInfo } from '@midscene/shared/img';
import { describe, expect, it } from 'vitest';
import { launchPage } from '../ai/web/puppeteer/utils';
Expand Down Expand Up @@ -51,8 +50,7 @@ describe(
},
});

const shotpath = getTmpFile('jpeg');
await page.screenshot({ path: shotpath });
const shotpath = await page.screenshot();

const info = await imageInfo(shotpath);
expect(info.width).toBe(1080);
Expand All @@ -69,8 +67,7 @@ describe(
},
});

const shotpath = getTmpFile('jpeg');
await page.screenshot({ path: shotpath });
const shotpath = await page.screenshot();

const info = await imageInfo(shotpath);
expect(info.width).toBe(1080); // always 1x for screenshot
Expand Down

0 comments on commit 43bf165

Please sign in to comment.