I have a form with many elements of the following pattern (ng-star-inserted
et al. removed):
<ui-input label="First Name">
<div>First Name</div>
<div>
<input type="text" placeholder="" autocomplete="off">
</div>
</ui-input>
I would like Playwright to type text into the corresponding box on the form. As I understand it, the Playwright school of thought is to find the inner <input>
element and await input.fill("Humbleton")
.
I’ve tried:
page.getByRole('textbox', { name: 'First Name' });
page.getByText('First Name').locator('input');
page.getByLabel('First Name').locator('input');
page.getByText('First Name').getByRole('textbox');
page.getByLabel('First Name').getByRole('textbox');
of which none work.
The go-to workaround is to insert a secret, unique-value attribute into the HTML and use the resulting unique XPath. However, I consider this to be cheating and against the spirit of e2e testing, clean code, propriety, and Playwright’s philosophy. Is there a Playwrightesque solution?
Finally I used page.keyboard
to fill out the form using page.keyboard.press('Tab')
to navigate from one field to another, but I have a hunch that this is not as robust and user-oriented as can be.
I feel there must be some overlooked elegant, expressive way to tell Playwright to just fill out the damn ‘First Name’ box.
2
Answers
Try using
page.locator('//ui-input[@label="First Name"]/descendant::input')
as
page.getByLabel('First Name').getByRole('textbox');
is not working.If this is also not working, Can you check if there is no
iframe
at the top level of this form?For your
getByLabel
to work, you’d need to usearia-label
:Other of your locators don’t work because the
input
isn’t actually a child of the<div>First Name</div>
element, which is what.getByText
would return.Also, your
<div>First Name</div>
doesn’t appear to be acting as a clickable label. I’d expect modern, accessible HTML to be something more along the lines of:If you can make your markup more like this, selection becomes straightforward.
But assuming it’s out of your control, you can use CSS selectors to find the input by the
label
attribute, or use.filter()
to select aui-input
with particular text.Note that these may not work or even be best practice, depending on your full HTML context, which wasn’t shown.
And yeah, don’t use XPath under almost any circumstances.