Nested loops with async/await in Puppeteer for cascading dropdown automation

I’m working on automating a website that has cascading dropdown menus where each dropdown depends on the previous selection. I have three dropdowns with different option counts.

const optionCounts = {
  categoryCount: 32,
  deliveryCount: 2, 
  amountCount: 30
};

I need to iterate through all combinations: first select category option 1, then delivery option 1, then loop through all 30 amount options. Here’s my approach:

for (let category = 1; category <= optionCounts.categoryCount; category++) {
  await page.evaluate((idx) => {
    document.querySelector(`#category > option:nth-child(${idx})`).selected = true;
  }, category);

  for (let delivery = 1; delivery <= optionCounts.deliveryCount; delivery++) {
    await page.evaluate((idx) => {
      document.querySelector(`#delivery > option:nth-child(${idx})`).selected = true;
    }, delivery);

    for (let amount = 1; amount <= optionCounts.amountCount; amount++) {
      await page.evaluate((idx) => {
        document.querySelector(`#amount > option:nth-child(${idx})`).selected = true;
      }, amount);
      
      console.log('Processing amount option');
    }
  }
}

I keep getting “await is only valid in async function” errors. How can I properly handle async operations in nested loops with Puppeteer?

That async/await error means your code isn’t wrapped in an async function, but there’s a bigger problem. Using page.evaluate() to set selected = true won’t trigger the change events that cascading dropdowns need. I’ve run into this exact issue before - page.select() works way better here because it actually fires the DOM events. Replace your evaluate calls with await page.select('#category', value) where value is the option value, not the nth-child index. Also throw in some delays between selections. Cascading menus usually need time to fetch new options via AJAX, so without proper event triggering, your nested dropdowns won’t update their options.

your main function needs to be async. you’r running this code outside an async function. either wrap it in (async () => { /* your code here */ })(); or put it inside an async function. also, you might need to trigger change events after setting selected=true - otherwise the dropdowns won’t actually update.

You’re right about needing the async wrapper. But add proper wait conditions between dropdown selections - that’s crucial here. Cascading dropdowns load options dynamically, so you’ve got to wait for the DOM to update before moving to the next selection. Use page.waitForSelector() or page.waitForFunction() after each dropdown change. Something like await page.waitForFunction(() => document.querySelectorAll('#delivery option').length > 1) after selecting the category. Without this, you’ll try selecting options that don’t exist yet, especially in those inner loops where available options change based on what you picked earlier.