@midscene/web 1.6.3-beta-20260403070857.0 → 1.6.4

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.
Files changed (32) hide show
  1. package/dist/es/bridge-mode/io-client.mjs +1 -1
  2. package/dist/es/bridge-mode/io-server.mjs +2 -2
  3. package/dist/es/bridge-mode/io-server.mjs.map +1 -1
  4. package/dist/es/bridge-mode/page-browser-side.mjs +1 -1
  5. package/dist/es/bridge-mode/page-browser-side.mjs.map +1 -1
  6. package/dist/es/cli.mjs +3 -1
  7. package/dist/es/cli.mjs.map +1 -1
  8. package/dist/es/mcp-server.mjs +1 -1
  9. package/dist/es/playwright/ai-fixture.mjs +54 -50
  10. package/dist/es/playwright/ai-fixture.mjs.map +1 -1
  11. package/dist/es/playwright/reporter/index.mjs +106 -143
  12. package/dist/es/playwright/reporter/index.mjs.map +1 -1
  13. package/dist/es/puppeteer/agent-launcher.mjs +0 -1
  14. package/dist/es/puppeteer/agent-launcher.mjs.map +1 -1
  15. package/dist/lib/bridge-mode/io-client.js +1 -1
  16. package/dist/lib/bridge-mode/io-server.js +2 -2
  17. package/dist/lib/bridge-mode/io-server.js.map +1 -1
  18. package/dist/lib/bridge-mode/page-browser-side.js +1 -1
  19. package/dist/lib/bridge-mode/page-browser-side.js.map +1 -1
  20. package/dist/lib/cli.js +3 -1
  21. package/dist/lib/cli.js.map +1 -1
  22. package/dist/lib/mcp-server.js +1 -1
  23. package/dist/lib/playwright/ai-fixture.js +52 -48
  24. package/dist/lib/playwright/ai-fixture.js.map +1 -1
  25. package/dist/lib/playwright/reporter/index.js +167 -204
  26. package/dist/lib/playwright/reporter/index.js.map +1 -1
  27. package/dist/lib/puppeteer/agent-launcher.js +0 -1
  28. package/dist/lib/puppeteer/agent-launcher.js.map +1 -1
  29. package/dist/types/playwright/ai-fixture.d.ts +3 -0
  30. package/dist/types/playwright/reporter/index.d.ts +7 -21
  31. package/dist/types/puppeteer/agent-launcher.d.ts +1 -1
  32. package/package.json +4 -4
@@ -1,19 +1,5 @@
1
1
  "use strict";
2
- var __webpack_modules__ = {
3
- "node:fs" (module) {
4
- module.exports = require("node:fs");
5
- }
6
- };
7
- var __webpack_module_cache__ = {};
8
- function __webpack_require__(moduleId) {
9
- var cachedModule = __webpack_module_cache__[moduleId];
10
- if (void 0 !== cachedModule) return cachedModule.exports;
11
- var module = __webpack_module_cache__[moduleId] = {
12
- exports: {}
13
- };
14
- __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
15
- return module.exports;
16
- }
2
+ var __webpack_require__ = {};
17
3
  (()=>{
18
4
  __webpack_require__.d = (exports1, definition)=>{
19
5
  for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
@@ -36,210 +22,187 @@ function __webpack_require__(moduleId) {
36
22
  };
37
23
  })();
38
24
  var __webpack_exports__ = {};
39
- (()=>{
40
- __webpack_require__.r(__webpack_exports__);
41
- __webpack_require__.d(__webpack_exports__, {
42
- default: ()=>reporter
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ default: ()=>reporter
28
+ });
29
+ const external_node_fs_namespaceObject = require("node:fs");
30
+ const external_node_path_namespaceObject = require("node:path");
31
+ const agent_namespaceObject = require("@midscene/core/agent");
32
+ const report_namespaceObject = require("@midscene/core/report");
33
+ const common_namespaceObject = require("@midscene/shared/common");
34
+ const utils_namespaceObject = require("@midscene/shared/utils");
35
+ function _define_property(obj, key, value) {
36
+ if (key in obj) Object.defineProperty(obj, key, {
37
+ value: value,
38
+ enumerable: true,
39
+ configurable: true,
40
+ writable: true
43
41
  });
44
- var external_node_fs_ = __webpack_require__("node:fs");
45
- const external_node_path_namespaceObject = require("node:path");
46
- const core_namespaceObject = require("@midscene/core");
47
- const agent_namespaceObject = require("@midscene/core/agent");
48
- const utils_namespaceObject = require("@midscene/core/utils");
49
- const common_namespaceObject = require("@midscene/shared/common");
50
- const shared_utils_namespaceObject = require("@midscene/shared/utils");
51
- function _define_property(obj, key, value) {
52
- if (key in obj) Object.defineProperty(obj, key, {
53
- value: value,
54
- enumerable: true,
55
- configurable: true,
56
- writable: true
57
- });
58
- else obj[key] = value;
59
- return obj;
42
+ else obj[key] = value;
43
+ return obj;
44
+ }
45
+ class MidsceneReporter {
46
+ static getMode(reporterType) {
47
+ if (!reporterType) return 'merged';
48
+ if ('merged' !== reporterType && 'separate' !== reporterType) throw new Error(`Unknown reporter type in playwright config: ${reporterType}, only support 'merged' or 'separate'`);
49
+ return reporterType;
60
50
  }
61
- class MidsceneReporter {
62
- static getMode(reporterType) {
63
- if (!reporterType) return 'merged';
64
- if ('merged' !== reporterType && 'separate' !== reporterType) throw new Error(`Unknown reporter type in playwright config: ${reporterType}, only support 'merged' or 'separate'`);
65
- return reporterType;
66
- }
67
- getSeparatedFilename(testTitle) {
68
- if (!this.testTitleToFilename.has(testTitle)) {
69
- const baseTag = `playwright-${(0, shared_utils_namespaceObject.replaceIllegalPathCharsAndSpace)(testTitle)}`;
70
- const generatedFilename = (0, agent_namespaceObject.getReportFileName)(baseTag);
71
- this.testTitleToFilename.set(testTitle, generatedFilename);
72
- }
73
- return this.testTitleToFilename.get(testTitle);
51
+ getSeparatedFilename(testTitle) {
52
+ if (!this.testTitleToFilename.has(testTitle)) {
53
+ const baseTag = `playwright-${(0, utils_namespaceObject.replaceIllegalPathCharsAndSpace)(testTitle)}`;
54
+ const generatedFilename = (0, agent_namespaceObject.getReportFileName)(baseTag);
55
+ this.testTitleToFilename.set(testTitle, generatedFilename);
74
56
  }
75
- getReportFilename(testTitle) {
76
- if ('merged' === this.mode) {
77
- if (!this.mergedFilename) this.mergedFilename = (0, agent_namespaceObject.getReportFileName)('playwright-merged');
78
- return this.mergedFilename;
79
- }
80
- if ('separate' === this.mode) {
81
- if (!testTitle) throw new Error('testTitle is required in separate mode');
82
- return this.getSeparatedFilename(testTitle);
83
- }
84
- throw new Error(`Unknown mode: ${this.mode}`);
57
+ return this.testTitleToFilename.get(testTitle);
58
+ }
59
+ getReportFilename(testTitle) {
60
+ if ('merged' === this.mode) {
61
+ if (!this.mergedFilename) this.mergedFilename = (0, agent_namespaceObject.getReportFileName)('playwright-merged');
62
+ return this.mergedFilename;
85
63
  }
86
- getReportPath(testTitle) {
87
- const fileName = this.getReportFilename(testTitle);
88
- if ('html-and-external-assets' === this.outputFormat) return (0, external_node_path_namespaceObject.join)((0, common_namespaceObject.getMidsceneRunSubDir)('report'), fileName, 'index.html');
89
- return (0, external_node_path_namespaceObject.join)((0, common_namespaceObject.getMidsceneRunSubDir)('report'), `${fileName}.html`);
64
+ if ('separate' === this.mode) {
65
+ if (!testTitle) throw new Error('testTitle is required in separate mode');
66
+ return this.getSeparatedFilename(testTitle);
90
67
  }
91
- copyScreenshotsToReport(tempFilePath, reportPath) {
92
- const screenshotsDir = (0, external_node_path_namespaceObject.join)((0, external_node_path_namespaceObject.dirname)(reportPath), 'screenshots');
93
- const tempScreenshotsDir = `${tempFilePath}.screenshots`;
94
- if (!(0, external_node_fs_.existsSync)(tempScreenshotsDir)) return;
95
- if (!(0, external_node_fs_.existsSync)(screenshotsDir)) (0, external_node_fs_.mkdirSync)(screenshotsDir, {
68
+ throw new Error(`Unknown mode: ${this.mode}`);
69
+ }
70
+ getReportPath(testTitle) {
71
+ const fileName = this.getReportFilename(testTitle);
72
+ if ('html-and-external-assets' === this.outputFormat) return (0, external_node_path_namespaceObject.join)((0, common_namespaceObject.getMidsceneRunSubDir)('report'), fileName, 'index.html');
73
+ return (0, external_node_path_namespaceObject.join)((0, common_namespaceObject.getMidsceneRunSubDir)('report'), `${fileName}.html`);
74
+ }
75
+ ensureOutputRoot() {
76
+ (0, external_node_fs_namespaceObject.mkdirSync)((0, common_namespaceObject.getMidsceneRunSubDir)('report'), {
77
+ recursive: true
78
+ });
79
+ }
80
+ copyReport(reportFilePath, targetPath) {
81
+ if ((0, report_namespaceObject.isDirectoryModeReport)(reportFilePath)) {
82
+ const targetDir = (0, external_node_path_namespaceObject.dirname)(targetPath);
83
+ (0, external_node_fs_namespaceObject.mkdirSync)(targetDir, {
96
84
  recursive: true
97
85
  });
98
- const screenshotMapPath = `${tempFilePath}.screenshots.json`;
99
- if (!(0, external_node_fs_.existsSync)(screenshotMapPath)) return;
100
- try {
101
- const { readFileSync } = __webpack_require__("node:fs");
102
- const screenshotMap = JSON.parse(readFileSync(screenshotMapPath, 'utf-8'));
103
- for (const [id, srcPath] of Object.entries(screenshotMap)){
104
- if ('merged' === this.mode && this.writtenScreenshots.has(id)) continue;
105
- const destPath = (0, external_node_path_namespaceObject.join)(screenshotsDir, `${id}.png`);
106
- if ((0, external_node_fs_.existsSync)(srcPath)) {
107
- (0, external_node_fs_.copyFileSync)(srcPath, destPath);
108
- if ('merged' === this.mode) this.writtenScreenshots.add(id);
109
- }
110
- }
111
- } catch (error) {
112
- console.error('Error copying screenshots:', error);
113
- }
114
- }
115
- async updateReport(testData) {
116
- if (!testData || !this.mode) return;
117
- this.writeQueue = this.writeQueue.then(async ()=>{
118
- const reportPath = this.getReportPath(testData.attributes?.playwright_test_title);
119
- if ('html-and-external-assets' === this.outputFormat) {
120
- const reportDir = (0, external_node_path_namespaceObject.dirname)(reportPath);
121
- if (!(0, external_node_fs_.existsSync)(reportDir)) (0, external_node_fs_.mkdirSync)(reportDir, {
122
- recursive: true
123
- });
124
- }
125
- const tpl = (0, utils_namespaceObject.getReportTpl)();
126
- if (!tpl) throw new Error('Report template not found. Ensure @midscene/core is built correctly.');
127
- let dumpScript = `<script type="midscene_web_dump">\n${(0, shared_utils_namespaceObject.escapeScriptTag)(testData.dumpString)}\n</script>`;
128
- if (testData.attributes) {
129
- const attributesArr = Object.keys(testData.attributes).map((key)=>`${key}="${encodeURIComponent(testData.attributes[key])}"`);
130
- dumpScript = dumpScript.replace('<script type="midscene_web_dump"', `<script type="midscene_web_dump" ${attributesArr.join(' ')}`);
131
- }
132
- if ('merged' === this.mode) if (this.mergedReportInitialized) (0, external_node_fs_.writeFileSync)(reportPath, dumpScript, {
133
- flag: 'a'
134
- });
135
- else {
136
- (0, external_node_fs_.writeFileSync)(reportPath, (0, utils_namespaceObject.insertContentBeforeClosingHtml)(tpl, dumpScript), {
137
- flag: 'w'
138
- });
139
- this.mergedReportInitialized = true;
140
- }
141
- else (0, external_node_fs_.writeFileSync)(reportPath, (0, utils_namespaceObject.insertContentBeforeClosingHtml)(tpl, dumpScript), {
142
- flag: 'w'
143
- });
144
- (0, agent_namespaceObject.printReportMsg)(reportPath);
86
+ (0, external_node_fs_namespaceObject.cpSync)((0, external_node_path_namespaceObject.dirname)(reportFilePath), targetDir, {
87
+ recursive: true,
88
+ force: true
145
89
  });
146
- await this.writeQueue;
90
+ return;
147
91
  }
148
- async onBegin(config, suite) {
149
- this.hasMultipleProjects = (config.projects?.length || 0) > 1;
92
+ (0, external_node_fs_namespaceObject.mkdirSync)((0, external_node_path_namespaceObject.dirname)(targetPath), {
93
+ recursive: true
94
+ });
95
+ (0, external_node_fs_namespaceObject.copyFileSync)(reportFilePath, targetPath);
96
+ }
97
+ collectReportInfo(test, result) {
98
+ const reportAnnotations = test.annotations.filter((annotation)=>'MIDSCENE_DUMP_ANNOTATION' === annotation.type && annotation.description);
99
+ if (0 === reportAnnotations.length || !this.mode) return;
100
+ const retry = result.retry ? `(retry #${result.retry})` : '';
101
+ const testId = `${test.id}${retry}`;
102
+ const projectName = this.hasMultipleProjects ? test.parent?.project()?.name : void 0;
103
+ const projectSuffix = projectName ? ` [${projectName}]` : '';
104
+ const testTitle = `${test.title}${projectSuffix}${retry}`;
105
+ const reports = reportAnnotations.map((annotation)=>annotation.description).filter((reportFilePath)=>{
106
+ if ((0, external_node_fs_namespaceObject.existsSync)(reportFilePath)) return true;
107
+ (0, utils_namespaceObject.logMsg)(`Failed to read Midscene report file: ${reportFilePath}`, new Error('Report file does not exist'));
108
+ return false;
109
+ }).map((reportFilePath)=>({
110
+ reportFilePath,
111
+ reportAttributes: {
112
+ testDuration: result.duration,
113
+ testStatus: result.status,
114
+ testTitle,
115
+ testId,
116
+ testDescription: test.parent?.title || ''
117
+ }
118
+ }));
119
+ if (0 === reports.length) return;
120
+ this.reportsByTestId.set(testId, {
121
+ testTitle,
122
+ reports
123
+ });
124
+ }
125
+ finalizeMergedReport() {
126
+ this.ensureOutputRoot();
127
+ const tool = new report_namespaceObject.ReportMergingTool();
128
+ let reportCount = 0;
129
+ for (const entry of this.reportsByTestId.values())for (const report of entry.reports){
130
+ tool.append(report);
131
+ reportCount += 1;
150
132
  }
151
- onTestBegin(_test, _result) {}
152
- onTestEnd(test, result) {
153
- const dumpAnnotation = test.annotations.find((annotation)=>'MIDSCENE_DUMP_ANNOTATION' === annotation.type);
154
- if (!dumpAnnotation?.description) return;
155
- const tempFilePath = dumpAnnotation.description;
156
- for (const filePath of core_namespaceObject.ReportActionDump.getFilePaths(tempFilePath))this.tempFiles.add(filePath);
157
- let dumpString;
158
- try {
159
- if ('html-and-external-assets' === this.outputFormat) {
160
- const { readFileSync } = __webpack_require__("node:fs");
161
- dumpString = readFileSync(tempFilePath, 'utf-8');
162
- const retry = result.retry ? `(retry #${result.retry})` : '';
163
- const projectName = this.hasMultipleProjects ? test.parent?.project()?.name : void 0;
164
- const projectSuffix = projectName ? ` [${projectName}]` : '';
165
- const testTitle = `${test.title}${projectSuffix}${retry}`;
166
- const reportPath = this.getReportPath(testTitle);
167
- this.copyScreenshotsToReport(tempFilePath, reportPath);
168
- } else dumpString = core_namespaceObject.ReportActionDump.fromFilesAsInlineJson(tempFilePath);
169
- } catch (error) {
170
- console.error(`Failed to read Midscene dump file: ${tempFilePath}`, error);
133
+ if (0 === reportCount) return;
134
+ const targetName = this.getReportFilename();
135
+ if (1 === reportCount) {
136
+ const firstReport = Array.from(this.reportsByTestId.values())[0]?.reports[0];
137
+ if (!firstReport) return;
138
+ if (firstReport.reportFilePath) {
139
+ const targetPath = this.getReportPath();
140
+ this.copyReport(firstReport.reportFilePath, targetPath);
141
+ (0, agent_namespaceObject.printReportMsg)(targetPath);
142
+ return;
171
143
  }
172
- if (dumpString) {
173
- const retry = result.retry ? `(retry #${result.retry})` : '';
174
- const testId = `${test.id}${retry}`;
175
- const projectName = this.hasMultipleProjects ? test.parent?.project()?.name : void 0;
176
- const projectSuffix = projectName ? ` [${projectName}]` : '';
177
- const testData = {
178
- dumpString,
179
- attributes: {
180
- 'data-group-id': testId,
181
- playwright_test_id: testId,
182
- playwright_test_title: `${test.title}${projectSuffix}${retry}`,
183
- playwright_test_status: result.status,
184
- playwright_test_duration: result.duration
185
- }
186
- };
187
- const reportPromise = this.updateReport(testData).catch((error)=>{
188
- console.error('Error updating report:', error);
189
- }).finally(()=>{
190
- this.pendingReports.delete(reportPromise);
191
- });
192
- this.pendingReports.add(reportPromise);
193
- }
194
- try {
195
- core_namespaceObject.ReportActionDump.cleanupFiles(tempFilePath);
196
- for (const filePath of core_namespaceObject.ReportActionDump.getFilePaths(tempFilePath))this.tempFiles.delete(filePath);
197
- } catch {}
144
+ const mergedReportPath = tool.mergeReports(targetName, {
145
+ overwrite: true
146
+ });
147
+ if (mergedReportPath) (0, agent_namespaceObject.printReportMsg)(mergedReportPath);
148
+ return;
198
149
  }
199
- async onEnd() {
200
- if (this.pendingReports.size > 0) {
201
- console.log(`Midscene: Waiting for ${this.pendingReports.size} pending report(s) to complete...`);
202
- await Promise.all(Array.from(this.pendingReports));
203
- }
204
- if ('html-and-external-assets' === this.outputFormat && 'merged' === this.mode) {
205
- const reportPath = this.getReportPath();
206
- const reportDir = (0, external_node_path_namespaceObject.dirname)(reportPath);
207
- console.log('[Midscene] Directory report generated.');
208
- console.log('[Midscene] Note: This report must be served via HTTP server due to CORS restrictions.');
209
- console.log(`[Midscene] Example: npx serve ${reportDir}`);
210
- } else if ('html-and-external-assets' === this.outputFormat && 'separate' === this.mode) {
211
- const reportBaseDir = (0, common_namespaceObject.getMidsceneRunSubDir)('report');
212
- console.log('[Midscene] Directory reports generated.');
213
- console.log('[Midscene] Note: Reports must be served via HTTP server due to CORS restrictions.');
214
- console.log(`[Midscene] Example: npx serve ${reportBaseDir}`);
215
- }
216
- if (this.tempFiles.size > 0) {
217
- console.log(`Midscene: Cleaning up ${this.tempFiles.size} remaining temp file(s)...`);
218
- for (const filePath of this.tempFiles)try {
219
- (0, external_node_fs_.rmSync)(filePath, {
220
- force: true
221
- });
222
- } catch (error) {}
223
- this.tempFiles.clear();
150
+ const mergedReportPath = tool.mergeReports(targetName, {
151
+ overwrite: true
152
+ });
153
+ if (mergedReportPath) (0, agent_namespaceObject.printReportMsg)(mergedReportPath);
154
+ }
155
+ finalizeSeparateReports() {
156
+ this.ensureOutputRoot();
157
+ for (const entry of this.reportsByTestId.values()){
158
+ const targetName = this.getReportFilename(entry.testTitle);
159
+ if (1 === entry.reports.length) {
160
+ const firstReport = entry.reports[0];
161
+ if (firstReport.reportFilePath) {
162
+ const targetPath = this.getReportPath(entry.testTitle);
163
+ this.copyReport(firstReport.reportFilePath, targetPath);
164
+ (0, agent_namespaceObject.printReportMsg)(targetPath);
165
+ continue;
166
+ }
167
+ const tool = new report_namespaceObject.ReportMergingTool();
168
+ tool.append(firstReport);
169
+ const reportPath = tool.mergeReports(targetName, {
170
+ overwrite: true
171
+ });
172
+ if (reportPath) (0, agent_namespaceObject.printReportMsg)(reportPath);
173
+ continue;
224
174
  }
225
- }
226
- constructor(options = {}){
227
- _define_property(this, "mergedFilename", void 0);
228
- _define_property(this, "testTitleToFilename", new Map());
229
- _define_property(this, "mode", void 0);
230
- _define_property(this, "outputFormat", void 0);
231
- _define_property(this, "tempFiles", new Set());
232
- _define_property(this, "pendingReports", new Set());
233
- _define_property(this, "mergedReportInitialized", false);
234
- _define_property(this, "writeQueue", Promise.resolve());
235
- _define_property(this, "hasMultipleProjects", false);
236
- _define_property(this, "writtenScreenshots", new Set());
237
- this.mode = MidsceneReporter.getMode(options.type ?? 'merged');
238
- this.outputFormat = options.outputFormat ?? 'single-html';
175
+ const tool = new report_namespaceObject.ReportMergingTool();
176
+ for (const report of entry.reports)tool.append(report);
177
+ const reportPath = tool.mergeReports(targetName, {
178
+ overwrite: true
179
+ });
180
+ if (reportPath) (0, agent_namespaceObject.printReportMsg)(reportPath);
239
181
  }
240
182
  }
241
- const reporter = MidsceneReporter;
242
- })();
183
+ async onBegin(config, _suite) {
184
+ this.hasMultipleProjects = (config.projects?.length || 0) > 1;
185
+ }
186
+ onTestBegin(_test, _result) {}
187
+ onTestEnd(test, result) {
188
+ this.collectReportInfo(test, result);
189
+ }
190
+ async onEnd() {
191
+ if ('merged' === this.mode) return void this.finalizeMergedReport();
192
+ if ('separate' === this.mode) this.finalizeSeparateReports();
193
+ }
194
+ constructor(options = {}){
195
+ _define_property(this, "mergedFilename", void 0);
196
+ _define_property(this, "testTitleToFilename", new Map());
197
+ _define_property(this, "reportsByTestId", new Map());
198
+ _define_property(this, "mode", void 0);
199
+ _define_property(this, "outputFormat", void 0);
200
+ _define_property(this, "hasMultipleProjects", false);
201
+ this.mode = MidsceneReporter.getMode(options.type ?? 'merged');
202
+ this.outputFormat = options.outputFormat ?? 'single-html';
203
+ }
204
+ }
205
+ const reporter = MidsceneReporter;
243
206
  exports["default"] = __webpack_exports__["default"];
244
207
  for(var __rspack_i in __webpack_exports__)if (-1 === [
245
208
  "default"
@@ -1 +1 @@
1
- {"version":3,"file":"playwright/reporter/index.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../../src/playwright/reporter/index.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import {\n copyFileSync,\n existsSync,\n mkdirSync,\n rmSync,\n writeFileSync,\n} from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport {\n ReportActionDump,\n type ReportDumpWithAttributes,\n} from '@midscene/core';\nimport { getReportFileName, printReportMsg } from '@midscene/core/agent';\nimport {\n getReportTpl,\n insertContentBeforeClosingHtml,\n} from '@midscene/core/utils';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport {\n escapeScriptTag,\n replaceIllegalPathCharsAndSpace,\n} from '@midscene/shared/utils';\nimport type {\n FullConfig,\n Reporter,\n Suite,\n TestCase,\n TestResult,\n} from '@playwright/test/reporter';\n\ninterface MidsceneReporterOptions {\n type?: 'merged' | 'separate';\n /**\n * Output format for the report.\n * - 'single-html': All screenshots embedded as base64 in a single HTML file (default)\n * - 'html-and-external-assets': Screenshots saved as separate PNG files in a screenshots/ subdirectory\n *\n * Note: 'html-and-external-assets' reports must be served via HTTP server due to CORS restrictions.\n */\n outputFormat?: 'single-html' | 'html-and-external-assets';\n}\n\nclass MidsceneReporter implements Reporter {\n private mergedFilename?: string;\n private testTitleToFilename = new Map<string, string>();\n mode?: 'merged' | 'separate';\n outputFormat: 'single-html' | 'html-and-external-assets';\n\n // Track all temp files created during this test run for cleanup\n private tempFiles = new Set<string>();\n\n // Track pending report updates\n private pendingReports = new Set<Promise<void>>();\n\n // Track whether the merged report file has been initialized\n private mergedReportInitialized = false;\n\n // Write queue to serialize file writes and prevent concurrent write conflicts\n private writeQueue: Promise<void> = Promise.resolve();\n\n // Track whether we have multiple projects (browsers)\n private hasMultipleProjects = false;\n\n // Track written screenshots to avoid duplicates (for directory mode)\n private writtenScreenshots = new Set<string>();\n\n constructor(options: MidsceneReporterOptions = {}) {\n // Set mode from constructor options (official Playwright way)\n this.mode = MidsceneReporter.getMode(options.type ?? 'merged');\n this.outputFormat = options.outputFormat ?? 'single-html';\n }\n\n private static getMode(reporterType: string): 'merged' | 'separate' {\n if (!reporterType) {\n return 'merged';\n }\n if (reporterType !== 'merged' && reporterType !== 'separate') {\n throw new Error(\n `Unknown reporter type in playwright config: ${reporterType}, only support 'merged' or 'separate'`,\n );\n }\n return reporterType;\n }\n\n private getSeparatedFilename(testTitle: string): string {\n if (!this.testTitleToFilename.has(testTitle)) {\n const baseTag = `playwright-${replaceIllegalPathCharsAndSpace(testTitle)}`;\n const generatedFilename = getReportFileName(baseTag);\n this.testTitleToFilename.set(testTitle, generatedFilename);\n }\n return this.testTitleToFilename.get(testTitle)!;\n }\n\n private getReportFilename(testTitle?: string): string {\n if (this.mode === 'merged') {\n if (!this.mergedFilename) {\n this.mergedFilename = getReportFileName('playwright-merged');\n }\n return this.mergedFilename;\n } else if (this.mode === 'separate') {\n if (!testTitle) throw new Error('testTitle is required in separate mode');\n return this.getSeparatedFilename(testTitle);\n }\n throw new Error(`Unknown mode: ${this.mode}`);\n }\n\n /**\n * Get the report path - for directory mode, returns a directory path with index.html\n */\n private getReportPath(testTitle?: string): string {\n const fileName = this.getReportFilename(testTitle);\n if (this.outputFormat === 'html-and-external-assets') {\n // Directory mode: report-name/index.html\n return join(getMidsceneRunSubDir('report'), fileName, 'index.html');\n }\n // Inline mode: report-name.html\n return join(getMidsceneRunSubDir('report'), `${fileName}.html`);\n }\n\n /**\n * Copy screenshots from temp location to report screenshots directory\n */\n private copyScreenshotsToReport(\n tempFilePath: string,\n reportPath: string,\n ): void {\n const screenshotsDir = join(dirname(reportPath), 'screenshots');\n const tempScreenshotsDir = `${tempFilePath}.screenshots`;\n\n if (!existsSync(tempScreenshotsDir)) {\n return;\n }\n\n // Ensure screenshots directory exists\n if (!existsSync(screenshotsDir)) {\n mkdirSync(screenshotsDir, { recursive: true });\n }\n\n // Read screenshot map to get all screenshot IDs\n const screenshotMapPath = `${tempFilePath}.screenshots.json`;\n if (!existsSync(screenshotMapPath)) {\n return;\n }\n\n try {\n const { readFileSync } = require('node:fs');\n const screenshotMap: Record<string, string> = JSON.parse(\n readFileSync(screenshotMapPath, 'utf-8'),\n );\n\n for (const [id, srcPath] of Object.entries(screenshotMap)) {\n // In merged mode, skip if already written to avoid duplicates\n // In separate mode, each test has its own screenshots directory\n if (this.mode === 'merged' && this.writtenScreenshots.has(id)) {\n continue;\n }\n\n const destPath = join(screenshotsDir, `${id}.png`);\n\n if (existsSync(srcPath)) {\n copyFileSync(srcPath, destPath);\n if (this.mode === 'merged') {\n this.writtenScreenshots.add(id);\n }\n }\n }\n } catch (error) {\n console.error('Error copying screenshots:', error);\n }\n }\n\n private async updateReport(testData: ReportDumpWithAttributes) {\n if (!testData || !this.mode) return;\n\n // Queue the write operation to prevent concurrent writes to the same file\n this.writeQueue = this.writeQueue.then(async () => {\n const reportPath = this.getReportPath(\n testData.attributes?.playwright_test_title,\n );\n\n // Ensure report directory exists for directory mode\n if (this.outputFormat === 'html-and-external-assets') {\n const reportDir = dirname(reportPath);\n if (!existsSync(reportDir)) {\n mkdirSync(reportDir, { recursive: true });\n }\n }\n\n // Get report template\n const tpl = getReportTpl();\n if (!tpl) {\n throw new Error(\n 'Report template not found. Ensure @midscene/core is built correctly.',\n );\n }\n\n // Parse the dump string and generate dump script tag\n let dumpScript = `<script type=\"midscene_web_dump\">\\n${escapeScriptTag(testData.dumpString)}\\n</script>`;\n\n if (testData.attributes) {\n const attributesArr = Object.keys(testData.attributes).map((key) => {\n return `${key}=\"${encodeURIComponent(testData.attributes![key])}\"`;\n });\n // Add attributes to the script tag\n dumpScript = dumpScript.replace(\n '<script type=\"midscene_web_dump\"',\n `<script type=\"midscene_web_dump\" ${attributesArr.join(' ')}`,\n );\n }\n\n // Write or append to file\n if (this.mode === 'merged') {\n // For merged report, write template + dump on first write, then only append dumps\n if (!this.mergedReportInitialized) {\n writeFileSync(\n reportPath,\n insertContentBeforeClosingHtml(tpl, dumpScript),\n { flag: 'w' },\n );\n this.mergedReportInitialized = true;\n } else {\n // Append only the dump scripts for subsequent tests\n writeFileSync(reportPath, dumpScript, { flag: 'a' });\n }\n } else {\n // For separate reports, write each test to its own file with template\n writeFileSync(\n reportPath,\n insertContentBeforeClosingHtml(tpl, dumpScript),\n { flag: 'w' },\n );\n }\n\n printReportMsg(reportPath);\n });\n\n await this.writeQueue;\n }\n\n async onBegin(config: FullConfig, suite: Suite) {\n // Check if we have multiple projects to determine if we need browser labels\n this.hasMultipleProjects = (config.projects?.length || 0) > 1;\n }\n\n onTestBegin(_test: TestCase, _result: TestResult) {\n // logger(`Starting test ${test.title}`);\n }\n\n onTestEnd(test: TestCase, result: TestResult) {\n const dumpAnnotation = test.annotations.find((annotation) => {\n return annotation.type === 'MIDSCENE_DUMP_ANNOTATION';\n });\n if (!dumpAnnotation?.description) return;\n\n const tempFilePath = dumpAnnotation.description;\n\n // Track temp files for potential cleanup in onEnd\n for (const filePath of ReportActionDump.getFilePaths(tempFilePath)) {\n this.tempFiles.add(filePath);\n }\n\n let dumpString: string | undefined;\n\n try {\n if (this.outputFormat === 'html-and-external-assets') {\n // Directory mode: keep { $screenshot: id } format, copy screenshots to report dir\n const { readFileSync } = require('node:fs');\n dumpString = readFileSync(tempFilePath, 'utf-8');\n\n // Get report path and copy screenshots\n const retry = result.retry ? `(retry #${result.retry})` : '';\n const projectName = this.hasMultipleProjects\n ? test.parent?.project()?.name\n : undefined;\n const projectSuffix = projectName ? ` [${projectName}]` : '';\n const testTitle = `${test.title}${projectSuffix}${retry}`;\n const reportPath = this.getReportPath(testTitle);\n\n this.copyScreenshotsToReport(tempFilePath, reportPath);\n } else {\n // Inline mode: convert screenshots to base64\n dumpString = ReportActionDump.fromFilesAsInlineJson(tempFilePath);\n }\n } catch (error) {\n console.error(\n `Failed to read Midscene dump file: ${tempFilePath}`,\n error,\n );\n // Don't return here - we still need to clean up the temp file\n }\n\n // Only update report if we successfully read the dump\n if (dumpString) {\n const retry = result.retry ? `(retry #${result.retry})` : '';\n const testId = `${test.id}${retry}`;\n\n // Get the project name (browser name) only if we have multiple projects\n const projectName = this.hasMultipleProjects\n ? test.parent?.project()?.name\n : undefined;\n const projectSuffix = projectName ? ` [${projectName}]` : '';\n\n const testData: ReportDumpWithAttributes = {\n dumpString,\n attributes: {\n 'data-group-id': testId,\n playwright_test_id: testId,\n playwright_test_title: `${test.title}${projectSuffix}${retry}`,\n playwright_test_status: result.status,\n playwright_test_duration: result.duration,\n },\n };\n\n // Start async report update and track it\n const reportPromise = this.updateReport(testData)\n .catch((error) => {\n console.error('Error updating report:', error);\n })\n .finally(() => {\n this.pendingReports.delete(reportPromise);\n });\n this.pendingReports.add(reportPromise);\n }\n\n // Always try to clean up temp files\n try {\n ReportActionDump.cleanupFiles(tempFilePath);\n for (const filePath of ReportActionDump.getFilePaths(tempFilePath)) {\n this.tempFiles.delete(filePath);\n }\n } catch {\n // Keep in tempFiles for cleanup in onEnd\n }\n }\n\n async onEnd() {\n // Wait for all pending report updates to complete\n if (this.pendingReports.size > 0) {\n console.log(\n `Midscene: Waiting for ${this.pendingReports.size} pending report(s) to complete...`,\n );\n await Promise.all(Array.from(this.pendingReports));\n }\n\n // Print directory mode notice (only for merged mode)\n if (\n this.outputFormat === 'html-and-external-assets' &&\n this.mode === 'merged'\n ) {\n const reportPath = this.getReportPath();\n const reportDir = dirname(reportPath);\n console.log('[Midscene] Directory report generated.');\n console.log(\n '[Midscene] Note: This report must be served via HTTP server due to CORS restrictions.',\n );\n console.log(`[Midscene] Example: npx serve ${reportDir}`);\n } else if (\n this.outputFormat === 'html-and-external-assets' &&\n this.mode === 'separate'\n ) {\n const reportBaseDir = getMidsceneRunSubDir('report');\n console.log('[Midscene] Directory reports generated.');\n console.log(\n '[Midscene] Note: Reports must be served via HTTP server due to CORS restrictions.',\n );\n console.log(`[Midscene] Example: npx serve ${reportBaseDir}`);\n }\n\n // Clean up any remaining temp files that weren't deleted in onTestEnd\n if (this.tempFiles.size > 0) {\n console.log(\n `Midscene: Cleaning up ${this.tempFiles.size} remaining temp file(s)...`,\n );\n\n for (const filePath of this.tempFiles) {\n try {\n rmSync(filePath, { force: true });\n } catch (error) {\n // Silently ignore - file may have been deleted already\n }\n }\n\n this.tempFiles.clear();\n }\n }\n}\n\nexport default MidsceneReporter;\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","MidsceneReporter","reporterType","Error","testTitle","baseTag","replaceIllegalPathCharsAndSpace","generatedFilename","getReportFileName","fileName","join","getMidsceneRunSubDir","tempFilePath","reportPath","screenshotsDir","dirname","tempScreenshotsDir","existsSync","mkdirSync","screenshotMapPath","readFileSync","require","screenshotMap","JSON","id","srcPath","destPath","copyFileSync","error","console","testData","reportDir","tpl","getReportTpl","dumpScript","escapeScriptTag","attributesArr","encodeURIComponent","writeFileSync","insertContentBeforeClosingHtml","printReportMsg","config","suite","_test","_result","test","result","dumpAnnotation","annotation","filePath","ReportActionDump","dumpString","retry","projectName","undefined","projectSuffix","testId","reportPromise","Promise","Array","reportBaseDir","rmSync","options","Map","Set"],"mappings":"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"}
1
+ {"version":3,"file":"playwright/reporter/index.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../../src/playwright/reporter/index.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { copyFileSync, cpSync, existsSync, mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { ReportFileWithAttributes, TestStatus } from '@midscene/core';\nimport { getReportFileName, printReportMsg } from '@midscene/core/agent';\nimport {\n ReportMergingTool,\n isDirectoryModeReport,\n} from '@midscene/core/report';\nimport { getMidsceneRunSubDir } from '@midscene/shared/common';\nimport {\n logMsg,\n replaceIllegalPathCharsAndSpace,\n} from '@midscene/shared/utils';\nimport type {\n FullConfig,\n Reporter,\n Suite,\n TestCase,\n TestResult,\n} from '@playwright/test/reporter';\n\ninterface MidsceneReporterOptions {\n type?: 'merged' | 'separate';\n outputFormat?: 'single-html' | 'html-and-external-assets';\n}\n\nclass MidsceneReporter implements Reporter {\n private mergedFilename?: string;\n private testTitleToFilename = new Map<string, string>();\n private reportsByTestId = new Map<\n string,\n {\n testTitle: string;\n reports: ReportFileWithAttributes[];\n }\n >();\n mode?: 'merged' | 'separate';\n outputFormat: 'single-html' | 'html-and-external-assets';\n private hasMultipleProjects = false;\n\n constructor(options: MidsceneReporterOptions = {}) {\n this.mode = MidsceneReporter.getMode(options.type ?? 'merged');\n this.outputFormat = options.outputFormat ?? 'single-html';\n }\n\n private static getMode(reporterType: string): 'merged' | 'separate' {\n if (!reporterType) {\n return 'merged';\n }\n if (reporterType !== 'merged' && reporterType !== 'separate') {\n throw new Error(\n `Unknown reporter type in playwright config: ${reporterType}, only support 'merged' or 'separate'`,\n );\n }\n return reporterType;\n }\n\n private getSeparatedFilename(testTitle: string): string {\n if (!this.testTitleToFilename.has(testTitle)) {\n const baseTag = `playwright-${replaceIllegalPathCharsAndSpace(testTitle)}`;\n const generatedFilename = getReportFileName(baseTag);\n this.testTitleToFilename.set(testTitle, generatedFilename);\n }\n return this.testTitleToFilename.get(testTitle)!;\n }\n\n private getReportFilename(testTitle?: string): string {\n if (this.mode === 'merged') {\n if (!this.mergedFilename) {\n this.mergedFilename = getReportFileName('playwright-merged');\n }\n return this.mergedFilename;\n }\n if (this.mode === 'separate') {\n if (!testTitle) throw new Error('testTitle is required in separate mode');\n return this.getSeparatedFilename(testTitle);\n }\n throw new Error(`Unknown mode: ${this.mode}`);\n }\n\n private getReportPath(testTitle?: string): string {\n const fileName = this.getReportFilename(testTitle);\n if (this.outputFormat === 'html-and-external-assets') {\n return join(getMidsceneRunSubDir('report'), fileName, 'index.html');\n }\n return join(getMidsceneRunSubDir('report'), `${fileName}.html`);\n }\n\n private ensureOutputRoot(): void {\n mkdirSync(getMidsceneRunSubDir('report'), { recursive: true });\n }\n\n private copyReport(reportFilePath: string, targetPath: string): void {\n if (isDirectoryModeReport(reportFilePath)) {\n const targetDir = dirname(targetPath);\n mkdirSync(targetDir, { recursive: true });\n cpSync(dirname(reportFilePath), targetDir, {\n recursive: true,\n force: true,\n });\n return;\n }\n\n mkdirSync(dirname(targetPath), { recursive: true });\n copyFileSync(reportFilePath, targetPath);\n }\n\n private collectReportInfo(test: TestCase, result: TestResult) {\n const reportAnnotations = test.annotations.filter((annotation) => {\n return (\n annotation.type === 'MIDSCENE_DUMP_ANNOTATION' && annotation.description\n );\n });\n if (reportAnnotations.length === 0 || !this.mode) {\n return;\n }\n\n const retry = result.retry ? `(retry #${result.retry})` : '';\n const testId = `${test.id}${retry}`;\n const projectName = this.hasMultipleProjects\n ? test.parent?.project()?.name\n : undefined;\n const projectSuffix = projectName ? ` [${projectName}]` : '';\n const testTitle = `${test.title}${projectSuffix}${retry}`;\n const reports = reportAnnotations\n .map((annotation) => annotation.description!)\n .filter((reportFilePath) => {\n if (existsSync(reportFilePath)) {\n return true;\n }\n logMsg(\n `Failed to read Midscene report file: ${reportFilePath}`,\n new Error('Report file does not exist'),\n );\n return false;\n })\n .map((reportFilePath): ReportFileWithAttributes => {\n return {\n reportFilePath,\n reportAttributes: {\n testDuration: result.duration,\n testStatus: result.status as TestStatus,\n testTitle,\n testId,\n testDescription: test.parent?.title || '',\n },\n };\n });\n\n if (reports.length === 0) {\n return;\n }\n\n this.reportsByTestId.set(testId, {\n testTitle,\n reports,\n });\n }\n\n private finalizeMergedReport(): void {\n this.ensureOutputRoot();\n const tool = new ReportMergingTool();\n let reportCount = 0;\n for (const entry of this.reportsByTestId.values()) {\n for (const report of entry.reports) {\n tool.append(report);\n reportCount += 1;\n }\n }\n\n if (reportCount === 0) {\n return;\n }\n\n const targetName = this.getReportFilename();\n if (reportCount === 1) {\n const firstReport = Array.from(this.reportsByTestId.values())[0]\n ?.reports[0];\n if (!firstReport) {\n return;\n }\n if (firstReport.reportFilePath) {\n const targetPath = this.getReportPath();\n this.copyReport(firstReport.reportFilePath, targetPath);\n printReportMsg(targetPath);\n return;\n }\n\n const mergedReportPath = tool.mergeReports(targetName, {\n overwrite: true,\n });\n if (mergedReportPath) {\n printReportMsg(mergedReportPath);\n }\n return;\n }\n\n const mergedReportPath = tool.mergeReports(targetName, {\n overwrite: true,\n });\n if (mergedReportPath) {\n printReportMsg(mergedReportPath);\n }\n }\n\n private finalizeSeparateReports(): void {\n this.ensureOutputRoot();\n for (const entry of this.reportsByTestId.values()) {\n const targetName = this.getReportFilename(entry.testTitle);\n if (entry.reports.length === 1) {\n const firstReport = entry.reports[0];\n if (firstReport.reportFilePath) {\n const targetPath = this.getReportPath(entry.testTitle);\n this.copyReport(firstReport.reportFilePath, targetPath);\n printReportMsg(targetPath);\n continue;\n }\n\n const tool = new ReportMergingTool();\n tool.append(firstReport);\n const reportPath = tool.mergeReports(targetName, {\n overwrite: true,\n });\n if (reportPath) {\n printReportMsg(reportPath);\n }\n continue;\n }\n\n const tool = new ReportMergingTool();\n for (const report of entry.reports) {\n tool.append(report);\n }\n const reportPath = tool.mergeReports(targetName, {\n overwrite: true,\n });\n if (reportPath) {\n printReportMsg(reportPath);\n }\n }\n }\n\n async onBegin(config: FullConfig, _suite: Suite) {\n this.hasMultipleProjects = (config.projects?.length || 0) > 1;\n }\n\n onTestBegin(_test: TestCase, _result: TestResult) {}\n\n onTestEnd(test: TestCase, result: TestResult) {\n this.collectReportInfo(test, result);\n }\n\n async onEnd() {\n if (this.mode === 'merged') {\n this.finalizeMergedReport();\n return;\n }\n\n if (this.mode === 'separate') {\n this.finalizeSeparateReports();\n }\n }\n}\n\nexport default MidsceneReporter;\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","MidsceneReporter","reporterType","Error","testTitle","baseTag","replaceIllegalPathCharsAndSpace","generatedFilename","getReportFileName","fileName","join","getMidsceneRunSubDir","mkdirSync","reportFilePath","targetPath","isDirectoryModeReport","targetDir","dirname","cpSync","copyFileSync","test","result","reportAnnotations","annotation","retry","testId","projectName","undefined","projectSuffix","reports","existsSync","logMsg","tool","ReportMergingTool","reportCount","entry","report","targetName","firstReport","Array","printReportMsg","mergedReportPath","reportPath","config","_suite","_test","_result","options","Map"],"mappings":"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"}
@@ -215,7 +215,6 @@ async function puppeteerAgentForTarget(target, preference, browser, existingPage
215
215
  const agent = new external_index_js_namespaceObject.PuppeteerAgent(page, {
216
216
  ...preferenceToUse,
217
217
  aiActContext,
218
- waitForNetworkIdleTimeout: 'number' == typeof target.waitForNetworkIdle?.timeout ? target.waitForNetworkIdle.timeout : void 0,
219
218
  forceSameTabNavigation: void 0 !== target.forceSameTabNavigation ? target.forceSameTabNavigation : true
220
219
  });
221
220
  freeFn.push({
@@ -1 +1 @@
1
- {"version":3,"file":"puppeteer/agent-launcher.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/puppeteer/agent-launcher.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { readFileSync } from 'node:fs';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\n\nimport { PuppeteerAgent } from '@/puppeteer/index';\nimport type { AgentOpt, Cache, MidsceneYamlScriptWebEnv } from '@midscene/core';\nimport { DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT } from '@midscene/shared/constants';\nimport puppeteer, { type Browser, type Page } from 'puppeteer';\n\nexport const defaultUA =\n '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';\nexport const defaultViewportWidth = 1440;\nexport const defaultViewportHeight = 768;\n// Setting deviceScaleFactor value to `0` means reset this value to the system default in Puppeteer.\nexport const defaultViewportScale = 0;\nexport const defaultWaitForNetworkIdleTimeout =\n DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT;\n\nexport function resolveAiActionContext(\n target: MidsceneYamlScriptWebEnv,\n preference?: Partial<Pick<AgentOpt, 'aiActionContext' | 'aiActContext'>>,\n): AgentOpt['aiActionContext'] | undefined {\n // Prefer agent-level preference if provided; otherwise fall back to target-level context.\n // Priority: preference.aiActContext > preference.aiActionContext (deprecated) > target.aiActionContext\n const data =\n preference?.aiActContext ??\n preference?.aiActionContext ??\n target.aiActionContext;\n return data;\n}\n\n/**\n * Chrome arguments that may reduce browser security.\n * These should only be used in controlled testing environments.\n *\n * Security implications:\n * - `--no-sandbox`: Disables Chrome's sandbox security model\n * - `--disable-setuid-sandbox`: Disables setuid sandbox on Linux\n * - `--disable-web-security`: Allows cross-origin requests without CORS\n * - `--ignore-certificate-errors`: Ignores SSL/TLS certificate errors\n * - `--disable-features=IsolateOrigins`: Disables origin isolation\n * - `--disable-site-isolation-trials`: Disables site isolation\n * - `--allow-running-insecure-content`: Allows mixed HTTP/HTTPS content\n */\nconst DANGEROUS_ARGS = [\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-web-security',\n '--ignore-certificate-errors',\n '--disable-features=IsolateOrigins',\n '--disable-site-isolation-trials',\n '--allow-running-insecure-content',\n] as const;\n\n/**\n * Validates Chrome launch arguments for security concerns.\n * Emits a warning if dangerous arguments are detected.\n *\n * This function filters out arguments that are already present in baseArgs\n * to avoid warning about platform-specific defaults (e.g., --no-sandbox on non-Windows).\n *\n * @param args - Chrome launch arguments to validate\n * @param baseArgs - Base Chrome arguments already configured\n *\n * @example\n * ```typescript\n * // Will show warning for --disable-web-security\n * validateChromeArgs(['--disable-web-security', '--headless'], ['--no-sandbox']);\n *\n * // Will NOT show warning for --no-sandbox (already in baseArgs)\n * validateChromeArgs(['--no-sandbox'], ['--no-sandbox', '--headless']);\n * ```\n */\nfunction validateChromeArgs(args: string[], baseArgs: string[]): void {\n // Filter out arguments that are already in baseArgs\n const newArgs = args.filter(\n (arg) =>\n !baseArgs.some((baseArg) => {\n // Check if arg starts with the same flag as baseArg (before '=' if present)\n const argFlag = arg.split('=')[0];\n const baseFlag = baseArg.split('=')[0];\n return argFlag === baseFlag;\n }),\n );\n\n const dangerousArgs = newArgs.filter((arg) =>\n DANGEROUS_ARGS.some((dangerous) => arg.startsWith(dangerous)),\n );\n\n if (dangerousArgs.length > 0) {\n console.warn(\n `Warning: Dangerous Chrome arguments detected: ${dangerousArgs.join(', ')}.\\nThese arguments may reduce browser security. Use only in controlled testing environments.`,\n );\n }\n}\n\ninterface FreeFn {\n name: string;\n fn: () => void;\n}\n\nconst launcherDebug = getDebug('puppeteer:launcher');\n\nexport interface BuildChromeArgsOptions {\n userAgent?: string;\n windowSize?: { width: number; height: number };\n chromeArgs?: string[];\n}\n\n/**\n * Builds Chrome launch arguments with sensible defaults.\n *\n * Platform-specific behavior:\n * - On non-Windows systems, automatically adds --no-sandbox and --disable-setuid-sandbox\n * for compatibility with containerized/CI environments\n *\n * @param options - Configuration options for Chrome arguments\n * @returns Array of Chrome launch arguments\n *\n * @example\n * ```typescript\n * // Basic usage\n * const args = buildChromeArgs();\n *\n * // With custom arguments\n * const args = buildChromeArgs({\n * chromeArgs: ['--disable-gpu', '--disable-dev-shm-usage'],\n * userAgent: 'CustomUA/1.0',\n * windowSize: { width: 1920, height: 1080 },\n * });\n * ```\n */\nexport function buildChromeArgs(options?: BuildChromeArgsOptions): string[] {\n const isWindows = process.platform === 'win32';\n\n const sandboxArgs = isWindows\n ? []\n : ['--no-sandbox', '--disable-setuid-sandbox'];\n const featureArgs = [\n '--disable-features=HttpsFirstBalancedModeAutoEnable',\n '--disable-features=PasswordLeakDetection',\n '--disable-save-password-bubble',\n ];\n const userAgentArg = options?.userAgent\n ? [`--user-agent=\"${options.userAgent}\"`]\n : [];\n const windowSizeArg = options?.windowSize\n ? [`--window-size=${options.windowSize.width},${options.windowSize.height}`]\n : [];\n\n const baseArgs = [\n ...sandboxArgs,\n ...featureArgs,\n ...userAgentArg,\n ...windowSizeArg,\n ];\n\n if (options?.chromeArgs?.length) {\n validateChromeArgs(options.chromeArgs, baseArgs);\n return [...baseArgs, ...options.chromeArgs];\n }\n\n return baseArgs;\n}\n\nexport async function launchPuppeteerPage(\n target: MidsceneYamlScriptWebEnv,\n preference?: {\n headed?: boolean;\n keepWindow?: boolean;\n ignoreDefaultArgs?: boolean | string[];\n },\n browser?: Browser,\n existingPage?: Page,\n) {\n assert(target.url, 'url is required');\n const freeFn: FreeFn[] = [];\n\n // prepare the environment\n const ua = target.userAgent || defaultUA;\n let width = defaultViewportWidth;\n if (target.viewportWidth !== undefined && target.viewportWidth !== null) {\n assert(\n typeof target.viewportWidth === 'number',\n 'viewportWidth must be a number',\n );\n width = Number.parseInt(target.viewportWidth as unknown as string, 10);\n assert(width > 0, `viewportWidth must be greater than 0, but got ${width}`);\n }\n let height = defaultViewportHeight;\n if (target.viewportHeight !== undefined && target.viewportHeight !== null) {\n assert(\n typeof target.viewportHeight === 'number',\n 'viewportHeight must be a number',\n );\n height = Number.parseInt(target.viewportHeight as unknown as string, 10);\n assert(\n height > 0,\n `viewportHeight must be greater than 0, but got ${height}`,\n );\n }\n let dpr = defaultViewportScale;\n if (\n target.deviceScaleFactor !== undefined &&\n target.deviceScaleFactor !== null\n ) {\n assert(\n typeof target.deviceScaleFactor === 'number',\n 'deviceScaleFactor must be a number',\n );\n dpr = Number.parseInt(target.deviceScaleFactor as unknown as string, 10);\n assert(dpr >= 0, `deviceScaleFactor must be >= 0, but got ${dpr}`);\n }\n const viewportConfig = {\n width,\n height,\n deviceScaleFactor: dpr,\n };\n\n const headed = preference?.headed || preference?.keepWindow;\n const defaultViewportConfig = headed ? null : viewportConfig;\n\n // launch the browser\n if (headed && process.env.CI === '1') {\n console.warn(\n 'you are probably running headed mode in CI, this will usually fail.',\n );\n }\n\n // Build Chrome arguments using the shared helper\n // Only pass windowSize in headed mode; in headless mode, defaultViewport takes precedence\n // Add 100px to height to account for browser UI (address bar, tabs, etc.)\n const browserUIHeight = 100;\n const args = buildChromeArgs({\n userAgent: ua,\n windowSize: headed\n ? { width, height: height + browserUIHeight }\n : undefined,\n chromeArgs: target.chromeArgs,\n });\n\n launcherDebug(\n 'launching browser with viewport, headed',\n headed,\n 'viewport',\n viewportConfig,\n 'args',\n args,\n 'preference',\n preference,\n );\n // If an existing page is provided, reuse it instead of creating a new one\n // This allows sharing localStorage and sessionStorage between YAML files\n let page: Page;\n let browserInstance = browser;\n\n if (existingPage) {\n // Reuse the existing page - this preserves localStorage and sessionStorage\n page = existingPage;\n launcherDebug('reusing existing page for shared browser context');\n\n // Get the browser instance from the existing page\n if (!browserInstance) {\n browserInstance = page.browser();\n }\n } else {\n // Create a new browser and page\n if (!browserInstance) {\n browserInstance = await puppeteer.launch({\n headless: !preference?.headed,\n defaultViewport: defaultViewportConfig,\n args,\n acceptInsecureCerts: target.acceptInsecureCerts,\n ignoreDefaultArgs: preference?.ignoreDefaultArgs,\n });\n freeFn.push({\n name: 'puppeteer_browser',\n fn: () => {\n if (!preference?.keepWindow) {\n if (process.platform === 'win32') {\n setTimeout(() => {\n browserInstance?.close();\n }, 800);\n } else {\n browserInstance?.close();\n }\n }\n },\n });\n }\n page = await browserInstance.newPage();\n }\n\n if (target.cookie) {\n const cookieFileContent = readFileSync(target.cookie, 'utf-8');\n await browserInstance.setCookie(...JSON.parse(cookieFileContent));\n }\n\n if (ua) {\n await page.setUserAgent(ua);\n }\n\n if (viewportConfig) {\n await page.setViewport(viewportConfig);\n }\n\n const waitForNetworkIdleTimeout =\n typeof target.waitForNetworkIdle?.timeout === 'number'\n ? target.waitForNetworkIdle.timeout\n : defaultWaitForNetworkIdleTimeout;\n\n try {\n launcherDebug('goto', target.url);\n await page.goto(target.url);\n if (waitForNetworkIdleTimeout > 0) {\n launcherDebug('waitForNetworkIdle', waitForNetworkIdleTimeout);\n await page.waitForNetworkIdle({\n timeout: waitForNetworkIdleTimeout,\n });\n }\n } catch (e) {\n if (\n typeof target.waitForNetworkIdle?.continueOnNetworkIdleError ===\n 'boolean' &&\n !target.waitForNetworkIdle?.continueOnNetworkIdleError\n ) {\n const newError = new Error(`failed to wait for network idle: ${e}`, {\n cause: e,\n });\n throw newError;\n }\n const newMessage = `failed to wait for network idle after ${waitForNetworkIdleTimeout}ms, but the script will continue.`;\n console.warn(newMessage);\n }\n\n return { page, freeFn };\n}\n\nexport async function puppeteerAgentForTarget(\n target: MidsceneYamlScriptWebEnv,\n preference?: {\n headed?: boolean;\n keepWindow?: boolean;\n } & Partial<\n Pick<\n AgentOpt,\n | 'groupName'\n | 'groupDescription'\n | 'generateReport'\n | 'autoPrintReportMsg'\n | 'reportFileName'\n | 'replanningCycleLimit'\n | 'cache'\n | 'aiActionContext'\n >\n >,\n browser?: Browser,\n existingPage?: Page,\n) {\n const { page, freeFn } = await launchPuppeteerPage(\n target,\n preference,\n browser,\n existingPage,\n );\n const aiActContext = resolveAiActionContext(target, preference);\n\n const { aiActionContext, ...preferenceToUse } = preference ?? {};\n\n // prepare Midscene agent\n const agent = new PuppeteerAgent(page, {\n ...preferenceToUse,\n aiActContext,\n waitForNetworkIdleTimeout:\n typeof target.waitForNetworkIdle?.timeout === 'number'\n ? target.waitForNetworkIdle.timeout\n : undefined,\n forceSameTabNavigation:\n typeof target.forceSameTabNavigation !== 'undefined'\n ? target.forceSameTabNavigation\n : true, // true for default in yaml script\n });\n\n freeFn.push({\n name: 'midscene_puppeteer_agent',\n fn: () => agent.destroy(),\n });\n\n return { agent, freeFn };\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","defaultUA","defaultViewportWidth","defaultViewportHeight","defaultViewportScale","defaultWaitForNetworkIdleTimeout","DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT","resolveAiActionContext","target","preference","data","DANGEROUS_ARGS","validateChromeArgs","args","baseArgs","newArgs","arg","baseArg","argFlag","baseFlag","dangerousArgs","dangerous","console","launcherDebug","getDebug","buildChromeArgs","options","isWindows","process","sandboxArgs","featureArgs","userAgentArg","windowSizeArg","launchPuppeteerPage","browser","existingPage","assert","freeFn","ua","width","undefined","Number","height","dpr","viewportConfig","headed","defaultViewportConfig","browserUIHeight","page","browserInstance","puppeteer","setTimeout","cookieFileContent","readFileSync","JSON","waitForNetworkIdleTimeout","e","newError","Error","newMessage","puppeteerAgentForTarget","aiActContext","aiActionContext","preferenceToUse","agent","PuppeteerAgent"],"mappings":"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"}
1
+ {"version":3,"file":"puppeteer/agent-launcher.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/puppeteer/agent-launcher.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { readFileSync } from 'node:fs';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\n\nimport { PuppeteerAgent } from '@/puppeteer/index';\nimport type { AgentOpt, Cache, MidsceneYamlScriptWebEnv } from '@midscene/core';\nimport { DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT } from '@midscene/shared/constants';\nimport puppeteer, { type Browser, type Page } from 'puppeteer';\n\nexport const defaultUA =\n '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';\nexport const defaultViewportWidth = 1440;\nexport const defaultViewportHeight = 768;\n// Setting deviceScaleFactor value to `0` means reset this value to the system default in Puppeteer.\nexport const defaultViewportScale = 0;\nexport const defaultWaitForNetworkIdleTimeout =\n DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT;\n\nexport function resolveAiActionContext(\n target: MidsceneYamlScriptWebEnv,\n preference?: Partial<Pick<AgentOpt, 'aiActionContext' | 'aiActContext'>>,\n): AgentOpt['aiActionContext'] | undefined {\n // Prefer agent-level preference if provided; otherwise fall back to target-level context.\n // Priority: preference.aiActContext > preference.aiActionContext (deprecated) > target.aiActionContext\n const data =\n preference?.aiActContext ??\n preference?.aiActionContext ??\n target.aiActionContext;\n return data;\n}\n\n/**\n * Chrome arguments that may reduce browser security.\n * These should only be used in controlled testing environments.\n *\n * Security implications:\n * - `--no-sandbox`: Disables Chrome's sandbox security model\n * - `--disable-setuid-sandbox`: Disables setuid sandbox on Linux\n * - `--disable-web-security`: Allows cross-origin requests without CORS\n * - `--ignore-certificate-errors`: Ignores SSL/TLS certificate errors\n * - `--disable-features=IsolateOrigins`: Disables origin isolation\n * - `--disable-site-isolation-trials`: Disables site isolation\n * - `--allow-running-insecure-content`: Allows mixed HTTP/HTTPS content\n */\nconst DANGEROUS_ARGS = [\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-web-security',\n '--ignore-certificate-errors',\n '--disable-features=IsolateOrigins',\n '--disable-site-isolation-trials',\n '--allow-running-insecure-content',\n] as const;\n\n/**\n * Validates Chrome launch arguments for security concerns.\n * Emits a warning if dangerous arguments are detected.\n *\n * This function filters out arguments that are already present in baseArgs\n * to avoid warning about platform-specific defaults (e.g., --no-sandbox on non-Windows).\n *\n * @param args - Chrome launch arguments to validate\n * @param baseArgs - Base Chrome arguments already configured\n *\n * @example\n * ```typescript\n * // Will show warning for --disable-web-security\n * validateChromeArgs(['--disable-web-security', '--headless'], ['--no-sandbox']);\n *\n * // Will NOT show warning for --no-sandbox (already in baseArgs)\n * validateChromeArgs(['--no-sandbox'], ['--no-sandbox', '--headless']);\n * ```\n */\nfunction validateChromeArgs(args: string[], baseArgs: string[]): void {\n // Filter out arguments that are already in baseArgs\n const newArgs = args.filter(\n (arg) =>\n !baseArgs.some((baseArg) => {\n // Check if arg starts with the same flag as baseArg (before '=' if present)\n const argFlag = arg.split('=')[0];\n const baseFlag = baseArg.split('=')[0];\n return argFlag === baseFlag;\n }),\n );\n\n const dangerousArgs = newArgs.filter((arg) =>\n DANGEROUS_ARGS.some((dangerous) => arg.startsWith(dangerous)),\n );\n\n if (dangerousArgs.length > 0) {\n console.warn(\n `Warning: Dangerous Chrome arguments detected: ${dangerousArgs.join(', ')}.\\nThese arguments may reduce browser security. Use only in controlled testing environments.`,\n );\n }\n}\n\ninterface FreeFn {\n name: string;\n fn: () => void;\n}\n\nconst launcherDebug = getDebug('puppeteer:launcher');\n\nexport interface BuildChromeArgsOptions {\n userAgent?: string;\n windowSize?: { width: number; height: number };\n chromeArgs?: string[];\n}\n\n/**\n * Builds Chrome launch arguments with sensible defaults.\n *\n * Platform-specific behavior:\n * - On non-Windows systems, automatically adds --no-sandbox and --disable-setuid-sandbox\n * for compatibility with containerized/CI environments\n *\n * @param options - Configuration options for Chrome arguments\n * @returns Array of Chrome launch arguments\n *\n * @example\n * ```typescript\n * // Basic usage\n * const args = buildChromeArgs();\n *\n * // With custom arguments\n * const args = buildChromeArgs({\n * chromeArgs: ['--disable-gpu', '--disable-dev-shm-usage'],\n * userAgent: 'CustomUA/1.0',\n * windowSize: { width: 1920, height: 1080 },\n * });\n * ```\n */\nexport function buildChromeArgs(options?: BuildChromeArgsOptions): string[] {\n const isWindows = process.platform === 'win32';\n\n const sandboxArgs = isWindows\n ? []\n : ['--no-sandbox', '--disable-setuid-sandbox'];\n const featureArgs = [\n '--disable-features=HttpsFirstBalancedModeAutoEnable',\n '--disable-features=PasswordLeakDetection',\n '--disable-save-password-bubble',\n ];\n const userAgentArg = options?.userAgent\n ? [`--user-agent=\"${options.userAgent}\"`]\n : [];\n const windowSizeArg = options?.windowSize\n ? [`--window-size=${options.windowSize.width},${options.windowSize.height}`]\n : [];\n\n const baseArgs = [\n ...sandboxArgs,\n ...featureArgs,\n ...userAgentArg,\n ...windowSizeArg,\n ];\n\n if (options?.chromeArgs?.length) {\n validateChromeArgs(options.chromeArgs, baseArgs);\n return [...baseArgs, ...options.chromeArgs];\n }\n\n return baseArgs;\n}\n\nexport async function launchPuppeteerPage(\n target: MidsceneYamlScriptWebEnv,\n preference?: {\n headed?: boolean;\n keepWindow?: boolean;\n ignoreDefaultArgs?: boolean | string[];\n },\n browser?: Browser,\n existingPage?: Page,\n) {\n assert(target.url, 'url is required');\n const freeFn: FreeFn[] = [];\n\n // prepare the environment\n const ua = target.userAgent || defaultUA;\n let width = defaultViewportWidth;\n if (target.viewportWidth !== undefined && target.viewportWidth !== null) {\n assert(\n typeof target.viewportWidth === 'number',\n 'viewportWidth must be a number',\n );\n width = Number.parseInt(target.viewportWidth as unknown as string, 10);\n assert(width > 0, `viewportWidth must be greater than 0, but got ${width}`);\n }\n let height = defaultViewportHeight;\n if (target.viewportHeight !== undefined && target.viewportHeight !== null) {\n assert(\n typeof target.viewportHeight === 'number',\n 'viewportHeight must be a number',\n );\n height = Number.parseInt(target.viewportHeight as unknown as string, 10);\n assert(\n height > 0,\n `viewportHeight must be greater than 0, but got ${height}`,\n );\n }\n let dpr = defaultViewportScale;\n if (\n target.deviceScaleFactor !== undefined &&\n target.deviceScaleFactor !== null\n ) {\n assert(\n typeof target.deviceScaleFactor === 'number',\n 'deviceScaleFactor must be a number',\n );\n dpr = Number.parseInt(target.deviceScaleFactor as unknown as string, 10);\n assert(dpr >= 0, `deviceScaleFactor must be >= 0, but got ${dpr}`);\n }\n const viewportConfig = {\n width,\n height,\n deviceScaleFactor: dpr,\n };\n\n const headed = preference?.headed || preference?.keepWindow;\n const defaultViewportConfig = headed ? null : viewportConfig;\n\n // launch the browser\n if (headed && process.env.CI === '1') {\n console.warn(\n 'you are probably running headed mode in CI, this will usually fail.',\n );\n }\n\n // Build Chrome arguments using the shared helper\n // Only pass windowSize in headed mode; in headless mode, defaultViewport takes precedence\n // Add 100px to height to account for browser UI (address bar, tabs, etc.)\n const browserUIHeight = 100;\n const args = buildChromeArgs({\n userAgent: ua,\n windowSize: headed\n ? { width, height: height + browserUIHeight }\n : undefined,\n chromeArgs: target.chromeArgs,\n });\n\n launcherDebug(\n 'launching browser with viewport, headed',\n headed,\n 'viewport',\n viewportConfig,\n 'args',\n args,\n 'preference',\n preference,\n );\n // If an existing page is provided, reuse it instead of creating a new one\n // This allows sharing localStorage and sessionStorage between YAML files\n let page: Page;\n let browserInstance = browser;\n\n if (existingPage) {\n // Reuse the existing page - this preserves localStorage and sessionStorage\n page = existingPage;\n launcherDebug('reusing existing page for shared browser context');\n\n // Get the browser instance from the existing page\n if (!browserInstance) {\n browserInstance = page.browser();\n }\n } else {\n // Create a new browser and page\n if (!browserInstance) {\n browserInstance = await puppeteer.launch({\n headless: !preference?.headed,\n defaultViewport: defaultViewportConfig,\n args,\n acceptInsecureCerts: target.acceptInsecureCerts,\n ignoreDefaultArgs: preference?.ignoreDefaultArgs,\n });\n freeFn.push({\n name: 'puppeteer_browser',\n fn: () => {\n if (!preference?.keepWindow) {\n if (process.platform === 'win32') {\n setTimeout(() => {\n browserInstance?.close();\n }, 800);\n } else {\n browserInstance?.close();\n }\n }\n },\n });\n }\n page = await browserInstance.newPage();\n }\n\n if (target.cookie) {\n const cookieFileContent = readFileSync(target.cookie, 'utf-8');\n await browserInstance.setCookie(...JSON.parse(cookieFileContent));\n }\n\n if (ua) {\n await page.setUserAgent(ua);\n }\n\n if (viewportConfig) {\n await page.setViewport(viewportConfig);\n }\n\n const waitForNetworkIdleTimeout =\n typeof target.waitForNetworkIdle?.timeout === 'number'\n ? target.waitForNetworkIdle.timeout\n : defaultWaitForNetworkIdleTimeout;\n\n try {\n launcherDebug('goto', target.url);\n await page.goto(target.url);\n if (waitForNetworkIdleTimeout > 0) {\n launcherDebug('waitForNetworkIdle', waitForNetworkIdleTimeout);\n await page.waitForNetworkIdle({\n timeout: waitForNetworkIdleTimeout,\n });\n }\n } catch (e) {\n if (\n typeof target.waitForNetworkIdle?.continueOnNetworkIdleError ===\n 'boolean' &&\n !target.waitForNetworkIdle?.continueOnNetworkIdleError\n ) {\n const newError = new Error(`failed to wait for network idle: ${e}`, {\n cause: e,\n });\n throw newError;\n }\n const newMessage = `failed to wait for network idle after ${waitForNetworkIdleTimeout}ms, but the script will continue.`;\n console.warn(newMessage);\n }\n\n return { page, freeFn };\n}\n\nexport async function puppeteerAgentForTarget(\n target: MidsceneYamlScriptWebEnv,\n preference?: {\n headed?: boolean;\n keepWindow?: boolean;\n } & Partial<\n Pick<\n AgentOpt,\n | 'groupName'\n | 'groupDescription'\n | 'generateReport'\n | 'persistExecutionDump'\n | 'autoPrintReportMsg'\n | 'reportFileName'\n | 'replanningCycleLimit'\n | 'cache'\n | 'aiActionContext'\n >\n >,\n browser?: Browser,\n existingPage?: Page,\n) {\n const { page, freeFn } = await launchPuppeteerPage(\n target,\n preference,\n browser,\n existingPage,\n );\n const aiActContext = resolveAiActionContext(target, preference);\n\n const { aiActionContext, ...preferenceToUse } = preference ?? {};\n\n // prepare Midscene agent\n const agent = new PuppeteerAgent(page, {\n ...preferenceToUse,\n aiActContext,\n forceSameTabNavigation:\n typeof target.forceSameTabNavigation !== 'undefined'\n ? target.forceSameTabNavigation\n : true, // true for default in yaml script\n });\n\n freeFn.push({\n name: 'midscene_puppeteer_agent',\n fn: () => agent.destroy(),\n });\n\n return { agent, freeFn };\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","defaultUA","defaultViewportWidth","defaultViewportHeight","defaultViewportScale","defaultWaitForNetworkIdleTimeout","DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT","resolveAiActionContext","target","preference","data","DANGEROUS_ARGS","validateChromeArgs","args","baseArgs","newArgs","arg","baseArg","argFlag","baseFlag","dangerousArgs","dangerous","console","launcherDebug","getDebug","buildChromeArgs","options","isWindows","process","sandboxArgs","featureArgs","userAgentArg","windowSizeArg","launchPuppeteerPage","browser","existingPage","assert","freeFn","ua","width","undefined","Number","height","dpr","viewportConfig","headed","defaultViewportConfig","browserUIHeight","page","browserInstance","puppeteer","setTimeout","cookieFileContent","readFileSync","JSON","waitForNetworkIdleTimeout","e","newError","Error","newMessage","puppeteerAgentForTarget","aiActContext","aiActionContext","preferenceToUse","agent","PuppeteerAgent"],"mappings":"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"}
@@ -15,6 +15,9 @@ export declare const PlaywrightAiFixture: (options?: {
15
15
  waitForNavigationTimeout?: number;
16
16
  cache?: PlaywrightCache;
17
17
  }) => {
18
+ _midsceneFinalizeReports: ((({}: Record<string, unknown>, use: any, testInfo: TestInfo) => Promise<void>) | {
19
+ auto: boolean;
20
+ })[];
18
21
  agentForPage: ({ page }: {
19
22
  page: OriginPlaywrightPage;
20
23
  }, use: any, testInfo: TestInfo) => Promise<void>;