@one2x/playwright 1.57.0-alpha.10 → 1.57.0-alpha.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.
|
@@ -59,7 +59,8 @@ class BrowserServerBackend {
|
|
|
59
59
|
await response.finish();
|
|
60
60
|
this._sessionLog?.logResponse(response);
|
|
61
61
|
} catch (error) {
|
|
62
|
-
|
|
62
|
+
console.error("error", error);
|
|
63
|
+
response.addError(String(error.stack));
|
|
63
64
|
} finally {
|
|
64
65
|
context.setRunningTool(void 0);
|
|
65
66
|
}
|
|
@@ -21,7 +21,7 @@ __export(actionRetry_exports, {
|
|
|
21
21
|
retryWithAllowIntercept: () => retryWithAllowIntercept
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(actionRetry_exports);
|
|
24
|
-
async function retryWithAllowIntercept(action, options, mode = "
|
|
24
|
+
async function retryWithAllowIntercept(action, options, mode = "auto") {
|
|
25
25
|
if (mode === "always") {
|
|
26
26
|
const optionsWithAllowIntercept = { ...options, allowIntercept: true };
|
|
27
27
|
await action(optionsWithAllowIntercept);
|
|
@@ -40,9 +40,16 @@ async function retryWithAllowIntercept(action, options, mode = "never") {
|
|
|
40
40
|
}
|
|
41
41
|
if (mode === "never") {
|
|
42
42
|
const enhancedError = new Error(
|
|
43
|
-
`
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
`RETRYABLE ERROR: Element is covered by an overlay/modal.
|
|
44
|
+
|
|
45
|
+
SOLUTION: Retry this tool call with allowIntercept option added:
|
|
46
|
+
Add parameter: allowIntercept: "always"
|
|
47
|
+
|
|
48
|
+
This will click through the overlay to reach the target element.
|
|
49
|
+
|
|
50
|
+
Alternative: Use allowIntercept: "auto" to automatically retry on interception.
|
|
51
|
+
|
|
52
|
+
Technical details - Intercepting element: ${interceptorInfo}`
|
|
46
53
|
);
|
|
47
54
|
enhancedError.stack = error.stack;
|
|
48
55
|
throw enhancedError;
|
|
@@ -48,16 +48,12 @@ const fillForm = (0, import_tool.defineTabTool)({
|
|
|
48
48
|
type: import_bundle.z.enum(["textbox", "checkbox", "radio", "combobox", "slider"]).describe("Type of the field"),
|
|
49
49
|
ref: import_bundle.z.string().describe("Exact target field reference from the page snapshot"),
|
|
50
50
|
value: import_bundle.z.string().describe("Value to fill in the field. If the field is a checkbox, the value should be `true` or `false`. If the field is a combobox, the value should be the text of the option.")
|
|
51
|
-
})).describe("Fields to fill in")
|
|
52
|
-
allowIntercept: import_bundle.z.enum(["never", "auto", "always"]).default("never").describe(
|
|
53
|
-
'How to handle element interception for checkbox/radio fields: "never" (default) - fail if element is intercepted; "auto" - automatically retry with allowIntercept if intercepted; "always" - use allowIntercept from the start'
|
|
54
|
-
)
|
|
51
|
+
})).describe("Fields to fill in")
|
|
55
52
|
}),
|
|
56
53
|
type: "input"
|
|
57
54
|
},
|
|
58
55
|
handle: async (tab, params, response) => {
|
|
59
56
|
response.setIncludeSnapshot();
|
|
60
|
-
const mode = params.allowIntercept;
|
|
61
57
|
for (const field of params.fields) {
|
|
62
58
|
const { locator, resolved } = await tab.refLocator({ element: field.name, ref: field.ref });
|
|
63
59
|
const locatorSource = `await page.${resolved}`;
|
|
@@ -68,12 +64,11 @@ const fillForm = (0, import_tool.defineTabTool)({
|
|
|
68
64
|
} else if (field.type === "checkbox" || field.type === "radio") {
|
|
69
65
|
const result = await (0, import_actionRetry.retryWithAllowIntercept)(
|
|
70
66
|
async (opts) => await locator.setChecked(field.value === "true", opts),
|
|
71
|
-
{}
|
|
72
|
-
mode
|
|
67
|
+
{}
|
|
73
68
|
);
|
|
74
69
|
if (result.mode === "auto" && result.interceptorInfo)
|
|
75
70
|
(0, import_utils.addInterceptorWarning)(response, resolved, ".setChecked(value, { allowIntercept: true })", result.interceptorInfo);
|
|
76
|
-
const needsAllowIntercept = result.mode === "auto" || result.mode === "always";
|
|
71
|
+
const needsAllowIntercept = result.mode === "auto" && result.interceptorInfo || result.mode === "always";
|
|
77
72
|
const optionsAttr = needsAllowIntercept ? ", { allowIntercept: true }" : "";
|
|
78
73
|
response.addCode(`${locatorSource}.setChecked(${field.value}${optionsAttr});`);
|
|
79
74
|
} else if (field.type === "combobox") {
|
|
@@ -58,10 +58,7 @@ const elementSchema = import_bundle.z.object({
|
|
|
58
58
|
const clickSchema = elementSchema.extend({
|
|
59
59
|
doubleClick: import_bundle.z.boolean().optional().describe("Whether to perform a double click instead of a single click"),
|
|
60
60
|
button: import_bundle.z.enum(["left", "right", "middle"]).optional().describe("Button to click, defaults to left"),
|
|
61
|
-
modifiers: import_bundle.z.array(import_bundle.z.enum(["Alt", "Control", "ControlOrMeta", "Meta", "Shift"])).optional().describe("Modifier keys to press")
|
|
62
|
-
allowIntercept: import_bundle.z.enum(["never", "auto", "always"]).default("never").describe(
|
|
63
|
-
'How to handle element interception: "never" (default) - fail if element is intercepted; "auto" - automatically retry with allowIntercept if intercepted; "always" - use allowIntercept from the start'
|
|
64
|
-
)
|
|
61
|
+
modifiers: import_bundle.z.array(import_bundle.z.enum(["Alt", "Control", "ControlOrMeta", "Meta", "Shift"])).optional().describe("Modifier keys to press")
|
|
65
62
|
});
|
|
66
63
|
const click = (0, import_tool.defineTabTool)({
|
|
67
64
|
capability: "core",
|
|
@@ -75,7 +72,6 @@ const click = (0, import_tool.defineTabTool)({
|
|
|
75
72
|
handle: async (tab, params, response) => {
|
|
76
73
|
response.setIncludeSnapshot();
|
|
77
74
|
const { locator, resolved } = await tab.refLocator(params);
|
|
78
|
-
const mode = params.allowIntercept;
|
|
79
75
|
const options = {
|
|
80
76
|
button: params.button,
|
|
81
77
|
modifiers: params.modifiers
|
|
@@ -89,15 +85,17 @@ const click = (0, import_tool.defineTabTool)({
|
|
|
89
85
|
else
|
|
90
86
|
await locator.click(opts);
|
|
91
87
|
},
|
|
92
|
-
options
|
|
93
|
-
mode
|
|
88
|
+
options
|
|
94
89
|
);
|
|
95
90
|
});
|
|
91
|
+
if (!result) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
96
94
|
if (result.mode === "auto" && result.interceptorInfo) {
|
|
97
95
|
const actionName = params.doubleClick ? ".dblclick({ allowIntercept: true })" : ".click({ allowIntercept: true })";
|
|
98
96
|
(0, import_utils.addInterceptorWarning)(response, resolved, actionName, result.interceptorInfo);
|
|
99
97
|
}
|
|
100
|
-
const needsAllowIntercept = result.mode === "auto" || result.mode === "always";
|
|
98
|
+
const needsAllowIntercept = result.mode === "auto" && result.interceptorInfo || result.mode === "always";
|
|
101
99
|
const finalOptions = needsAllowIntercept ? { ...options, allowIntercept: true } : options;
|
|
102
100
|
const formatted = javascript.formatObject(finalOptions, " ", "oneline");
|
|
103
101
|
const optionsAttr = formatted !== "{}" ? formatted : "";
|
|
@@ -118,10 +116,7 @@ const drag = (0, import_tool.defineTabTool)({
|
|
|
118
116
|
startElement: import_bundle.z.string().describe("Human-readable source element description used to obtain the permission to interact with the element"),
|
|
119
117
|
startRef: import_bundle.z.string().describe("Exact source element reference from the page snapshot"),
|
|
120
118
|
endElement: import_bundle.z.string().describe("Human-readable target element description used to obtain the permission to interact with the element"),
|
|
121
|
-
endRef: import_bundle.z.string().describe("Exact target element reference from the page snapshot")
|
|
122
|
-
allowIntercept: import_bundle.z.enum(["never", "auto", "always"]).default("never").describe(
|
|
123
|
-
'How to handle element interception: "never" (default) - fail if element is intercepted; "auto" - automatically retry with allowIntercept if intercepted; "always" - use allowIntercept from the start'
|
|
124
|
-
)
|
|
119
|
+
endRef: import_bundle.z.string().describe("Exact target element reference from the page snapshot")
|
|
125
120
|
}),
|
|
126
121
|
type: "input"
|
|
127
122
|
},
|
|
@@ -131,18 +126,19 @@ const drag = (0, import_tool.defineTabTool)({
|
|
|
131
126
|
{ ref: params.startRef, element: params.startElement },
|
|
132
127
|
{ ref: params.endRef, element: params.endElement }
|
|
133
128
|
]);
|
|
134
|
-
const mode = params.allowIntercept;
|
|
135
129
|
let result;
|
|
136
130
|
await tab.waitForCompletion(async () => {
|
|
137
131
|
result = await (0, import_actionRetry.retryWithAllowIntercept)(
|
|
138
132
|
async (opts) => await start.locator.dragTo(end.locator, opts),
|
|
139
|
-
{}
|
|
140
|
-
mode
|
|
133
|
+
{}
|
|
141
134
|
);
|
|
142
135
|
});
|
|
136
|
+
if (!result) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
143
139
|
if (result.mode === "auto" && result.interceptorInfo)
|
|
144
140
|
(0, import_utils.addInterceptorWarning)(response, start.resolved, ".dragTo(target, { allowIntercept: true })", result.interceptorInfo);
|
|
145
|
-
const needsAllowIntercept = result.mode === "auto" || result.mode === "always";
|
|
141
|
+
const needsAllowIntercept = result.mode === "auto" && result.interceptorInfo || result.mode === "always";
|
|
146
142
|
const optionsAttr = needsAllowIntercept ? ", { allowIntercept: true }" : "";
|
|
147
143
|
response.addCode(`await page.${start.resolved}.dragTo(page.${end.resolved}${optionsAttr});`);
|
|
148
144
|
response.setIncludeAutoScreenshot();
|
|
@@ -154,28 +150,25 @@ const hover = (0, import_tool.defineTabTool)({
|
|
|
154
150
|
name: "browser_hover",
|
|
155
151
|
title: "Hover mouse",
|
|
156
152
|
description: "Hover over element on page",
|
|
157
|
-
inputSchema: elementSchema
|
|
158
|
-
allowIntercept: import_bundle.z.enum(["never", "auto", "always"]).default("never").describe(
|
|
159
|
-
'How to handle element interception: "never" (default) - fail if element is intercepted; "auto" - automatically retry with allowIntercept if intercepted; "always" - use allowIntercept from the start'
|
|
160
|
-
)
|
|
161
|
-
}),
|
|
153
|
+
inputSchema: elementSchema,
|
|
162
154
|
type: "input"
|
|
163
155
|
},
|
|
164
156
|
handle: async (tab, params, response) => {
|
|
165
157
|
response.setIncludeSnapshot();
|
|
166
158
|
const { locator, resolved } = await tab.refLocator(params);
|
|
167
|
-
const mode = params.allowIntercept;
|
|
168
159
|
let result;
|
|
169
160
|
await tab.waitForCompletion(async () => {
|
|
170
161
|
result = await (0, import_actionRetry.retryWithAllowIntercept)(
|
|
171
162
|
async (opts) => await locator.hover(opts),
|
|
172
|
-
{}
|
|
173
|
-
mode
|
|
163
|
+
{}
|
|
174
164
|
);
|
|
175
165
|
});
|
|
166
|
+
if (!result) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
176
169
|
if (result.mode === "auto" && result.interceptorInfo)
|
|
177
170
|
(0, import_utils.addInterceptorWarning)(response, resolved, ".hover({ allowIntercept: true })", result.interceptorInfo);
|
|
178
|
-
const needsAllowIntercept = result.mode === "auto" || result.mode === "always";
|
|
171
|
+
const needsAllowIntercept = result.mode === "auto" && result.interceptorInfo || result.mode === "always";
|
|
179
172
|
const optionsAttr = needsAllowIntercept ? "{ allowIntercept: true }" : "";
|
|
180
173
|
response.addCode(`await page.${resolved}.hover(${optionsAttr});`);
|
|
181
174
|
response.setIncludeAutoScreenshot();
|
|
@@ -85,10 +85,10 @@ async function generateLocators(locator) {
|
|
|
85
85
|
return selectors.map((s) => (0, import_utils.asLocator)("javascript", s));
|
|
86
86
|
}
|
|
87
87
|
function addInterceptorWarning(response, targetSelector, actionName, interceptorInfo) {
|
|
88
|
-
response.addResult(
|
|
88
|
+
response.addResult(` Warning: An intercepting element was appearing above target element \`page.${targetSelector}\``);
|
|
89
|
+
response.addResult(` \`${actionName}\` WAS fired to the intercepting element, not the target element`);
|
|
89
90
|
if (interceptorInfo)
|
|
90
|
-
response.addResult(`
|
|
91
|
-
response.addResult(`\u2713 Retried action \`${actionName}\` and succeeded. The \`allowIntercept\` option is CRUCIAL`);
|
|
91
|
+
response.addResult(` Intercepting element: ${interceptorInfo}`);
|
|
92
92
|
}
|
|
93
93
|
// Annotate the CommonJS export names for ESM import in node:
|
|
94
94
|
0 && (module.exports = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@one2x/playwright",
|
|
3
|
-
"version": "1.57.0-alpha.
|
|
3
|
+
"version": "1.57.0-alpha.11",
|
|
4
4
|
"description": "A high-level API to automate web browsers",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"license": "Apache-2.0",
|
|
66
66
|
"dependencies": {
|
|
67
67
|
"content-type": "^1.0.5",
|
|
68
|
-
"playwright-core": "npm:@one2x/playwright-core@1.57.0-alpha.
|
|
68
|
+
"playwright-core": "npm:@one2x/playwright-core@1.57.0-alpha.11",
|
|
69
69
|
"raw-body": "^2.5.2"
|
|
70
70
|
},
|
|
71
71
|
"optionalDependencies": {
|