All challenges · Foundations

Challenge 3 of 29 · Beginner-friendly · Foundations

Count Multiple Elements: Reuse One Locator

Repeat an action a set number of times with one locator you keep in a variable. The hidden check counts what your actions produced.

Skills you will practise

  • reusing a locator
  • repeated actions
  • role-based locators

The concept

Playwright locators are descriptions, not snapshots. When you write const tagInput = page.getByRole('textbox', { name: 'Tag' }), nothing is looked up yet. Each time you act on tagInput, Playwright finds the element fresh. That makes it safe to store a locator in a variable and use it again and again, even if the page re-renders between clicks.

This matters when a task says “do this three times” or when you need to check how many items exist. Reusing one well-named locator keeps the test readable and means there is only one place to fix if the UI changes.

To check how many things are on the page, use expect(locator).toHaveCount(n). It retries until the count matches, which avoids reading a number before the page has finished updating.

The fragile version

Fragile
for (let i = 0; i < 3; i++) {
  await page.locator('#app > div:nth-child(4) > button').click();
}
const n = await page.locator('li').count();
expect(n).toBe(3);

Why it breaks: The selector is tied to DOM position, and count() reads the number once with no retry, so it can run before the last item appears and fail intermittently.

A robust Playwright version

Robust
const tagInput = page.getByRole('textbox', { name: 'Tag' });
for (const tag of ['smoke', 'checkout', 'mobile']) {
  await tagInput.fill(tag);
  await tagInput.press('Tab');
}
await expect(page.getByRole('listitem')).toHaveCount(3);

One readable locator, reused for every action in the loop. The web-first toHaveCount assertion waits until the list reaches the expected size.

This is a general example on a made-up page, not the challenge’s reference solution.

Common mistakes

  • Using forEach with async callbacks, which does not wait for each click.
  • Asserting with count() plus toBe, which does not retry.
  • Counting too broadly, for example every li on the page including the navigation menu.

FAQ

Can I store a Playwright locator in a variable?

Yes. Locators are lazy and re-resolve on every action, so they are safe to reuse.

What is the difference between count() and toHaveCount()?

count() returns the number right now. toHaveCount() is an assertion that keeps retrying until it matches or times out.

Why does my loop not wait between clicks?

Array.forEach ignores returned Promises. Use a for or for...of loop with await.

Try it

Practise this in Challenge 3. You write the code in the browser editor with no setup. It runs in a fresh Chromium, a hidden validator checks what actually happened, and you get pass or fail, the logs and a video of the run. Challenges 1 to 10 are open without an account; create a free one any time to keep your progress. The reference solution and the hidden validator are shown only after you pass. We never publish solutions here.