2

I have a set of files in a folder with specific names and I use node to return me the names of those files and then for each file I want to run a puppeteer test which fills the form and submits it but I seem to be having issues with the forEach not waiting for the previous test to finish and end up with loads of Execution context was destroyed which obviously prevent my tests from finishing. I ended up with users logged in but the page the page.type is not run in some of the cases...

How do I wait for the puppeteer to complete the test and then run the next element in forEach?

See code below:

fs.readdir(testFolder, async (err, files) => {
  files.forEach(file => {
(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  page.setViewport({
    width: 1920,
    height: 1080
  });
  await page.goto('www.mypage.com');
  //login
  // some login code here
  await page.click('#register')
  await page.waitForNavigation();
  console.log('New Page URL:', page.url());

  await page.waitForSelector('#firstName');
  await page.waitFor(1000);

  await page.type('#firstName', file);
  // register and wait for nagivation (in my case it is a page reload)
  await page.waitForSelector('#updateProfile');
  await page.click('#updateProfile');
  await page.waitForNavigation();
  await browser.close();
})();
});

});

Mac_W
  • 2,927
  • 6
  • 17
  • 30

1 Answers1

2

It is a tricky one to use Array.forEach with async/await as all the iteratees will be executed, but forEach is going to return before all of them finish execution, which is not the desirable behavior in many cases with async functions.

See a benchmarking of puppeteer clicks in map vs. forEach vs. for...of here, which gives a picture what happens.


Solutions

I.) As you are iterating the main puppeteer script I'd solve it either by refactoring the forEach to a for...of loop, it results in a bit worse performance as execution happens in strict order and not in parallel, but it is still in align with your expectation:

wait for the puppeteer to complete the test and then run the next element

II.) or you could create your own "async forEach" method.

For example:

async function asyncForEach(array, callback) {
  for (let index = 0; index < array.length; index++) {
    await callback(array[index], index, array)
  }
}

source of asyncForEach method: Sebastien Chopin: JavaScript: async/await with forEach() (codeburst.io)

theDavidBarton
  • 7,643
  • 4
  • 24
  • 51