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
- const clickBlockPattern = /puppeteer\.Locator\.race\s*\(\s*\[([\s\S]*?)\]\s*\)[\s\S]*?\.click\s*\(([\s\S]*?)\)/g;
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
- const fillBlockPattern = /puppeteer\.Locator\.race\s*\(\s*\[([\s\S]*?)\]\s*\)[\s\S]*?\.fill\s*\(\s*['"]([^'"]*(?:\\.[^'"]*)*)['"]\s*\)/g;
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 (const block of actionBlocks) {
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: 'Click performed successfully',
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: blockError instanceof Error ? blockError.message : String(blockError),
327
+ message: `Block ${blockIndex + 1}/${actionBlocks.length} failed: ${errorMessage}`,
290
328
  });
291
329
  // Continue with next block even if one fails
292
330
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-nvk-browser",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "n8n nodes for managing Chrome browser profiles and page interactions",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",