n8n-nodes-nvk-browser 1.0.7 → 1.0.8
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.
|
@@ -148,9 +148,12 @@ class MoveAndClick {
|
|
|
148
148
|
try {
|
|
149
149
|
const actionBlocks = [];
|
|
150
150
|
// Find all click blocks
|
|
151
|
-
|
|
151
|
+
// Improved regex to handle closing braces - semicolon is optional (for last block)
|
|
152
|
+
const clickBlockPattern = /puppeteer\.Locator\.race\s*\(\s*\[([\s\S]*?)\]\s*\)[\s\S]*?\.click\s*\(([\s\S]*?)\)(?:\s*;|\s*$)/g;
|
|
152
153
|
let clickMatch;
|
|
153
154
|
let clickIndex = 0;
|
|
155
|
+
// Reset regex lastIndex to ensure we find all matches
|
|
156
|
+
clickBlockPattern.lastIndex = 0;
|
|
154
157
|
while ((clickMatch = clickBlockPattern.exec(selector)) !== null) {
|
|
155
158
|
const raceBlockContent = clickMatch[1];
|
|
156
159
|
const clickOptionsContent = clickMatch[2] || '';
|
|
@@ -183,9 +186,12 @@ class MoveAndClick {
|
|
|
183
186
|
}
|
|
184
187
|
}
|
|
185
188
|
// Find all fill blocks
|
|
186
|
-
|
|
189
|
+
// Improved regex to handle closing braces - semicolon is optional (for last block)
|
|
190
|
+
const fillBlockPattern = /puppeteer\.Locator\.race\s*\(\s*\[([\s\S]*?)\]\s*\)[\s\S]*?\.fill\s*\(\s*['"]([^'"]*(?:\\.[^'"]*)*)['"]\s*\)(?:\s*;|\s*$)/g;
|
|
187
191
|
let fillMatch;
|
|
188
192
|
let fillIndex = 0;
|
|
193
|
+
// Reset regex lastIndex to ensure we find all matches
|
|
194
|
+
fillBlockPattern.lastIndex = 0;
|
|
189
195
|
while ((fillMatch = fillBlockPattern.exec(selector)) !== null) {
|
|
190
196
|
const raceBlockContent = fillMatch[1];
|
|
191
197
|
const fillTextValue = fillMatch[2].replace(/\\(.)/g, '$1'); // Unescape
|
|
@@ -215,7 +221,8 @@ class MoveAndClick {
|
|
|
215
221
|
if (actionBlocks.length === 0) {
|
|
216
222
|
throw new Error('No valid Locator.race() blocks found in code. Please ensure your code contains puppeteer.Locator.race([...]).click() or .fill() patterns.');
|
|
217
223
|
}
|
|
218
|
-
for (
|
|
224
|
+
for (let blockIndex = 0; blockIndex < actionBlocks.length; blockIndex++) {
|
|
225
|
+
const block = actionBlocks[blockIndex];
|
|
219
226
|
try {
|
|
220
227
|
// Create locator from block's locators
|
|
221
228
|
let locator;
|
|
@@ -240,10 +247,28 @@ class MoveAndClick {
|
|
|
240
247
|
locator = locator.setTimeout(timeout);
|
|
241
248
|
}
|
|
242
249
|
}
|
|
250
|
+
// Wait for element to be visible/actionable before executing
|
|
251
|
+
// Try to wait for the locator to be ready
|
|
252
|
+
try {
|
|
253
|
+
if (typeof locator.wait === 'function') {
|
|
254
|
+
await locator.wait({ timeout: timeout });
|
|
255
|
+
}
|
|
256
|
+
else if (typeof page.waitForSelector === 'function') {
|
|
257
|
+
// Fallback: try to wait using first locator's selector if available
|
|
258
|
+
// This is a best-effort approach
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (waitError) {
|
|
262
|
+
// Continue even if wait fails - element might already be ready
|
|
263
|
+
}
|
|
243
264
|
// Wait before action if specified
|
|
244
265
|
if (waitForClick > 0) {
|
|
245
266
|
await page.waitForTimeout(waitForClick);
|
|
246
267
|
}
|
|
268
|
+
// Add small delay between actions to ensure page state is stable
|
|
269
|
+
if (blockIndex > 0) {
|
|
270
|
+
await page.waitForTimeout(100); // Small delay between actions
|
|
271
|
+
}
|
|
247
272
|
// Execute action
|
|
248
273
|
if (block.type === 'fill' && block.fillText) {
|
|
249
274
|
if (typeof locator.fill === 'function') {
|
|
@@ -269,11 +294,23 @@ class MoveAndClick {
|
|
|
269
294
|
clickOptions.offset = block.offset;
|
|
270
295
|
}
|
|
271
296
|
if (typeof locator.click === 'function') {
|
|
297
|
+
// Ensure element is actionable before clicking
|
|
298
|
+
try {
|
|
299
|
+
// Try to scroll into view if needed
|
|
300
|
+
if (typeof locator.scrollIntoViewIfNeeded === 'function') {
|
|
301
|
+
await locator.scrollIntoViewIfNeeded();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
catch (scrollError) {
|
|
305
|
+
// Continue even if scroll fails
|
|
306
|
+
}
|
|
272
307
|
await locator.click(clickOptions);
|
|
308
|
+
// Wait a bit after click to ensure action is processed
|
|
309
|
+
await page.waitForTimeout(50);
|
|
273
310
|
executedActionsInfo.push({
|
|
274
311
|
type: 'click',
|
|
275
312
|
success: true,
|
|
276
|
-
message:
|
|
313
|
+
message: `Click performed successfully (block ${blockIndex + 1}/${actionBlocks.length})`,
|
|
277
314
|
});
|
|
278
315
|
actionType = 'click';
|
|
279
316
|
}
|
|
@@ -283,10 +320,11 @@ class MoveAndClick {
|
|
|
283
320
|
}
|
|
284
321
|
}
|
|
285
322
|
catch (blockError) {
|
|
323
|
+
const errorMessage = blockError instanceof Error ? blockError.message : String(blockError);
|
|
286
324
|
executedActionsInfo.push({
|
|
287
325
|
type: block.type,
|
|
288
326
|
success: false,
|
|
289
|
-
message:
|
|
327
|
+
message: `Block ${blockIndex + 1}/${actionBlocks.length} failed: ${errorMessage}`,
|
|
290
328
|
});
|
|
291
329
|
// Continue with next block even if one fails
|
|
292
330
|
}
|