The automation script for Playwright/Puppeteer is having trouble properly handling `async...await` in a `for..loop` on the `/signup` page

Currently, I am faced with the challenge of automating rate-limit requests using a playwright automation script.

The issue arises when the script keeps attempting to sign up with the email

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fe8a9b8d8acebe9b869f938e929bd09d9193">[email protected]</a>
, resulting in an error indicating that the email is already in use.

Despite my efforts to implement async...await correctly with the for...loop, it seems like something is not working as intended.

import { chromium } from 'playwright'

async function main() {
  const browser = await chromium.launch({ headless: false })

  const page = await browser.newPage()
  for (let i = 0; i < 20; i++) {
    await page.goto('http://localhost:3000/signup')
    await page.waitForLoadState('domcontentloaded')

    await page.fill('input[name="email"]', `test${i}@example.com`)
    await page.click('button[type="submit"]')

    await page.waitForURL('http://localhost:3000/verify-email')
    
    console.log(i)
  }

  await page.close()
  await browser.close()
}

main()

I also attempted the commented code section above, but it did not yield the desired results either.

When examining the response from my server script, it displays:

{ email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a2d6c7d1d692e2c7dac3cfd2cec78cc1cdcf">[email protected]</a>' }
{ user: [], unique: true }
{ email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8afeeff9febacaeff2ebe7fae6efa4e9e5e7">[email protected]</a>' }
{
  user: [
    {
      id: '01HNPK1GRM5ZHWXZBV1K2R3A9B',
      email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6f1b0a1c1b5f2f0a170e021f030a410c0002">[email protected]</a>',
      emailVerified: 0
    }
  ],
  unique: false
}

The server checks for unique emails, displaying unique: true initially but then strangely returns unique: false.

This is unexpected given the use of for...loop along with async...await.

The expected output should resemble:

{ email: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fe8a9b8d8acebe9b869f938e929bd09d9193">[email protected]</a>' }
{ user: [], unique: true }
{ email: '[email protected]' }
{ user: [], unique: true }

What could be going wrong in this scenario?

It's worth mentioning that similar issues were encountered while using Puppeteer as well:

import puppeteer from 'puppeteer'

async function main() {
  const browser = await puppeteer.launch({
    headless: false,
  })
  const page = await browser.newPage()

  for (let i = 0; i < 20; i++) {
    await page.goto('http://localhost:3000/signup')

    await page.type('input[name="email"]', `test${i}@example.com`)
    await page.click('button[type="submit"]')

    await page.waitForNavigation()

    console.log(i)
  }

  await page.close()
  await browser.close()
}

Furthermore, the technology stack involves the utilization of React Server Actions within Next.js 14 -> https://github.com/deadcoder0904/next-14-lucia-v3-sqlite-drizzle-conform-zod-email-verification-otp-server-actions/

Answer №1

If you want to push your promises to an array and execute them in parallel, you can do so by following this approach:

const promiseArr = []
for (let i = 0; i < 20; i++) {
    const page = await browser.newPage()
    promiseArr.push(page.goto('http://localhost:3000/signup'))
    promiseArr.push(page.type('input[name="email"]', `test${i}@example.com`))
    promiseArr.push(page.click('button[type="submit"]'))
    promiseArr.push(page.waitForNavigation())
}
// This will reject all promises if any of them rejects
await Promise.all(promiseArr);

The behavior of awaiting promises within a for loop is different than you might expect. Check out this thread for more details.

Update: The code snippet below offers a potentially better solution for executing promises in parallel using Promise.all:

const promiseArr = []
for (let i = 0; i < 20; i++) {
    const page = await browser.newPage()
    promiseArr.push(signUp(page, i));
}

// This will reject all promises if any one of them rejects
await Promise.all(promiseArr);

function signUp(page, i) {
    return new Promise(async (resolve, reject) => {
        await page.goto('http://localhost:3000/signup')
        await page.type('input[name="email"]', `test${i}@example.com`)
        await page.click('button[type="submit"]')
        await page.waitForNavigation()
        resolve();
    });
}

Answer №2

Below is the updated code snippet that tackles the mentioned issue:

javascript
Copy code
import { chromium } from 'playwright'

async function main() {
  const browser = await chromium.launch({ headless: false })

  const page = await browser.newPage()
  for (let i = 0; i < 20; i++) {
    (async (index) => {
      await page.goto('http://localhost:3000/signup')
      await page.waitForLoadState('domcontentloaded')

      await page.fill('input[name="email"]', `test${index}@example.com`)
      await page.click('button[type="submit"]')

      await page.waitForURL('http://localhost:3000/verify-email')
      // await page.waitForSelector('#verify-email-form', {
      //   state: 'visible',
      //   timeout: 0,
      // })

      console.log(index)
    })(i)
  }

  await page.close()
  await browser.close()
}

main()

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

troubles with dividing string

Recently delving into JavaScript/Angular development and encountering a little roadblock. I am attempting to break up a string of a textarea into an array at the \n character within a controller by utilizing $scope.mytext.split("\n"), however, I ...

What is the best way to tidy up a function within a useEffect hook?

When updating state within a useEffect hook while using async/await syntax, I encountered an error regarding the cleanup function. I'm unsure how to properly utilize the cleanup function in this scenario. Error: Warning - A React state update was att ...

Automate Zoom join function with the help of puppeteer

Having trouble joining a Zoom meeting using Puppeteer, my code is not capturing the password field. Can anyone assist? Here is my code snippet: const puppeteer = require("puppeteer-extra"); const StealthPlugin = require("puppeteer-extra-plu ...

javascript: window.open()

I am currently using VB.NET 2005 and I have a requirement to launch a new browser window using Process.Start(). The challenge is that I need to specify the size of the browser window, for example, height:300 and width:500. Process.Start("firefox.exe", "ab ...

Exploring Angular 8 Route Paths

Working on an Angular 8 project, I encountered an issue with my code: src/app/helpers/auth.guard.ts import { AuthenticationService } from '@app/services'; The AuthenticationService ts file is located at: src/app/services/authentication.servic ...

Explore RxJs DistinctUntilChanged for Deep Object Comparison

I have a scenario where I need to avoid redundant computations if the subscription emits the same object. this.stateObject$ .pipe(distinctUntilChanged((obj1, obj2) => JSON.stringify({ obj: obj1 }) === JSON.stringify({ obj: obj2 }))) .subscribe(obj =& ...

SWR Fails to Recognize Environment Variables

I'm struggling to utilize ENV variables when using the SWR hook for data fetching. My current approach is as follows: const videoURLWithEnv = `https://youtube.googleapis.com/youtube/v3/search?part=snippet&channelId=UCwkj9jcrMZCcbcIa6nF5LNQ&ma ...

Changing the background color of a page to match the background color of a button in React, which can be updated at any time

I have a special button called ArbitraryBtn that, when clicked, changes the page's background color to random colors: import React from 'react'; export const changeToArbitraryColor = () => (document.body.style.backgroundColor = ...

`npm run build` in Ubuntu does not detect any environment variables in process.env

Currently in the process of deploying a VueJS project. I have a file that contains API URLs where process.env is used. In production, if API_URL is defined, I can use localhost on my development server and switch to API_URL in production. const apiRoot = p ...

How can I create a top right profile button similar to Google using AngularJS?

I am looking to implement a floating button in the top right corner of my main screen. When clicked, I want it to open a card below with an arrow pointing towards the button similar to the one on . I am currently using Angular Material and have tried using ...

Tips for isolating all the Javascript loaded via ajax or jquery.load within a specific child scope instead of a global scope

I am currently working on a solution to embed a third-party page into my site using ajax/jquery.load() to avoid using iframes (CORS requirements are already handled by the third party). My dilemma lies in the fact that the main host site loads jquery 1.x ...

Can you explain the concept of "inlining" as it pertains to the "env" document in Next.js?

I am exploring the 'env' concept in a static build file within Next.js, and I am curious about the meaning of "inlining" in this context. Can someone provide a more specific example? When process.env.NEXT_PUBLIC_ANALYTICS_ID is loaded into the ...

What is the best way to incorporate NextJS routes in React while utilizing a form?

This is the main code section for my app const App = () => { const classes = useStyles(); const formik = useFormik({ initialValues: { name: "", email: "", password: "", confirmPassword: "" }, validationSc ...

How can you effectively utilize Selenium to web scrape a webpage featuring collapsible fields?

Have you checked out this website - ? I'm currently working on extracting fixture data from it, such as competition names, team names, and dates. Although I have a scraping solution in place, the challenge lies in dealing with collapsible competition ...

Tips on adjusting the label on a datetime-local button

While using mobile browsers, I noticed that the datetime local feature includes three buttons. One of these buttons is called the Set button, but I would like to change its name to Ok. Is there a way to do this? I tried looking for solutions but couldn&apo ...

What can be done to enhance this particular element?

I've created a Component that uses a 3rd party joke API to fetch jokes with a specific category upon page load. The component also includes a refresh button for fetching new jokes. export default function Jokes() { const { cat } = useParams(); const [ ...

Notify user before exiting the page if there is an unsaved form using TypeScript

I am working on a script that handles unsaved text inputs. Here is the code for the script: export class Unsave { public static unsave_check(): void { let unsaved = false; $(":input").change(function(){ unsaved = true; ...

Navigating Parent Menus While Submenus are Expanded in React Using Material-UI

My React application includes a dynamic menu component created with Material-UI (@mui) that supports nested menus and submenus. I'm aiming to achieve a specific behavior where users can access other menus (such as parent menus) while keeping a submenu ...

Changing the color of a progress bar in Bootstrap based on a specific percentage level

var elem = document.getElementById("progress-bar"); var progress = 75; elem.style.width = 80 + '%'; if (progress > 80) { elem.style.background = "red"; } #myProgress { height: 5px; } #progress-bar { w ...

Adjust the flexslider to transition to a new slide when hovering over the thumbnails

I have a flexslider with thumbnails like this ; https://i.stack.imgur.com/9bfC2.jpg I am looking to change the slide when the user hovers over the thumbnails. How can I achieve this functionality? Here is the jQuery code I am currently using to set up th ...