Search code examples
typescriptplaywrightplaywright-typescript

playwright page.getByLabel() resolved to 2 elements


I am learning playwright and i find page.getByLabel is very usefulm but i try to find input elements i think finds the same twice.

> test('Fill Contact details and verify should success', async ({ page }) => {
          await page.goto('https://practice.automationbro.com/contact/')
          
          const inputName = page.getByLabel('Name')
          const inputEmail = page.getByLabel('Email')
          const inputPhone = page.getByLabel('Phone')
          const inputMessage = page.getByLabel('Message')
          const buttonSubmit = page.getByRole('button', {name : 'Submit'})

          await inputName.scrollIntoViewIfNeeded()
          await inputName.fill('Name')

          await inputEmail.scrollIntoViewIfNeeded()
          await inputEmail.fill('[email protected]')

          await inputPhone.scrollIntoViewIfNeeded();
          await inputPhone.fill('+36123456789')    
          
          await inputMessage.scrollIntoViewIfNeeded()
          await inputMessage.fill('Lorem Ipsum')
          
          await buttonSubmit.click()

          await expect(page.getByText('Thanks for contacting us! We will be in touch with you shortly')).toBeVisible();
     }) 

When i run it fails with :

1) [chromium] › automationbro.spec.ts:75:10 › Home › Fill Contact details and verify should success 

    locator.scrollIntoViewIfNeeded: Error: strict mode violation: getByLabel('Message') resolved to 2 elements:
        1) <textarea class="input-text" id="evf-277-field_yhGx3FOwr2-…></textarea> aka getByRole('textbox', { name: 'Message' })
        2) <input type="text" class="input-text" id="evf-277-field…/> aka locator('#evf-277-field-hp')

    =========================== logs ===========================
    waiting for getByLabel('Message')
    ============================================================

      91 |           await inputPhone.fill('+36123456789')    
      92 |           
    > 93 |           await inputMessage.scrollIntoViewIfNeeded()
         |                              ^
      94 |           await inputMessage.fill('Lorem Ipsum')
      95 |           
      96 |           await buttonSubmit.click()

Page has only one input element with that label. Why did it find 2 elements?


Solution

  • It looks like the labels are linked to hidden as well as visible input fields. One way to disambiguate is with getByRole:

    import {expect, test} from "@playwright/test"; // ^1.30.0
    
    test("fill contact details and verify", async ({page}) => {
      await page.goto("https://practice.automationbro.com/contact/");
    
      const inputName = page.getByRole("textbox", {name: "Name"});
      const inputEmail = page.getByRole("textbox", {name: "Email"});
      const inputPhone = page.getByRole("textbox", {name: "Phone"});
      const inputMessage = page.getByRole("textbox", {name: "Message"});
      const buttonSubmit = page.getByRole("button", {name: "Submit"});
    
      await inputName.scrollIntoViewIfNeeded();
      await inputName.fill("Name");
    
      await inputEmail.scrollIntoViewIfNeeded();
      await inputEmail.fill("[email protected]");
    
      await inputPhone.scrollIntoViewIfNeeded();
      await inputPhone.fill("+36123456789");
    
      await inputMessage.scrollIntoViewIfNeeded();
      await inputMessage.fill("Lorem Ipsum");
    
      await buttonSubmit.click();
    
      await expect(
        page.getByText(
          "Thanks for contacting us! We will be in touch with you shortly"
        )
      ).toBeVisible();
    });
    

    That said, I don't think you need to scrollIntoViewIfNeeded(). I'd remove the variables and use something like

    import {expect, test} from "@playwright/test";
    
    test("fill contact details and verify", async ({page}) => {
      await page.goto("https://practice.automationbro.com/contact/");
      await page.getByRole("textbox", {name: "Name"}).fill("Name");
      await page.getByRole("textbox", {name: "Email"}).fill("[email protected]");
      await page.getByRole("textbox", {name: "Phone"}).fill("+36123456789");
      await page.getByRole("textbox", {name: "Message"}).fill("Lorem Ipsum");
      await page.getByRole("button", {name: "Submit"}).click();
      await expect(
        page.getByText(
          "Thanks for contacting us! We will be in touch with you shortly"
        )
      ).toBeVisible();
    });
    

    Which could be factored into a POM in a larger test suite.


    Note that https://practice.automationbro.com/contact/ has disappeared since the time of writing, so the code is no longer runnable. There's a snapshot on the Wayback Machine but I left my original code as-is, so it may not align with the snapshot version.