Skip to content

Commit

Permalink
fix: filter unused element for appium
Browse files Browse the repository at this point in the history
  • Loading branch information
quanru committed Sep 4, 2024
1 parent d510e97 commit 15f04ca
Show file tree
Hide file tree
Showing 14 changed files with 97 additions and 83 deletions.
5 changes: 1 addition & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,5 @@
},
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "modifications",
"[plaintext]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
"editor.formatOnSaveMode": "modifications"
}
8 changes: 6 additions & 2 deletions packages/shared/src/img/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export async function transformImgPathToBase64(inputPath: string) {
*/
export async function resizeImg(
inputData: string | Buffer,
newSize?: {
width: number;
height: number;
},
): Promise<string | Buffer> {
const isBase64 = typeof inputData === 'string';
const imageBuffer = isBase64
Expand All @@ -59,9 +63,9 @@ export async function resizeImg(
throw Error('Undefined width or height from the input image.');
}

const newSize = calculateNewDimensions(width, height);
const finalNewSize = newSize || calculateNewDimensions(width, height);

image.resize(newSize.width, newSize.height);
image.resize(finalNewSize.width, finalNewSize.height);
const resizedBuffer = await image.getBufferAsync(Jimp.MIME_PNG);

return isBase64 ? resizedBuffer.toString('base64') : resizedBuffer;
Expand Down
25 changes: 21 additions & 4 deletions packages/web-integration/src/appium/page.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import fs from 'node:fs';
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 { AbstractPage, MouseButton, screenshotOptions } from '../Page';
import { parsePageSource } from '../extractor/appium-exactor';
import { clientExtractTextWithPosition } from '../extractor';
import type { AbstractPage, MouseButton, screenshotOptions } from '../page';

type WebKeyInput = PuppeteerKeyInput;

Expand All @@ -21,16 +22,32 @@ export class Page implements AbstractPage {

async getElementInfos() {
const pageSource = await this.browser.getPageSource();
return parsePageSource(pageSource);
const { width, height } = await this.browser.getWindowSize();
const parser = new DOMParser();
const doc = parser.parseFromString(pageSource, 'text/xml');
const infos = clientExtractTextWithPosition(doc).filter(
(element) =>
element.rect.height !== height &&
element.rect.width !== width &&
element.rect.left !== 0 &&
element.rect.top !== 0 &&
element.attributes.visible === 'true',
);

return infos;
}

async screenshot(options: screenshotOptions): Promise<Buffer> {
if (!options.path) {
return Buffer.from('');
}

const { width, height } = await this.browser.getWindowSize();
const screenshotBuffer = await this.browser.saveScreenshot(options.path);
const resizedScreenshotBuffer = await resizeImg(screenshotBuffer);
const resizedScreenshotBuffer = await resizeImg(screenshotBuffer, {
width,
height,
});

if (options.path) {
fs.writeFileSync(options.path, resizedScreenshotBuffer);
Expand Down
2 changes: 1 addition & 1 deletion packages/web-integration/src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import assert from 'node:assert';
import type { Buffer } from 'node:buffer';
import fs, { readFileSync } from 'node:fs';
import path from 'node:path';
import type { ElementInfo } from '@/extractor/extractor';
import type { ElementInfo } from '@/extractor';
import type { PlaywrightParserOpt, UIContext } from '@midscene/core';
import { getTmpFile } from '@midscene/core/utils';
import { base64Encoded, imageInfoOfBase64 } from '@midscene/shared/img';
Expand Down
2 changes: 1 addition & 1 deletion packages/web-integration/src/debug/img/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ElementInfo } from '@/extractor';
import { NodeType } from '@/extractor/constants';
import type { ElementInfo } from '@/extractor/extractor';
import type { WebPage } from '../../common/page';

export async function getElementInfos(page: WebPage) {
Expand Down
2 changes: 1 addition & 1 deletion packages/web-integration/src/debug/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import type { WebPage } from '@/common/page';
import type { ElementInfo } from '@/extractor';
import { NodeType } from '@/extractor/constants';
import type { ElementInfo } from '@/extractor/extractor';
import { getTmpFile } from '@midscene/core/utils';
import {
processImageElementInfo,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { DOMParser } from '@xmldom/xmldom';
import type { ElementInfo } from './';
import { NodeType } from './constants';
import type { ElementInfo } from './extractor';
import { generateId, midsceneGenerateHash } from './util';

// https://github.com/appium/appium/tree/master/packages/universal-xml-plugin
Expand Down Expand Up @@ -55,11 +54,36 @@ function validTextNodeContent(node: Node): string {
return '';
}

// New parsePageSource function to extract from Appium's pageSource
export function parsePageSource(pageSource: string) {
const parser = new DOMParser();
const doc = parser.parseFromString(pageSource, 'text/xml');
return extractTextWithPosition(doc);
function getXPathForElement(element: Node): string {
if (element.nodeType !== 1) {
return '';
}

const getIndex = (sib: Node, name: string) => {
let count = 1;
for (let cur = sib.previousSibling; cur; cur = cur.previousSibling) {
if (cur.nodeType === 1 && cur.nodeName === name) {
count++;
}
}
return count;
};

const getPath = (node: Node, path = ''): string => {
if (node.parentNode) {
path = getPath(node.parentNode, path);
}

if (node.nodeType === 1) {
const index = getIndex(node, node.nodeName);
const tagName = node.nodeName.toLowerCase();
path += `/${tagName}[${index}]`;
}

return path;
};

return getPath(element);
}

// Perform DFS traversal and collect element information
Expand Down Expand Up @@ -107,7 +131,6 @@ export function extractTextWithPosition(initNode: Document): ElementInfo[] {
}

const xpath = getXPathForElement(node);

const elementInfo: ElementInfo = {
id: nodeHashId,
indexId: generateId(nodeIndex++),
Expand All @@ -125,6 +148,7 @@ export function extractTextWithPosition(initNode: Document): ElementInfo[] {
],
nodeType,
htmlNode: null,
nodePath: '',
};

elementInfoArray.push(elementInfo);
Expand All @@ -136,35 +160,3 @@ export function extractTextWithPosition(initNode: Document): ElementInfo[] {

return elementInfoArray;
}

function getXPathForElement(element: Node): string {
if (element.nodeType !== 1) {
return '';
}

const getIndex = (sib: Node, name: string) => {
let count = 1;
for (let cur = sib.previousSibling; cur; cur = cur.previousSibling) {
if (cur.nodeType === 1 && cur.nodeName === name) {
count++;
}
}
return count;
};

const getPath = (node: Node, path = ''): string => {
if (node.parentNode) {
path = getPath(node.parentNode, path);
}

if (node.nodeType === 1) {
const index = getIndex(node, node.nodeName);
const tagName = node.nodeName.toLowerCase();
path += `/${tagName}[${index}]`;
}

return path;
};

return getPath(element);
}
6 changes: 3 additions & 3 deletions packages/web-integration/src/extractor/debug.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { extractTextWithPosition } from '.';
import { webExtractTextWithPosition } from '.';
import { setExtractTextWithPositionOnWindow } from './util';

console.log(extractTextWithPosition(document.body, true));
console.log(JSON.stringify(extractTextWithPosition(document.body, false)));
console.log(webExtractTextWithPosition(document.body, true));
console.log(JSON.stringify(webExtractTextWithPosition(document.body, false)));
setExtractTextWithPositionOnWindow();
22 changes: 21 additions & 1 deletion packages/web-integration/src/extractor/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
export { extractTextWithPosition } from './extractor';
import type { NodeType } from '@midscene/shared/constants';

export interface ElementInfo {
id: string;
indexId?: string; // for debug use
nodePath: string;
nodeHashId: string;
locator: string;
attributes: {
nodeType: NodeType;
[key: string]: string;
};
nodeType: NodeType;
htmlNode: Node | null;
content: string;
rect: { left: number; top: number; width: number; height: number };
center: [number, number];
}

export { extractTextWithPosition as webExtractTextWithPosition } from './web-extractor';
export { extractTextWithPosition as clientExtractTextWithPosition } from './client-extractor';
2 changes: 1 addition & 1 deletion packages/web-integration/src/extractor/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import SHA256 from 'js-sha256';
import { extractTextWithPosition } from './extractor';
import { extractTextWithPosition } from './web-extractor';

// import { TEXT_MAX_SIZE } from './constants';
let debugMode = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
CONTAINER_MINI_WIDTH,
NodeType,
} from '@midscene/shared/constants';
import type { ElementInfo } from '.';
import {
isButtonElement,
isFormElement,
Expand All @@ -21,23 +22,6 @@ import {
visibleRect,
} from './util';

export interface ElementInfo {
id: string;
indexId?: string; // for debug use
nodePath: string;
nodeHashId: string;
locator: string;
attributes: {
nodeType: NodeType;
[key: string]: string;
};
nodeType: NodeType;
htmlNode: Node | null;
content: string;
rect: { left: number; top: number; width: number; height: number };
center: [number, number];
}

function collectElementInfo(node: Node, nodePath: string): ElementInfo | null {
const rect = visibleRect(node);
logger('collectElementInfo', node, node.nodeName, rect);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { WebKeyInput } from './common/page';
import type { ElementInfo } from './extractor/extractor';
import type { ElementInfo } from './extractor';

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

export type screenshotOptions = {
path?: string;
Expand Down
6 changes: 3 additions & 3 deletions packages/web-integration/src/playwright/page.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Page as Browser } from 'playwright';
import type { AbstractPage, screenshotOptions } from '../Page';
import type { MouseButton } from '../Page';
import type { WebKeyInput } from '../common/page';
import { getExtraReturnLogic } from '../common/utils';
import type { ElementInfo } from '../extractor/extractor';
import type { ElementInfo } from '../extractor';
import type { AbstractPage, screenshotOptions } from '../page';
import type { MouseButton } from '../page';

export class Page implements AbstractPage {
private browser: Browser;
Expand Down
6 changes: 3 additions & 3 deletions packages/web-integration/src/puppeteer/page.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Page as Browser } from 'puppeteer';
import type { AbstractPage, screenshotOptions } from '../Page';
import type { MouseButton } from '../Page';
import type { WebKeyInput } from '../common/page';
import { getExtraReturnLogic } from '../common/utils';
import type { ElementInfo } from '../extractor/extractor';
import type { ElementInfo } from '../extractor';
import type { AbstractPage, screenshotOptions } from '../page';
import type { MouseButton } from '../page';

export class Page implements AbstractPage {
private browser: Browser;
Expand Down

0 comments on commit 15f04ca

Please sign in to comment.