Skip to content

[Feature] extend Locator API with helper methods #16785

Closed

Description

@gajus

As an example, I would like to introduce findByRole method that is equivalent to:

page.locator(
  `role=${role}[name="${name}"]`
)

I have figured out how to add this to Page object,

#1604 (comment)

This allows me to write code like:

await page.findByRole('link', 'Services').click();

However, this breaks when chaining Locator instances, e.g.

await page
  .locator('role=dialog')
-  .locator('role=link[name="Create A Service"]')
+  .findByRole('link', 'Create A Service')
  .click();

The above is throwing an error since .locator('role=dialog') is returning an instance of a Locator that is not aware of findByRole.

Activity

  1. yury-s commented on Aug 23, 2022

    @yury-s
    Member

    Gajus Kuizinas (@gajus) do you have a particular API in mind that Playwright could expose to support such extensibility?

    You can already wrap a locator in another object with the extended interface similar to how you did with the page (you'd need to override Page.locator to return a wrapper instead of the original locator). You'd also need to proxy all locator methods and also ensure that the methods that return a new instance of Locator also return wrapped objects. It will not work with the playwright API methods that accept Locator as argument (e..g. has option) so they'd have to be unwrapped before being passed into the method.

    Related issue #13517

  2. gajus commented on Aug 24, 2022

    @gajus
    Author

    Is there a reason we could not use the same pattern that we use for fixtures?

    export const test = base.extend({
      locator: async ({ page }, use) => {
        use(new Proxy(page.locator, {}))
      }
    });

    Internals would need to be rewritten to use refer to locator that comes from test.

  3. yury-s commented on Aug 24, 2022

    @yury-s
    Member

    Is there a reason we could not use the same pattern that we use for fixtures?
    Internals would need to be rewritten to use refer to locator that comes from test.

    The fixtures are a part of the test runner, the library doesn't know about them, so it would have to be implemented in the fixtures land which makes it essentially the same as what I described above (basically adding proxies to all affected objects).

  4. gajus commented on Aug 24, 2022

    @gajus
    Author

    I would consider moving expect function away from something we import at the top level to something that is initialized per test, i.e.

    import {
    -  expect,
      test,
    } from '@playwright/test';
    
    -test('foo', async ({ page }) => {});
    +test('foo', async ({ expect, page }) => {});

    This would give a lot more control over expect.

  5. mrmckeb commented on Aug 26, 2022

    @mrmckeb

    I came here to ask the same thing, as we tried creating a custom fixture with a method that wrapped locator, but that makes debugging a little messy - especially with the VSCode extension, as it points to the locator, not the line.

    Perhaps a simpler approach would be to allow users to register locator middleware, similar to custom selectors.

    page.locator({ role: 'link', 'name: 'XYZ' });

    In our case, we have a custom function to build test IDs, so it might look something like this:

    page.locator({ testId: ['x', 'y'] });

    But I also like the idea of named functions, like getByTestId or getByRole... and I think I'd prefer that if both were of equal cost.

  6. pavelfeldman commented on Nov 5, 2022

    @pavelfeldman
    Member

    Closing since we've introduced typed locators like getByRole.

  7. marc-guenther commented on Mar 10, 2025

    @marc-guenther

    Why was this closed? The feature request was not about adding getByRole(), but about having a way to extend the Locator API.

    I stumbled upon this, because we are just evaluating migration from Cypress, and in Cypress you can define your own actions. Seems in Playwright, you can't.

  8. DesselBane commented on Oct 21, 2025

    @DesselBane
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions