playwright icon indicating copy to clipboard operation
playwright copied to clipboard

[Feature] Add possibility of creating Locators with variables

Open MikeShysh opened this issue 3 years ago • 3 comments

Hi, it would be more convenient to create Locators with the possibility of specifying variable values exactly before executing some actions. For example I have two elements on the page:

await this.page.click('.header-actions [helptag="apply-filters"]:not(.mat-button-disabled)');

As we can see, only helptag differs. With the current implementation of Locators I need to create 2 locator elements or make my own functions to generate raw string selector and pass it to locator. I propose creating out-of-the box implementation in Locators for such functionality. Maybe something like this:

headerActionBtns = this.page.locator('.header-actions [helptag="${btnName}"]:not(.mat-button-disabled)', btnName)
headerActionBtns.click({btnName: 'default-filters'});
or
headerActionBtns.with({btnName: 'default-filters'}).click(); 

Please consider. Thank you

MikeShysh avatar Jan 13 '22 16:01 MikeShysh

@MikeShysh This proposal does not seem like a clear improvement so far. Perhaps there are more usecases or possible APIs that would work better?

// proposed
headerActionBtns = this.page.locator('.header-actions [helptag="${btnName}"]:not(.mat-button-disabled)', btnName)

// works today - note `...` backticks
headerActionBtns = this.page.locator(`.header-actions [helptag="${btnName}"]:not(.mat-button-disabled)`)

dgozman avatar Jan 13 '22 18:01 dgozman

@dgozman // works today - note ... backticks headerActionBtns = this.page.locator(.header-actions [helptag="${btnName}"]:not(.mat-button-disabled))

Yes, I use this now in some cases, but it requires duplication of selectors' text and specifying exactly before action. My idea was to allow modifying already created Locator's _selector by passing variable before executing.

// proposed headerActionBtns = this.page.locator('.header-actions [helptag="${btnName}"]:not(.mat-button-disabled)', btnName) It's not what I mean) Its really does not bring benefit.

I want to pass Locator objects between classes instances and have a possibility to substitute variables. Something like https://nodejs.org/api/util.html#utilformatformat-args in native Locators implementation. Of course, I could achieve what I need if I handle selectors like raw strings, create my own helper functions etc, but it would be better as native implementation in Locators. Maybe it sounds a bit over the top, but please consider

One more example

    async setTopUpAmount(idx: number, value: string): Promise<void> {
        await this.page.fill(`:nth-match(pb-dynamic-list > div, ${idx}) >> [helptag="topup-amount"] input`, value);
    }

    async clickTopUpAmount(idx: number): Promise<void> {
        await this.page.click(`:nth-match(pb-dynamic-list > div, ${idx}) >> [helptag="topup-amount"]`);
    }

    async setTopUpFee(idx: number, value: string): Promise<void> {
        await this.page.fill(`:nth-match(pb-dynamic-list > div, ${idx}) >> [helptag="topup-fee"] input`, value);
    }

    async clickTopUpFee(idx: number): Promise<void> {
        await this.page.click(`:nth-match(pb-dynamic-list > div, ${idx}) >> [helptag="topup-fee"]`);
    }

I want to simplify it

MikeShysh avatar Jan 14 '22 08:01 MikeShysh

+1 for this. I ran into many situation where multiple locators are pretty much the same, except for their text. So it would be great to use the same locator for all those elements and just have a variable for the text value.

DanielStoica85 avatar Aug 08 '22 09:08 DanielStoica85

+1, adding this feature will be appreciated.

woytekn avatar Oct 11 '22 08:10 woytekn

+1, this feature will be awesome for the community.

andersoncorbellini avatar Oct 17 '22 22:10 andersoncorbellini

+1, looking forward to have this feature :)

mahmutkaya avatar Jan 30 '23 07:01 mahmutkaya

If I’m understanding the problem/desire correctly, it seems this could actually be handled comparably by making the locator variable a function returning the locator instead. Using the proposal:

// proposed
headerActionBtns = this.page.locator('.header-actions [helptag="${btnName}"]:not(.mat-button-disabled)', btnName)
headerActionBtns.click({btnName: 'default-filters'});
or
headerActionBtns.with({btnName: 'default-filters'}).click(); 

// Using a function
headerActionBtns = ({ btnName }) => this.page.locator(`.header-actions [helptag="${btnName}"]:not(.mat-button-disabled)`);
headerActionBtns({btnName: 'default-filters'}).click(); 

This takes advantage of native javascript rather than needing to add something to Playwright, and seems to do and feel about the same as proposed.

It could be similarly applied to the last example too, having the helptag value be passed in, and then potentially chaining the input to fill as needed. It seems it uses typescript too, in which case you could even provide options as the type (‘topup-amount’ | ‘topup-fee’).

I am also an advocate for simplifying, and believe that should do it as desired. Hope that helps someone, and definitely curious if it doesn’t work for anyone.

davidrosevear avatar Feb 08 '23 10:02 davidrosevear

Why was this issue closed?

Thank you for your involvement. This issue was closed due to limited engagement (upvotes/activity), lack of recent activity, and insufficient actionability. To maintain a manageable database, we prioritize issues based on these factors.

If you disagree with this closure, please open a new issue and reference this one. More support or clarity on its necessity may prompt a review. Your understanding and cooperation are appreciated.

pavelfeldman avatar Nov 16 '23 04:11 pavelfeldman