@godscene/web 1.7.11
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/README.md +7 -0
- package/bin/midscene-playground +3 -0
- package/bin/midscene-web +2 -0
- package/dist/es/bin.mjs +14 -0
- package/dist/es/bridge-mode/agent-cli-side.mjs +135 -0
- package/dist/es/bridge-mode/browser.mjs +2 -0
- package/dist/es/bridge-mode/common.mjs +41 -0
- package/dist/es/bridge-mode/index.mjs +4 -0
- package/dist/es/bridge-mode/io-client.mjs +99 -0
- package/dist/es/bridge-mode/io-server.mjs +218 -0
- package/dist/es/bridge-mode/page-browser-side.mjs +119 -0
- package/dist/es/cdp-proxy-constants.mjs +7 -0
- package/dist/es/cdp-proxy-manager.mjs +217 -0
- package/dist/es/cdp-proxy.mjs +151 -0
- package/dist/es/cdp-target-store.mjs +26 -0
- package/dist/es/chrome-extension/agent.mjs +8 -0
- package/dist/es/chrome-extension/cdpInput.mjs +172 -0
- package/dist/es/chrome-extension/cdpInput.mjs.LICENSE.txt +5 -0
- package/dist/es/chrome-extension/dynamic-scripts.mjs +36 -0
- package/dist/es/chrome-extension/index.mjs +5 -0
- package/dist/es/chrome-extension/page.mjs +733 -0
- package/dist/es/cli-options.mjs +97 -0
- package/dist/es/cli.mjs +26 -0
- package/dist/es/common/cache-helper.mjs +26 -0
- package/dist/es/common/viewport.mjs +36 -0
- package/dist/es/index.mjs +8 -0
- package/dist/es/mcp-server.mjs +33 -0
- package/dist/es/mcp-tools-cdp.mjs +164 -0
- package/dist/es/mcp-tools-puppeteer.mjs +246 -0
- package/dist/es/mcp-tools.mjs +81 -0
- package/dist/es/platform.mjs +37 -0
- package/dist/es/playwright/ai-fixture.mjs +364 -0
- package/dist/es/playwright/index.mjs +36 -0
- package/dist/es/playwright/page.mjs +42 -0
- package/dist/es/playwright/reporter/index.mjs +178 -0
- package/dist/es/puppeteer/agent-launcher.mjs +172 -0
- package/dist/es/puppeteer/base-page.mjs +830 -0
- package/dist/es/puppeteer/index.mjs +35 -0
- package/dist/es/puppeteer/page.mjs +7 -0
- package/dist/es/static/index.mjs +3 -0
- package/dist/es/static/static-agent.mjs +10 -0
- package/dist/es/static/static-page.mjs +123 -0
- package/dist/es/utils.mjs +6 -0
- package/dist/es/web-element.mjs +57 -0
- package/dist/es/web-page.mjs +272 -0
- package/dist/lib/bin.js +20 -0
- package/dist/lib/bridge-mode/agent-cli-side.js +172 -0
- package/dist/lib/bridge-mode/browser.js +36 -0
- package/dist/lib/bridge-mode/common.js +105 -0
- package/dist/lib/bridge-mode/index.js +44 -0
- package/dist/lib/bridge-mode/io-client.js +133 -0
- package/dist/lib/bridge-mode/io-server.js +255 -0
- package/dist/lib/bridge-mode/page-browser-side.js +163 -0
- package/dist/lib/cdp-proxy-constants.js +50 -0
- package/dist/lib/cdp-proxy-manager.js +273 -0
- package/dist/lib/cdp-proxy.js +179 -0
- package/dist/lib/cdp-target-store.js +66 -0
- package/dist/lib/chrome-extension/agent.js +42 -0
- package/dist/lib/chrome-extension/cdpInput.js +206 -0
- package/dist/lib/chrome-extension/cdpInput.js.LICENSE.txt +5 -0
- package/dist/lib/chrome-extension/dynamic-scripts.js +86 -0
- package/dist/lib/chrome-extension/index.js +58 -0
- package/dist/lib/chrome-extension/page.js +767 -0
- package/dist/lib/cli-options.js +131 -0
- package/dist/lib/cli.js +54 -0
- package/dist/lib/common/cache-helper.js +66 -0
- package/dist/lib/common/viewport.js +88 -0
- package/dist/lib/index.js +66 -0
- package/dist/lib/mcp-server.js +73 -0
- package/dist/lib/mcp-tools-cdp.js +208 -0
- package/dist/lib/mcp-tools-puppeteer.js +296 -0
- package/dist/lib/mcp-tools.js +115 -0
- package/dist/lib/platform.js +71 -0
- package/dist/lib/playwright/ai-fixture.js +401 -0
- package/dist/lib/playwright/index.js +89 -0
- package/dist/lib/playwright/page.js +76 -0
- package/dist/lib/playwright/reporter/index.js +212 -0
- package/dist/lib/puppeteer/agent-launcher.js +240 -0
- package/dist/lib/puppeteer/base-page.js +876 -0
- package/dist/lib/puppeteer/index.js +85 -0
- package/dist/lib/puppeteer/page.js +41 -0
- package/dist/lib/static/index.js +50 -0
- package/dist/lib/static/static-agent.js +44 -0
- package/dist/lib/static/static-page.js +157 -0
- package/dist/lib/utils.js +38 -0
- package/dist/lib/web-element.js +94 -0
- package/dist/lib/web-page.js +322 -0
- package/dist/types/bin.d.ts +1 -0
- package/dist/types/bridge-mode/agent-cli-side.d.ts +49 -0
- package/dist/types/bridge-mode/browser.d.ts +2 -0
- package/dist/types/bridge-mode/common.d.ts +74 -0
- package/dist/types/bridge-mode/index.d.ts +4 -0
- package/dist/types/bridge-mode/io-client.d.ts +10 -0
- package/dist/types/bridge-mode/io-server.d.ts +27 -0
- package/dist/types/bridge-mode/page-browser-side.d.ts +21 -0
- package/dist/types/cdp-proxy-constants.d.ts +4 -0
- package/dist/types/cdp-proxy-manager.d.ts +53 -0
- package/dist/types/cdp-proxy.d.ts +37 -0
- package/dist/types/cdp-target-store.d.ts +26 -0
- package/dist/types/chrome-extension/agent.d.ts +4 -0
- package/dist/types/chrome-extension/cdpInput.d.ts +52 -0
- package/dist/types/chrome-extension/dynamic-scripts.d.ts +3 -0
- package/dist/types/chrome-extension/index.d.ts +5 -0
- package/dist/types/chrome-extension/page.d.ts +120 -0
- package/dist/types/cli-options.d.ts +8 -0
- package/dist/types/cli.d.ts +1 -0
- package/dist/types/common/cache-helper.d.ts +20 -0
- package/dist/types/common/viewport.d.ts +17 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/mcp-server.d.ts +26 -0
- package/dist/types/mcp-tools-cdp.d.ts +23 -0
- package/dist/types/mcp-tools-puppeteer.d.ts +23 -0
- package/dist/types/mcp-tools.d.ts +14 -0
- package/dist/types/platform.d.ts +10 -0
- package/dist/types/playwright/ai-fixture.d.ts +133 -0
- package/dist/types/playwright/index.d.ts +13 -0
- package/dist/types/playwright/page.d.ts +11 -0
- package/dist/types/playwright/reporter/index.d.ts +28 -0
- package/dist/types/puppeteer/agent-launcher.d.ts +59 -0
- package/dist/types/puppeteer/base-page.d.ts +123 -0
- package/dist/types/puppeteer/index.d.ts +11 -0
- package/dist/types/puppeteer/page.d.ts +6 -0
- package/dist/types/static/index.d.ts +2 -0
- package/dist/types/static/static-agent.d.ts +5 -0
- package/dist/types/static/static-page.d.ts +46 -0
- package/dist/types/utils.d.ts +6 -0
- package/dist/types/web-element.d.ts +48 -0
- package/dist/types/web-page.d.ts +69 -0
- package/package.json +173 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { copyFileSync, cpSync, existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { getReportFileName, printReportMsg } from "@godscene/core/agent";
|
|
4
|
+
import { ReportMergingTool, isDirectoryModeReport } from "@godscene/core/report";
|
|
5
|
+
import { getMidsceneRunSubDir } from "@godscene/shared/common";
|
|
6
|
+
import { logMsg, replaceIllegalPathCharsAndSpace } from "@godscene/shared/utils";
|
|
7
|
+
function _define_property(obj, key, value) {
|
|
8
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
9
|
+
value: value,
|
|
10
|
+
enumerable: true,
|
|
11
|
+
configurable: true,
|
|
12
|
+
writable: true
|
|
13
|
+
});
|
|
14
|
+
else obj[key] = value;
|
|
15
|
+
return obj;
|
|
16
|
+
}
|
|
17
|
+
class MidsceneReporter {
|
|
18
|
+
static getMode(reporterType) {
|
|
19
|
+
if (!reporterType) return 'merged';
|
|
20
|
+
if ('merged' !== reporterType && 'separate' !== reporterType) throw new Error(`Unknown reporter type in playwright config: ${reporterType}, only support 'merged' or 'separate'`);
|
|
21
|
+
return reporterType;
|
|
22
|
+
}
|
|
23
|
+
getSeparatedFilename(testTitle) {
|
|
24
|
+
if (!this.testTitleToFilename.has(testTitle)) {
|
|
25
|
+
const baseTag = `playwright-${replaceIllegalPathCharsAndSpace(testTitle)}`;
|
|
26
|
+
const generatedFilename = getReportFileName(baseTag);
|
|
27
|
+
this.testTitleToFilename.set(testTitle, generatedFilename);
|
|
28
|
+
}
|
|
29
|
+
return this.testTitleToFilename.get(testTitle);
|
|
30
|
+
}
|
|
31
|
+
getReportFilename(testTitle) {
|
|
32
|
+
if ('merged' === this.mode) {
|
|
33
|
+
if (!this.mergedFilename) this.mergedFilename = getReportFileName('playwright-merged');
|
|
34
|
+
return this.mergedFilename;
|
|
35
|
+
}
|
|
36
|
+
if ('separate' === this.mode) {
|
|
37
|
+
if (!testTitle) throw new Error('testTitle is required in separate mode');
|
|
38
|
+
return this.getSeparatedFilename(testTitle);
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`Unknown mode: ${this.mode}`);
|
|
41
|
+
}
|
|
42
|
+
getReportPath(testTitle) {
|
|
43
|
+
const fileName = this.getReportFilename(testTitle);
|
|
44
|
+
if ('html-and-external-assets' === this.outputFormat) return join(getMidsceneRunSubDir('report'), fileName, 'index.html');
|
|
45
|
+
return join(getMidsceneRunSubDir('report'), `${fileName}.html`);
|
|
46
|
+
}
|
|
47
|
+
ensureOutputRoot() {
|
|
48
|
+
mkdirSync(getMidsceneRunSubDir('report'), {
|
|
49
|
+
recursive: true
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
copyReport(reportFilePath, targetPath) {
|
|
53
|
+
if (isDirectoryModeReport(reportFilePath)) {
|
|
54
|
+
const targetDir = dirname(targetPath);
|
|
55
|
+
mkdirSync(targetDir, {
|
|
56
|
+
recursive: true
|
|
57
|
+
});
|
|
58
|
+
cpSync(dirname(reportFilePath), targetDir, {
|
|
59
|
+
recursive: true,
|
|
60
|
+
force: true
|
|
61
|
+
});
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
mkdirSync(dirname(targetPath), {
|
|
65
|
+
recursive: true
|
|
66
|
+
});
|
|
67
|
+
copyFileSync(reportFilePath, targetPath);
|
|
68
|
+
}
|
|
69
|
+
collectReportInfo(test, result) {
|
|
70
|
+
const reportAnnotations = test.annotations.filter((annotation)=>'MIDSCENE_DUMP_ANNOTATION' === annotation.type && annotation.description);
|
|
71
|
+
if (0 === reportAnnotations.length || !this.mode) return;
|
|
72
|
+
const retry = result.retry ? `(retry #${result.retry})` : '';
|
|
73
|
+
const testId = `${test.id}${retry}`;
|
|
74
|
+
const projectName = this.hasMultipleProjects ? test.parent?.project()?.name : void 0;
|
|
75
|
+
const projectSuffix = projectName ? ` [${projectName}]` : '';
|
|
76
|
+
const testTitle = `${test.title}${projectSuffix}${retry}`;
|
|
77
|
+
const reports = reportAnnotations.map((annotation)=>annotation.description).filter((reportFilePath)=>{
|
|
78
|
+
if (existsSync(reportFilePath)) return true;
|
|
79
|
+
logMsg(`Failed to read Midscene report file: ${reportFilePath}`, new Error('Report file does not exist'));
|
|
80
|
+
return false;
|
|
81
|
+
}).map((reportFilePath)=>({
|
|
82
|
+
reportFilePath,
|
|
83
|
+
reportAttributes: {
|
|
84
|
+
testDuration: result.duration,
|
|
85
|
+
testStatus: result.status,
|
|
86
|
+
testTitle,
|
|
87
|
+
testId,
|
|
88
|
+
testDescription: test.parent?.title || ''
|
|
89
|
+
}
|
|
90
|
+
}));
|
|
91
|
+
if (0 === reports.length) return;
|
|
92
|
+
this.reportsByTestId.set(testId, {
|
|
93
|
+
testTitle,
|
|
94
|
+
reports
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
finalizeMergedReport() {
|
|
98
|
+
this.ensureOutputRoot();
|
|
99
|
+
const tool = new ReportMergingTool();
|
|
100
|
+
let reportCount = 0;
|
|
101
|
+
for (const entry of this.reportsByTestId.values())for (const report of entry.reports){
|
|
102
|
+
tool.append(report);
|
|
103
|
+
reportCount += 1;
|
|
104
|
+
}
|
|
105
|
+
if (0 === reportCount) return;
|
|
106
|
+
const targetName = this.getReportFilename();
|
|
107
|
+
if (1 === reportCount) {
|
|
108
|
+
const firstReport = Array.from(this.reportsByTestId.values())[0]?.reports[0];
|
|
109
|
+
if (!firstReport) return;
|
|
110
|
+
if (firstReport.reportFilePath) {
|
|
111
|
+
const targetPath = this.getReportPath();
|
|
112
|
+
this.copyReport(firstReport.reportFilePath, targetPath);
|
|
113
|
+
printReportMsg(targetPath);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const mergedReportPath = tool.mergeReports(targetName, {
|
|
117
|
+
overwrite: true
|
|
118
|
+
});
|
|
119
|
+
if (mergedReportPath) printReportMsg(mergedReportPath);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const mergedReportPath = tool.mergeReports(targetName, {
|
|
123
|
+
overwrite: true
|
|
124
|
+
});
|
|
125
|
+
if (mergedReportPath) printReportMsg(mergedReportPath);
|
|
126
|
+
}
|
|
127
|
+
finalizeSeparateReports() {
|
|
128
|
+
this.ensureOutputRoot();
|
|
129
|
+
for (const entry of this.reportsByTestId.values()){
|
|
130
|
+
const targetName = this.getReportFilename(entry.testTitle);
|
|
131
|
+
if (1 === entry.reports.length) {
|
|
132
|
+
const firstReport = entry.reports[0];
|
|
133
|
+
if (firstReport.reportFilePath) {
|
|
134
|
+
const targetPath = this.getReportPath(entry.testTitle);
|
|
135
|
+
this.copyReport(firstReport.reportFilePath, targetPath);
|
|
136
|
+
printReportMsg(targetPath);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const tool = new ReportMergingTool();
|
|
140
|
+
tool.append(firstReport);
|
|
141
|
+
const reportPath = tool.mergeReports(targetName, {
|
|
142
|
+
overwrite: true
|
|
143
|
+
});
|
|
144
|
+
if (reportPath) printReportMsg(reportPath);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const tool = new ReportMergingTool();
|
|
148
|
+
for (const report of entry.reports)tool.append(report);
|
|
149
|
+
const reportPath = tool.mergeReports(targetName, {
|
|
150
|
+
overwrite: true
|
|
151
|
+
});
|
|
152
|
+
if (reportPath) printReportMsg(reportPath);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async onBegin(config, _suite) {
|
|
156
|
+
this.hasMultipleProjects = (config.projects?.length || 0) > 1;
|
|
157
|
+
}
|
|
158
|
+
onTestBegin(_test, _result) {}
|
|
159
|
+
onTestEnd(test, result) {
|
|
160
|
+
this.collectReportInfo(test, result);
|
|
161
|
+
}
|
|
162
|
+
async onEnd() {
|
|
163
|
+
if ('merged' === this.mode) return void this.finalizeMergedReport();
|
|
164
|
+
if ('separate' === this.mode) this.finalizeSeparateReports();
|
|
165
|
+
}
|
|
166
|
+
constructor(options = {}){
|
|
167
|
+
_define_property(this, "mergedFilename", void 0);
|
|
168
|
+
_define_property(this, "testTitleToFilename", new Map());
|
|
169
|
+
_define_property(this, "reportsByTestId", new Map());
|
|
170
|
+
_define_property(this, "mode", void 0);
|
|
171
|
+
_define_property(this, "outputFormat", void 0);
|
|
172
|
+
_define_property(this, "hasMultipleProjects", false);
|
|
173
|
+
this.mode = MidsceneReporter.getMode(options.type ?? 'merged');
|
|
174
|
+
this.outputFormat = options.outputFormat ?? 'single-html';
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const reporter = MidsceneReporter;
|
|
178
|
+
export { reporter as default };
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { getDebug } from "@godscene/shared/logger";
|
|
3
|
+
import { assert } from "@godscene/shared/utils";
|
|
4
|
+
import { defaultViewportHeight, defaultViewportWidth, resolveWebViewportSize } from "../common/viewport.mjs";
|
|
5
|
+
import { PuppeteerAgent } from "./index.mjs";
|
|
6
|
+
import { DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT } from "@godscene/shared/constants";
|
|
7
|
+
import puppeteer from "puppeteer";
|
|
8
|
+
const defaultUA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36';
|
|
9
|
+
const defaultViewportScale = 0;
|
|
10
|
+
const defaultWaitForNetworkIdleTimeout = DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT;
|
|
11
|
+
function resolveAiActionContext(target, preference) {
|
|
12
|
+
const data = preference?.aiActContext ?? preference?.aiActionContext ?? target.aiActionContext;
|
|
13
|
+
return data;
|
|
14
|
+
}
|
|
15
|
+
const DANGEROUS_ARGS = [
|
|
16
|
+
'--no-sandbox',
|
|
17
|
+
'--disable-setuid-sandbox',
|
|
18
|
+
'--disable-web-security',
|
|
19
|
+
'--ignore-certificate-errors',
|
|
20
|
+
'--disable-features=IsolateOrigins',
|
|
21
|
+
'--disable-site-isolation-trials',
|
|
22
|
+
'--allow-running-insecure-content'
|
|
23
|
+
];
|
|
24
|
+
function validateChromeArgs(args, baseArgs) {
|
|
25
|
+
const newArgs = args.filter((arg)=>!baseArgs.some((baseArg)=>{
|
|
26
|
+
const argFlag = arg.split('=')[0];
|
|
27
|
+
const baseFlag = baseArg.split('=')[0];
|
|
28
|
+
return argFlag === baseFlag;
|
|
29
|
+
}));
|
|
30
|
+
const dangerousArgs = newArgs.filter((arg)=>DANGEROUS_ARGS.some((dangerous)=>arg.startsWith(dangerous)));
|
|
31
|
+
if (dangerousArgs.length > 0) console.warn(`Warning: Dangerous Chrome arguments detected: ${dangerousArgs.join(', ')}.\nThese arguments may reduce browser security. Use only in controlled testing environments.`);
|
|
32
|
+
}
|
|
33
|
+
const launcherDebug = getDebug('puppeteer:launcher');
|
|
34
|
+
function buildChromeArgs(options) {
|
|
35
|
+
const isWindows = 'win32' === process.platform;
|
|
36
|
+
const sandboxArgs = isWindows ? [] : [
|
|
37
|
+
'--no-sandbox',
|
|
38
|
+
'--disable-setuid-sandbox'
|
|
39
|
+
];
|
|
40
|
+
const featureArgs = [
|
|
41
|
+
'--disable-features=HttpsFirstBalancedModeAutoEnable',
|
|
42
|
+
'--disable-features=PasswordLeakDetection',
|
|
43
|
+
'--disable-save-password-bubble'
|
|
44
|
+
];
|
|
45
|
+
const userAgentArg = options?.userAgent ? [
|
|
46
|
+
`--user-agent="${options.userAgent}"`
|
|
47
|
+
] : [];
|
|
48
|
+
const windowSizeArg = options?.windowSize ? [
|
|
49
|
+
`--window-size=${options.windowSize.width},${options.windowSize.height}`
|
|
50
|
+
] : [];
|
|
51
|
+
const baseArgs = [
|
|
52
|
+
...sandboxArgs,
|
|
53
|
+
...featureArgs,
|
|
54
|
+
...userAgentArg,
|
|
55
|
+
...windowSizeArg
|
|
56
|
+
];
|
|
57
|
+
if (options?.chromeArgs?.length) {
|
|
58
|
+
validateChromeArgs(options.chromeArgs, baseArgs);
|
|
59
|
+
return [
|
|
60
|
+
...baseArgs,
|
|
61
|
+
...options.chromeArgs
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
return baseArgs;
|
|
65
|
+
}
|
|
66
|
+
async function launchPuppeteerPage(target, preference, browser, existingPage) {
|
|
67
|
+
assert(target.url, 'url is required');
|
|
68
|
+
const freeFn = [];
|
|
69
|
+
const ua = target.userAgent || defaultUA;
|
|
70
|
+
const { width, height } = resolveWebViewportSize(target);
|
|
71
|
+
let dpr = defaultViewportScale;
|
|
72
|
+
if (void 0 !== target.deviceScaleFactor && null !== target.deviceScaleFactor) {
|
|
73
|
+
assert('number' == typeof target.deviceScaleFactor, 'deviceScaleFactor must be a number');
|
|
74
|
+
dpr = target.deviceScaleFactor;
|
|
75
|
+
assert(dpr > 0, `deviceScaleFactor must be > 0, but got ${dpr}`);
|
|
76
|
+
}
|
|
77
|
+
const viewportConfig = {
|
|
78
|
+
width,
|
|
79
|
+
height,
|
|
80
|
+
deviceScaleFactor: dpr
|
|
81
|
+
};
|
|
82
|
+
const headed = preference?.headed || preference?.keepWindow;
|
|
83
|
+
const defaultViewportConfig = headed ? null : viewportConfig;
|
|
84
|
+
if (headed && '1' === process.env.CI) console.warn('you are probably running headed mode in CI, this will usually fail.');
|
|
85
|
+
const browserUIHeight = 100;
|
|
86
|
+
const args = buildChromeArgs({
|
|
87
|
+
userAgent: ua,
|
|
88
|
+
windowSize: headed ? {
|
|
89
|
+
width,
|
|
90
|
+
height: height + browserUIHeight
|
|
91
|
+
} : void 0,
|
|
92
|
+
chromeArgs: target.chromeArgs
|
|
93
|
+
});
|
|
94
|
+
launcherDebug('launching browser with viewport, headed', headed, 'viewport', viewportConfig, 'args', args, 'preference', preference);
|
|
95
|
+
let page;
|
|
96
|
+
let browserInstance = browser;
|
|
97
|
+
if (existingPage) {
|
|
98
|
+
page = existingPage;
|
|
99
|
+
launcherDebug('reusing existing page for shared browser context');
|
|
100
|
+
if (!browserInstance) browserInstance = page.browser();
|
|
101
|
+
} else {
|
|
102
|
+
if (!browserInstance) {
|
|
103
|
+
browserInstance = await puppeteer.launch({
|
|
104
|
+
headless: !preference?.headed,
|
|
105
|
+
defaultViewport: defaultViewportConfig,
|
|
106
|
+
args,
|
|
107
|
+
acceptInsecureCerts: target.acceptInsecureCerts,
|
|
108
|
+
ignoreDefaultArgs: preference?.ignoreDefaultArgs
|
|
109
|
+
});
|
|
110
|
+
freeFn.push({
|
|
111
|
+
name: 'puppeteer_browser',
|
|
112
|
+
fn: ()=>{
|
|
113
|
+
if (!preference?.keepWindow) if ('win32' === process.platform) setTimeout(()=>{
|
|
114
|
+
browserInstance?.close();
|
|
115
|
+
}, 800);
|
|
116
|
+
else browserInstance?.close();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
page = await browserInstance.newPage();
|
|
121
|
+
}
|
|
122
|
+
if (target.cookie) {
|
|
123
|
+
const cookieFileContent = readFileSync(target.cookie, 'utf-8');
|
|
124
|
+
await browserInstance.setCookie(...JSON.parse(cookieFileContent));
|
|
125
|
+
}
|
|
126
|
+
if (ua) await page.setUserAgent(ua);
|
|
127
|
+
if (viewportConfig) await page.setViewport(viewportConfig);
|
|
128
|
+
const waitForNetworkIdleTimeout = 'number' == typeof target.waitForNetworkIdle?.timeout ? target.waitForNetworkIdle.timeout : defaultWaitForNetworkIdleTimeout;
|
|
129
|
+
try {
|
|
130
|
+
launcherDebug('goto', target.url);
|
|
131
|
+
await page.goto(target.url);
|
|
132
|
+
if (waitForNetworkIdleTimeout > 0) {
|
|
133
|
+
launcherDebug('waitForNetworkIdle', waitForNetworkIdleTimeout);
|
|
134
|
+
await page.waitForNetworkIdle({
|
|
135
|
+
timeout: waitForNetworkIdleTimeout
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
} catch (e) {
|
|
139
|
+
if ('boolean' == typeof target.waitForNetworkIdle?.continueOnNetworkIdleError && !target.waitForNetworkIdle?.continueOnNetworkIdleError) {
|
|
140
|
+
const newError = new Error(`failed to wait for network idle: ${e}`, {
|
|
141
|
+
cause: e
|
|
142
|
+
});
|
|
143
|
+
throw newError;
|
|
144
|
+
}
|
|
145
|
+
const newMessage = `failed to wait for network idle after ${waitForNetworkIdleTimeout}ms, but the script will continue.`;
|
|
146
|
+
console.warn(newMessage);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
page,
|
|
150
|
+
freeFn
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async function puppeteerAgentForTarget(target, preference, browser, existingPage) {
|
|
154
|
+
const { page, freeFn } = await launchPuppeteerPage(target, preference, browser, existingPage);
|
|
155
|
+
const aiActContext = resolveAiActionContext(target, preference);
|
|
156
|
+
const { aiActionContext, ...preferenceToUse } = preference ?? {};
|
|
157
|
+
const agent = new PuppeteerAgent(page, {
|
|
158
|
+
...preferenceToUse,
|
|
159
|
+
aiActContext,
|
|
160
|
+
waitForNetworkIdleTimeout: 'number' == typeof target.waitForNetworkIdle?.timeout ? target.waitForNetworkIdle.timeout : void 0,
|
|
161
|
+
forceSameTabNavigation: void 0 !== target.forceSameTabNavigation ? target.forceSameTabNavigation : true
|
|
162
|
+
});
|
|
163
|
+
freeFn.push({
|
|
164
|
+
name: 'midscene_puppeteer_agent',
|
|
165
|
+
fn: ()=>agent.destroy()
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
agent,
|
|
169
|
+
freeFn
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
export { buildChromeArgs, defaultUA, defaultViewportHeight, defaultViewportScale, defaultViewportWidth, defaultWaitForNetworkIdleTimeout, launchPuppeteerPage, puppeteerAgentForTarget, resolveAiActionContext };
|