n8n-nodes-nvk-browser 1.0.3 → 1.0.5
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.
|
@@ -22,7 +22,7 @@ exports.moveAndClickFields = [
|
|
|
22
22
|
type: 'string',
|
|
23
23
|
required: true,
|
|
24
24
|
default: '',
|
|
25
|
-
description: 'For Puppeteer: CSS selector, XPath (with >XPATH> prefix), or code
|
|
25
|
+
description: 'For Puppeteer: CSS selector, XPath (with >XPATH> prefix), or paste the full Puppeteer code from Chrome Recorder (export as "Puppeteer"). The node will automatically extract the first Locator.race().click() block. Examples: "textarea", ">XPATH>/html/body/div", or full code with puppeteer.Locator.race([...]).click(). For Javascript: CSS selector only.',
|
|
26
26
|
typeOptions: {
|
|
27
27
|
rows: 4,
|
|
28
28
|
},
|
|
@@ -146,28 +146,59 @@ class MoveAndClick {
|
|
|
146
146
|
try {
|
|
147
147
|
// Parse selectors from the code pattern
|
|
148
148
|
const locators = [];
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
locators.push(page.locator(cssSel));
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
});
|
|
149
|
+
// Find Locator.race blocks - prioritize blocks that end with .click()
|
|
150
|
+
// Improved regex to handle multiline code from Chrome Recorder
|
|
151
|
+
// Match pattern: puppeteer.Locator.race([...]).setTimeout(...).click(...)
|
|
152
|
+
const clickBlockPattern = /puppeteer\.Locator\.race\s*\(\s*\[([\s\S]*?)\]\s*\)[\s\S]*?\.click\s*\(/;
|
|
153
|
+
const clickBlockMatch = selector.match(clickBlockPattern);
|
|
154
|
+
let raceBlockContent = null;
|
|
155
|
+
if (clickBlockMatch && clickBlockMatch[1]) {
|
|
156
|
+
raceBlockContent = clickBlockMatch[1];
|
|
161
157
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
158
|
+
else {
|
|
159
|
+
// Fallback: find any Locator.race block (even without .click())
|
|
160
|
+
const anyRaceBlockMatch = selector.match(/puppeteer\.Locator\.race\s*\(\s*\[([\s\S]*?)\]\s*\)/);
|
|
161
|
+
if (anyRaceBlockMatch && anyRaceBlockMatch[1]) {
|
|
162
|
+
raceBlockContent = anyRaceBlockMatch[1];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (raceBlockContent) {
|
|
166
|
+
// Extract all locator calls from the race block
|
|
167
|
+
// Handle both single and double quotes, and handle escaped quotes
|
|
168
|
+
// Improved regex to handle complex selectors with parentheses and special characters
|
|
169
|
+
const locatorPattern = /(?:targetPage|page)\.locator\((['"])((?:(?!\1)[^\\]|\\.)*)\1\)/g;
|
|
170
|
+
let locatorMatch;
|
|
171
|
+
while ((locatorMatch = locatorPattern.exec(raceBlockContent)) !== null) {
|
|
172
|
+
const selectorValue = locatorMatch[2].replace(/\\(.)/g, '$1'); // Unescape
|
|
173
|
+
if (selectorValue && typeof page.locator === 'function') {
|
|
174
|
+
locators.push(page.locator(selectorValue));
|
|
169
175
|
}
|
|
170
|
-
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (locators.length === 0) {
|
|
179
|
+
// Fallback: Parse CSS selectors (lines with targetPage.locator('...') or page.locator('...'))
|
|
180
|
+
const cssMatches = selector.match(/(?:targetPage|page)\.locator\(['"]([^'"]+)['"]\)/g);
|
|
181
|
+
if (cssMatches) {
|
|
182
|
+
cssMatches.forEach(match => {
|
|
183
|
+
const cssSel = match.match(/['"]([^'"]+)['"]/)?.[1];
|
|
184
|
+
if (cssSel && !cssSel.startsWith('::-p-xpath')) {
|
|
185
|
+
// Use page.locator if available, otherwise fallback
|
|
186
|
+
if (typeof page.locator === 'function') {
|
|
187
|
+
locators.push(page.locator(cssSel));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
// Parse XPath selectors (::-p-xpath(...))
|
|
193
|
+
const xpathMatches = selector.match(/::-p-xpath\(([^)]+)\)/g);
|
|
194
|
+
if (xpathMatches) {
|
|
195
|
+
xpathMatches.forEach(match => {
|
|
196
|
+
const xpath = match.match(/::-p-xpath\(([^)]+)\)/)?.[1];
|
|
197
|
+
if (xpath && typeof page.locator === 'function') {
|
|
198
|
+
locators.push(page.locator(`::-p-xpath(${xpath})`));
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
171
202
|
}
|
|
172
203
|
// Also check for >CSS> and >XPATH> prefixes
|
|
173
204
|
if (selector.includes('>CSS>') || selector.includes('>XPATH>')) {
|
|
@@ -213,11 +244,25 @@ class MoveAndClick {
|
|
|
213
244
|
if (waitForClick > 0) {
|
|
214
245
|
await page.waitForTimeout(waitForClick);
|
|
215
246
|
}
|
|
247
|
+
// Parse offset from code if present (handle multiline)
|
|
248
|
+
let offset;
|
|
249
|
+
// Match offset in click options, handling multiline and whitespace
|
|
250
|
+
const offsetMatch = selector.match(/\.click\s*\(\s*\{[\s\S]*?offset:\s*\{[\s\S]*?x:\s*(\d+)[\s\S]*?y:\s*(\d+)[\s\S]*?\}[\s\S]*?\}/);
|
|
251
|
+
if (offsetMatch && offsetMatch[1] && offsetMatch[2]) {
|
|
252
|
+
offset = {
|
|
253
|
+
x: parseInt(offsetMatch[1], 10),
|
|
254
|
+
y: parseInt(offsetMatch[2], 10),
|
|
255
|
+
};
|
|
256
|
+
}
|
|
216
257
|
// Click with options
|
|
217
258
|
const clickOptions = {
|
|
218
259
|
button: button,
|
|
219
260
|
clickCount: clickCount,
|
|
220
261
|
};
|
|
262
|
+
// Add offset if found in code
|
|
263
|
+
if (offset) {
|
|
264
|
+
clickOptions.offset = offset;
|
|
265
|
+
}
|
|
221
266
|
if (typeof locator.click === 'function') {
|
|
222
267
|
await locator.click(clickOptions);
|
|
223
268
|
}
|
|
@@ -227,19 +272,13 @@ class MoveAndClick {
|
|
|
227
272
|
}
|
|
228
273
|
else {
|
|
229
274
|
// Fallback to simple selector parsing
|
|
230
|
-
throw new Error('Could not parse
|
|
275
|
+
throw new Error('Could not parse Locator.race() from code. Please ensure your code contains a valid puppeteer.Locator.race([...]) pattern with targetPage.locator() or page.locator() calls.');
|
|
231
276
|
}
|
|
232
277
|
}
|
|
233
278
|
catch (error) {
|
|
234
|
-
// If code parsing fails,
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
await page.waitForTimeout(waitForClick);
|
|
238
|
-
}
|
|
239
|
-
await page.click(selector, {
|
|
240
|
-
button: button,
|
|
241
|
-
clickCount: clickCount,
|
|
242
|
-
});
|
|
279
|
+
// If code parsing fails, provide helpful error message
|
|
280
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
281
|
+
throw new Error(`Failed to parse Puppeteer Locator code: ${errorMessage}. Please check that your selector field contains a valid Locator.race() pattern or a simple CSS/XPath selector.`);
|
|
243
282
|
}
|
|
244
283
|
}
|
|
245
284
|
else {
|