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?
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.