@midscene/web 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/index.js +342 -114
- package/dist/es/playwright-report.js +2380 -0
- package/dist/lib/index.js +343 -114
- package/dist/lib/playwright-report.js +2383 -0
- package/dist/script/htmlElement.js +596 -25
- package/dist/script/types/htmlElement.d.ts +2 -0
- package/dist/types/index.d.ts +116 -21
- package/dist/types/playwright-report.d.ts +10 -0
- package/package.json +25 -4
- package/modern.config.ts +0 -13
- package/modern.inspect.config.ts +0 -20
- package/playwright.config.ts +0 -42
- package/src/html-element/constants.ts +0 -10
- package/src/html-element/debug.ts +0 -3
- package/src/html-element/dom-util.ts +0 -11
- package/src/html-element/extractInfo.ts +0 -168
- package/src/html-element/index.ts +0 -1
- package/src/html-element/util.ts +0 -160
- package/src/img/img.ts +0 -132
- package/src/img/util.ts +0 -28
- package/src/index.ts +0 -2
- package/src/playwright/actions.ts +0 -276
- package/src/playwright/cdp.ts +0 -322
- package/src/playwright/element.ts +0 -74
- package/src/playwright/index.ts +0 -120
- package/src/playwright/utils.ts +0 -88
- package/src/puppeteer/element.ts +0 -49
- package/src/puppeteer/index.ts +0 -6
- package/src/puppeteer/utils.ts +0 -116
- package/tests/e2e/ai-auto-todo.spec.ts +0 -24
- package/tests/e2e/ai-xicha.spec.ts +0 -34
- package/tests/e2e/fixture.ts +0 -6
- package/tests/e2e/generate-test-data.spec.ts +0 -60
- package/tests/e2e/todo-app-midscene.spec.ts +0 -98
- package/tests/e2e/tool.ts +0 -63
- package/tsconfig.json +0 -23
- package/vitest.config.ts +0 -14
package/src/puppeteer/utils.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
// import { readFileSync } from 'fs';
|
|
2
|
-
// import { Buffer } from 'buffer';
|
|
3
|
-
// import assert from 'assert';
|
|
4
|
-
// import type { Browser, Page } from 'puppeteer';
|
|
5
|
-
// import type { Page as PlaywrightPage } from 'playwright';
|
|
6
|
-
// import { Element } from './index';
|
|
7
|
-
// import { alignCoordByTrim, base64Encoded, imageInfoOfBase64 } from '@/image';
|
|
8
|
-
// import { UIContext, PuppeteerParserOpt, PlaywrightParserOpt, Rect, BaseElement } from '@/types';
|
|
9
|
-
// import { getTmpFile } from '@/utils';
|
|
10
|
-
// import { pageScriptToGetTexts } from '@/query';
|
|
11
|
-
// import { describeUserPage } from '@/insight/prompt';
|
|
12
|
-
|
|
13
|
-
// export interface TextElement {
|
|
14
|
-
// content: string;
|
|
15
|
-
// rect: Rect;
|
|
16
|
-
// center: [number, number]; // center coordinates as [rect.left + rect.width/2, rect.top + rect.height/2], use this for better control of page
|
|
17
|
-
// locator: string;
|
|
18
|
-
// }
|
|
19
|
-
|
|
20
|
-
// export async function alignTextElements(
|
|
21
|
-
// screenshotBuffer: Buffer,
|
|
22
|
-
// elements: TextElement[],
|
|
23
|
-
// ): Promise<TextElement[]> {
|
|
24
|
-
// const textsAligned: TextElement[] = [];
|
|
25
|
-
// for (const item of elements) {
|
|
26
|
-
// const { rect } = item;
|
|
27
|
-
// const aligned = await alignCoordByTrim(screenshotBuffer, rect);
|
|
28
|
-
// item.rect = aligned;
|
|
29
|
-
// item.center = [
|
|
30
|
-
// Math.round(aligned.left + aligned.width / 2),
|
|
31
|
-
// Math.round(aligned.top + aligned.height / 2),
|
|
32
|
-
// ];
|
|
33
|
-
// textsAligned.push(item);
|
|
34
|
-
// }
|
|
35
|
-
// return textsAligned;
|
|
36
|
-
// }
|
|
37
|
-
|
|
38
|
-
// async function extractDataFromPage(page: Page, opt?: PuppeteerParserOpt): Promise<UIContext<Element>> {
|
|
39
|
-
// assert(page, 'page is required');
|
|
40
|
-
// const file = getTmpFile('jpeg');
|
|
41
|
-
// await page.screenshot({ path: file, type: 'jpeg', quality: 75 });
|
|
42
|
-
// const screenshotBuffer = readFileSync(file);
|
|
43
|
-
// const screenshotBase64 = base64Encoded(file);
|
|
44
|
-
// const size = await imageInfoOfBase64(screenshotBase64);
|
|
45
|
-
|
|
46
|
-
// const scripts = pageScriptToGetTexts(opt?.selector);
|
|
47
|
-
// const texts = (await page.evaluate(scripts)) as BaseElement[];
|
|
48
|
-
|
|
49
|
-
// // align texts
|
|
50
|
-
// const textsAligned = await alignTextElements(screenshotBuffer, texts);
|
|
51
|
-
|
|
52
|
-
// const baseElements = textsAligned.map((item) => {
|
|
53
|
-
// const { center, ...res } = item;
|
|
54
|
-
// return new Element(res);
|
|
55
|
-
// });
|
|
56
|
-
|
|
57
|
-
// const basicContext = {
|
|
58
|
-
// screenshotBase64,
|
|
59
|
-
// size,
|
|
60
|
-
// content: baseElements,
|
|
61
|
-
// };
|
|
62
|
-
|
|
63
|
-
// return {
|
|
64
|
-
// ...basicContext,
|
|
65
|
-
// describer: async () => {
|
|
66
|
-
// return describeUserPage(basicContext);
|
|
67
|
-
// },
|
|
68
|
-
// };
|
|
69
|
-
// }
|
|
70
|
-
|
|
71
|
-
// export async function parseContextFromPuppeteerPage(
|
|
72
|
-
// page: Page,
|
|
73
|
-
// opt?: PuppeteerParserOpt,
|
|
74
|
-
// ): Promise<UIContext<Element>> {
|
|
75
|
-
// return extractDataFromPage(page, opt);
|
|
76
|
-
// }
|
|
77
|
-
|
|
78
|
-
// export async function parseContextFromPuppeteerBrowser(browser: Browser): Promise<UIContext<Element>> {
|
|
79
|
-
// const pages = await browser.pages();
|
|
80
|
-
// let visiblePage: Page;
|
|
81
|
-
// if (!pages.length) {
|
|
82
|
-
// throw new Error('No page found in the puppeteer browser');
|
|
83
|
-
// } else if (pages.length === 1) {
|
|
84
|
-
// visiblePage = pages[0];
|
|
85
|
-
|
|
86
|
-
// // filter a visible page, otherwise use the last one
|
|
87
|
-
// } else {
|
|
88
|
-
// const candidates = [];
|
|
89
|
-
// for (const page of pages) {
|
|
90
|
-
// // eslint-disable-next-line @typescript-eslint/no-loop-func
|
|
91
|
-
// const isVisible = await page.evaluate(() => document.visibilityState === 'visible');
|
|
92
|
-
// if (isVisible) {
|
|
93
|
-
// candidates.push(page);
|
|
94
|
-
// }
|
|
95
|
-
// }
|
|
96
|
-
// if (candidates.length === 0) {
|
|
97
|
-
// const lastUrl = pages[pages.length - 1].url();
|
|
98
|
-
// console.warn(`There are no visible pages, use the last one (${lastUrl})`);
|
|
99
|
-
// visiblePage = candidates[candidates.length - 1];
|
|
100
|
-
// } else if (candidates.length === 1) {
|
|
101
|
-
// visiblePage = candidates[0];
|
|
102
|
-
// } else {
|
|
103
|
-
// const lastUrl = pages[pages.length - 1].url();
|
|
104
|
-
// console.warn(`Multiple visible pages found, use the last one (${lastUrl})`);
|
|
105
|
-
// visiblePage = candidates[candidates.length - 1];
|
|
106
|
-
// }
|
|
107
|
-
// }
|
|
108
|
-
// return parseContextFromPuppeteerPage(visiblePage);
|
|
109
|
-
// }
|
|
110
|
-
|
|
111
|
-
// export async function parseContextFromPlaywrightPage(
|
|
112
|
-
// page: PlaywrightPage,
|
|
113
|
-
// opt?: PlaywrightParserOpt,
|
|
114
|
-
// ): Promise<UIContext<Element>> {
|
|
115
|
-
// return extractDataFromPage(page as any as Page, opt); // seems key APIs are the same ?
|
|
116
|
-
// }
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { expect } from 'playwright/test';
|
|
2
|
-
import { test } from './fixture';
|
|
3
|
-
|
|
4
|
-
test.beforeEach(async ({ page }) => {
|
|
5
|
-
await page.goto('https://todomvc.com/examples/react/dist/');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
test('ai todo', async ({ ai, aiQuery }) => {
|
|
9
|
-
await ai('Enter "Learn JS today" in the task box, then press Enter to create');
|
|
10
|
-
await ai('Enter "Learn Rust tomorrow" in the task box, then press Enter to create');
|
|
11
|
-
await ai('Enter "Learning AI the day after tomorrow" in the task box, then press Enter to create');
|
|
12
|
-
await ai(
|
|
13
|
-
'Move your mouse over the second item in the task list and click the Delete button to the right of the second task',
|
|
14
|
-
);
|
|
15
|
-
await ai('Click the check button to the left of the second task');
|
|
16
|
-
await ai('Click the completed Status button below the task list');
|
|
17
|
-
|
|
18
|
-
const taskList = await aiQuery<string[]>('string[], tasks in the list');
|
|
19
|
-
expect(taskList.length).toBe(1);
|
|
20
|
-
expect(taskList[0]).toBe('Learning AI the day after tomorrow');
|
|
21
|
-
|
|
22
|
-
const placeholder = await ai('string, return the placeholder text in the input box', 'query');
|
|
23
|
-
expect(placeholder).toBe('What needs to be done?');
|
|
24
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { test } from './fixture';
|
|
2
|
-
|
|
3
|
-
test.beforeEach(async ({ page }) => {
|
|
4
|
-
page.setViewportSize({ width: 400, height: 905 });
|
|
5
|
-
await page.goto('https://heyteavivocity.meuu.online/home');
|
|
6
|
-
await page.waitForLoadState('networkidle');
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
test('ai order', async ({ ai }) => {
|
|
10
|
-
await ai('点击左上角语言切换按钮(英文、中文),在弹出的下拉列表中点击中文');
|
|
11
|
-
await ai('在向下滚动一屏');
|
|
12
|
-
await ai('直接点击多肉葡萄的规格按钮');
|
|
13
|
-
await ai('点击不使用吸管、点击冰沙推荐、点击正常冰推荐');
|
|
14
|
-
await ai('在向下滚动一屏');
|
|
15
|
-
await ai('点击标准甜、点击绿妍(推荐)、点击标准口味');
|
|
16
|
-
await ai('滚动到最下面');
|
|
17
|
-
await ai('点击选好了按钮');
|
|
18
|
-
await ai('点击右上角商品图标按钮');
|
|
19
|
-
|
|
20
|
-
// 随便滚动一下
|
|
21
|
-
await ai('滚动到最下面');
|
|
22
|
-
|
|
23
|
-
// const content = await aiQuery(query('购物车商品详情', {
|
|
24
|
-
// productName: "商品名称,在价格上面",
|
|
25
|
-
// productPrice: "商品价格",
|
|
26
|
-
// productDescription: "商品描述(饮品的各种参数,吸管、冰沙等),在价格下面",
|
|
27
|
-
// }));
|
|
28
|
-
|
|
29
|
-
// console.log('商品订单详情:', {
|
|
30
|
-
// productName: content.productName,
|
|
31
|
-
// productPrice: content.productPrice,
|
|
32
|
-
// productDescription: content.productDescription,
|
|
33
|
-
// });
|
|
34
|
-
});
|
package/tests/e2e/fixture.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { test } from '@playwright/test';
|
|
2
|
-
import { generateTestData, generateTestDataPath } from './tool';
|
|
3
|
-
|
|
4
|
-
test('generate todo test data', async ({ page }) => {
|
|
5
|
-
await page.goto('https://todomvc.com/examples/react/dist/');
|
|
6
|
-
// Add data
|
|
7
|
-
await page.getByTestId('text-input').click();
|
|
8
|
-
await page.keyboard.type('Learn Python');
|
|
9
|
-
await page.keyboard.press('Enter');
|
|
10
|
-
await page.getByTestId('text-input').click();
|
|
11
|
-
await page.keyboard.type('Learn Rust');
|
|
12
|
-
await page.keyboard.press('Enter');
|
|
13
|
-
await page.getByTestId('text-input').click();
|
|
14
|
-
await page.keyboard.type('Learn AI');
|
|
15
|
-
await page.keyboard.press('Enter');
|
|
16
|
-
await page.getByText('Learn Rust').hover();
|
|
17
|
-
|
|
18
|
-
const midsceneTestDataPath = generateTestDataPath('todo');
|
|
19
|
-
const buffer = await page.screenshot();
|
|
20
|
-
|
|
21
|
-
const base64String = buffer.toString('base64');
|
|
22
|
-
await generateTestData(page, midsceneTestDataPath, base64String);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('generate visualstudio test data', async ({ page }) => {
|
|
26
|
-
await page.goto('https://code.visualstudio.com/');
|
|
27
|
-
await page.waitForLoadState('networkidle');
|
|
28
|
-
|
|
29
|
-
const midsceneTestDataPath = generateTestDataPath('visualstudio');
|
|
30
|
-
const buffer = await page.screenshot();
|
|
31
|
-
|
|
32
|
-
const base64String = buffer.toString('base64');
|
|
33
|
-
await generateTestData(page, midsceneTestDataPath, base64String);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test('generate githubstatus test data', async ({ page }) => {
|
|
37
|
-
await page.setViewportSize({ width: 1920, height: 1080 });
|
|
38
|
-
await page.goto('https://www.githubstatus.com/');
|
|
39
|
-
await page.waitForLoadState('networkidle');
|
|
40
|
-
|
|
41
|
-
const midsceneTestDataPath = generateTestDataPath('githubstatus');
|
|
42
|
-
const buffer = await page.screenshot();
|
|
43
|
-
|
|
44
|
-
const base64String = buffer.toString('base64');
|
|
45
|
-
await generateTestData(page, midsceneTestDataPath, base64String);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('generate xicha test data', async ({ page }) => {
|
|
49
|
-
page.setViewportSize({ width: 400, height: 905 });
|
|
50
|
-
await page.goto('https://heyteavivocity.meuu.online/home');
|
|
51
|
-
await page.evaluate('window.localStorage.setItem("LOCALE", "zh-CN")');
|
|
52
|
-
await page.goto('https://heyteavivocity.meuu.online/home');
|
|
53
|
-
await page.waitForLoadState('networkidle');
|
|
54
|
-
|
|
55
|
-
const midsceneTestDataPath = generateTestDataPath('xicha');
|
|
56
|
-
const buffer = await page.screenshot();
|
|
57
|
-
|
|
58
|
-
const base64String = buffer.toString('base64');
|
|
59
|
-
await generateTestData(page, midsceneTestDataPath, base64String);
|
|
60
|
-
});
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
// import { test, expect, type Page } from '@playwright/test';
|
|
2
|
-
// import Insight, { TextElement, query } from 'midscene';
|
|
3
|
-
// import { retrieveElements, retrieveOneElement } from 'midscene/query';
|
|
4
|
-
|
|
5
|
-
// test.beforeEach(async ({ page }) => {
|
|
6
|
-
// await page.goto('https://todomvc.com/examples/react/dist/');
|
|
7
|
-
// });
|
|
8
|
-
|
|
9
|
-
// const TODO_ITEMS = ['buy some cheese', 'feed the cat', 'book a doctors appointment'];
|
|
10
|
-
|
|
11
|
-
// interface InputBoxSection {
|
|
12
|
-
// element: TextElement;
|
|
13
|
-
// toggleAllBtn: TextElement;
|
|
14
|
-
// placeholder: string;
|
|
15
|
-
// inputValue: string;
|
|
16
|
-
// }
|
|
17
|
-
|
|
18
|
-
// interface TodoItem {
|
|
19
|
-
// name: string;
|
|
20
|
-
// finished: boolean;
|
|
21
|
-
// }
|
|
22
|
-
|
|
23
|
-
// interface ControlLayerSection {
|
|
24
|
-
// numbersLeft: number;
|
|
25
|
-
// tipElement: TextElement;
|
|
26
|
-
// controlElements: TextElement[];
|
|
27
|
-
// }
|
|
28
|
-
|
|
29
|
-
// // A comprehensive parser for page content
|
|
30
|
-
// const parsePage = async (page: Page) => {
|
|
31
|
-
// const insight = await Insight.fromPlaywrightPage(page);
|
|
32
|
-
// const todoListPage = await insight.segment({
|
|
33
|
-
// 'input-box': query<InputBoxSection>('an input box to type item and a "toggle-all" button', {
|
|
34
|
-
// element: retrieveOneElement('input box'),
|
|
35
|
-
// toggleAllBtn: retrieveOneElement('toggle all button, if exists'),
|
|
36
|
-
// placeholder: 'placeholder string in the input box, string, if exists',
|
|
37
|
-
// inputValue: 'the value in the input box, string, if exists',
|
|
38
|
-
// }),
|
|
39
|
-
// 'todo-list': query<{ todoItems: TodoItem[] }>('a list with todo-data (if exists)', {
|
|
40
|
-
// todoItems: '{name: string, finished: boolean}[]',
|
|
41
|
-
// }),
|
|
42
|
-
// 'control-layer': query<ControlLayerSection>('status and control layer of todo (if exists)', {
|
|
43
|
-
// numbersLeft: 'number',
|
|
44
|
-
// tipElement: retrieveOneElement(
|
|
45
|
-
// 'the element indicates the number of remaining items, like `xx items left`',
|
|
46
|
-
// ),
|
|
47
|
-
// controlElements: retrieveElements('control elements, used to filter items'),
|
|
48
|
-
// }),
|
|
49
|
-
// });
|
|
50
|
-
|
|
51
|
-
// return todoListPage;
|
|
52
|
-
// };
|
|
53
|
-
|
|
54
|
-
// test.describe('New Todo', () => {
|
|
55
|
-
// test('should allow me to add todo items', async ({ page }) => {
|
|
56
|
-
// // add a todo item
|
|
57
|
-
// const todoPage = await parsePage(page);
|
|
58
|
-
// const inputBox = todoPage['input-box'];
|
|
59
|
-
// expect(inputBox).toBeTruthy();
|
|
60
|
-
|
|
61
|
-
// await page.mouse.click(...inputBox!.element.center);
|
|
62
|
-
// await page.keyboard.type(TODO_ITEMS[0], { delay: 100 });
|
|
63
|
-
// await page.keyboard.press('Enter');
|
|
64
|
-
|
|
65
|
-
// // update page parsing result, and check the interface
|
|
66
|
-
// const todoPage2 = await parsePage(page);
|
|
67
|
-
// expect(todoPage2['input-box'].inputValue).toBeFalsy();
|
|
68
|
-
// expect(todoPage2['input-box'].placeholder).toBeTruthy();
|
|
69
|
-
// expect(todoPage2['todo-list'].todoItems.length).toBe(1);
|
|
70
|
-
// expect(todoPage2['todo-list'].todoItems[0].name).toBe(TODO_ITEMS[0]);
|
|
71
|
-
|
|
72
|
-
// // add another item
|
|
73
|
-
// await page.mouse.click(...todoPage2['input-box'].element.center);
|
|
74
|
-
// await page.keyboard.type(TODO_ITEMS[1], { delay: 100 });
|
|
75
|
-
// await page.keyboard.press('Enter');
|
|
76
|
-
|
|
77
|
-
// // update page parsing result
|
|
78
|
-
// const todoPage3 = await parsePage(page);
|
|
79
|
-
// const items = todoPage3['todo-list'].todoItems;
|
|
80
|
-
// expect(items.length).toBe(2);
|
|
81
|
-
// expect(items[1].name).toEqual(TODO_ITEMS[1]);
|
|
82
|
-
// expect(items.some((item) => item.finished)).toBeFalsy();
|
|
83
|
-
// expect(todoPage3['control-layer'].numbersLeft).toBe(2);
|
|
84
|
-
|
|
85
|
-
// // will mark all as completed
|
|
86
|
-
// const toggleBtn = todoPage3['input-box'].toggleAllBtn;
|
|
87
|
-
// expect(toggleBtn).toBeTruthy();
|
|
88
|
-
// expect(todoPage3['todo-list'].todoItems.filter((item) => item.finished).length).toBe(0);
|
|
89
|
-
|
|
90
|
-
// await page.mouse.click(...toggleBtn!.center, { delay: 500 });
|
|
91
|
-
// await page.waitForTimeout(3000);
|
|
92
|
-
|
|
93
|
-
// const todoPage4 = await parsePage(page);
|
|
94
|
-
// const allItems = todoPage4['todo-list'].todoItems;
|
|
95
|
-
// expect(allItems.length).toBe(2);
|
|
96
|
-
// expect(allItems.filter((item) => item.finished).length).toBe(allItems.length);
|
|
97
|
-
// });
|
|
98
|
-
// });
|
package/tests/e2e/tool.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { Page as PlaywrightPage } from '@playwright/test';
|
|
4
|
-
import { resizeImg, saveBase64Image } from '@midscene/core/image';
|
|
5
|
-
import { getElementInfos } from '@/img/util';
|
|
6
|
-
import { processImageElementInfo } from '@/img/img';
|
|
7
|
-
|
|
8
|
-
export async function generateTestData(page: PlaywrightPage, targetDir: string, inputImgBase64: string) {
|
|
9
|
-
const { elementsPostionInfo, captureElementSnapshot, elementsPostionInfoWithoutText } =
|
|
10
|
-
await getElementInfos(page);
|
|
11
|
-
|
|
12
|
-
const inputImagePath = path.join(targetDir, 'input.png');
|
|
13
|
-
const outputImagePath = path.join(targetDir, 'output.png');
|
|
14
|
-
const outputWithoutTextImgPath = path.join(targetDir, 'output_without_text.png');
|
|
15
|
-
const resizeOutputImgPath = path.join(targetDir, 'resize-output.png');
|
|
16
|
-
const snapshotJsonPath = path.join(targetDir, 'element-snapshot.json');
|
|
17
|
-
|
|
18
|
-
const { compositeElementInfoImgBase64, compositeElementInfoImgWithoutTextBase64 } =
|
|
19
|
-
await processImageElementInfo({
|
|
20
|
-
elementsPostionInfo,
|
|
21
|
-
elementsPostionInfoWithoutText,
|
|
22
|
-
inputImgBase64,
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const resizeImgBase64 = await resizeImg(inputImgBase64);
|
|
26
|
-
|
|
27
|
-
writeFileSyncWithDir(snapshotJsonPath, JSON.stringify(captureElementSnapshot, null, 2));
|
|
28
|
-
await saveBase64Image({ base64Data: inputImgBase64, outputPath: inputImagePath });
|
|
29
|
-
await saveBase64Image({ base64Data: compositeElementInfoImgBase64, outputPath: outputImagePath });
|
|
30
|
-
await saveBase64Image({
|
|
31
|
-
base64Data: compositeElementInfoImgWithoutTextBase64,
|
|
32
|
-
outputPath: outputWithoutTextImgPath,
|
|
33
|
-
});
|
|
34
|
-
await saveBase64Image({ base64Data: resizeImgBase64, outputPath: resizeOutputImgPath });
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function generateTestDataPath(testDataName: string) {
|
|
38
|
-
// `dist/lib/index.js` Is the default export path
|
|
39
|
-
const modulePath = require.resolve('@midscene/core').replace('dist/lib/index.js', '');
|
|
40
|
-
const midsceneTestDataPath = path.join(modulePath, `tests/ai-model/inspector/test-data/${testDataName}`);
|
|
41
|
-
|
|
42
|
-
return midsceneTestDataPath;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function ensureDirectoryExistence(filePath: string) {
|
|
46
|
-
const dirname = path.dirname(filePath);
|
|
47
|
-
if (existsSync(dirname)) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
ensureDirectoryExistence(dirname);
|
|
51
|
-
mkdirSync(dirname);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
type WriteFileSyncParams = Parameters<typeof writeFileSync>;
|
|
55
|
-
|
|
56
|
-
export function writeFileSyncWithDir(
|
|
57
|
-
filePath: string,
|
|
58
|
-
content: WriteFileSyncParams[1],
|
|
59
|
-
options: WriteFileSyncParams[2] = {},
|
|
60
|
-
) {
|
|
61
|
-
ensureDirectoryExistence(filePath);
|
|
62
|
-
writeFileSync(filePath, content, options);
|
|
63
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"baseUrl": ".",
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"emitDeclarationOnly": true,
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"forceConsistentCasingInFileNames": true,
|
|
8
|
-
"isolatedModules": true,
|
|
9
|
-
"jsx": "preserve",
|
|
10
|
-
"lib": ["DOM", "ESNext"],
|
|
11
|
-
"moduleResolution": "node",
|
|
12
|
-
"paths": {
|
|
13
|
-
"@/*": ["./src/*"]
|
|
14
|
-
},
|
|
15
|
-
"target": "ES2017",
|
|
16
|
-
"resolveJsonModule": true,
|
|
17
|
-
"rootDir": "./",
|
|
18
|
-
"skipLibCheck": true,
|
|
19
|
-
"strict": true
|
|
20
|
-
},
|
|
21
|
-
"exclude": [ "node_modules"],
|
|
22
|
-
"include": ["src", "tests", "./playwright.config.ts"]
|
|
23
|
-
}
|
package/vitest.config.ts
DELETED