9

I need some help to make conditional statements using Playwright tests.
I have a given selector, let's say a button, and I need to write a conditional statement like this:

if (selector is not present/visible)

    do nothing and proceed with the *next lines of code*

else  

    await page.click(*selector*)

*next lines of code*

Is there any efficient way to do these kinds of things? I didn't found anything in the Playwright documentation.

theDavidBarton
  • 7,643
  • 4
  • 24
  • 51
Ciccios_1518
  • 435
  • 1
  • 6
  • 13

4 Answers4

7

I. using Element Handles within the condition

It can be implemented in JavaScript similarly to your pseudo-code using page.$(selector), which returns null if the specified element is not in the DOM. (Note: watch for the right usage of parenthesis inside the condition!)

I'd also reverse your initial if(falsy)...else condition into a single if(truthy), as you want to execute a command only if the selector exists, the else branch doesn't make too much sense:

if ((await page.$('#elem-id')) !== null) {
  await page.click('#elem-id')
}
// code goes on with *next lines of code*

II. using Locators within the condition

Some may notice the warning in the docs "The use of ElementHandle is discouraged, use Locator objects and web-first assertions instead." By default you shouldn't worry about using ElementHandles or mixing them together with Playwright's Locators in e2e tests or scrapers, they are inherited from Puppeteer and act reliably in Playwright as well (if they wouldn't: Microsoft would have deprecated them). Microsoft promotes Locators over Element Handles only because most of the extra functionalities they invested in in the past years (like "getByAltText", "getByLabel" etc.) are built on top of Locators so you can write e2e tests easier with their help. That's the reason for the warning in the docs. You don't need to avoid Element Handles at every cost.

If you want to reuse a locator in a conditional statement you can use locator.isVisible().

const myElement = page.locator('#elem-id') 
if (await myElement.isVisible()) {
  await myElement.click()
}
// code goes on with *next lines of code*
Jaeeun Lee
  • 3,056
  • 11
  • 40
  • 60
theDavidBarton
  • 7,643
  • 4
  • 24
  • 51
  • I've spent some time trying to figure a way to do this using Locators...so far nothing. Would love it if someone found a (simple) solution using Locators. – Andrew Dec 07 '22 at 17:09
  • @Andrew do you have any specific reason to use locator over elmentHandle other than that some are [against elementHandles](https://stackoverflow.com/a/72310047/12412595)? for me using any Plawright locator in the condition seems no beneficial (for user-like interactions: yes, they will be better). of course, it can depend on the use case, but the above solution is safe and clean by default. – theDavidBarton Dec 09 '22 at 11:24
  • I don't really disagree, @theDavidBarton; the main reasons I have to use Locator are simply 1) it's recommended by Playwright itself 2) I use Locator elsewhere, as it allows for more semantic queries (`getByRole`), so using element handles here means I have to make an exception, or use locator AND element handle for the same element in different places. So no big reason; but on the other hand, it seems like functionality that *should* be availabe via Locators, so if it is, I'd love to know about it, so I can do what this does, but have slightly cleaner, more consistent code. That's all. :) – Andrew Dec 09 '22 at 15:28
  • 1
    clear. I extended my answer above, you might find it useful. – theDavidBarton Dec 09 '22 at 18:53
1

Despite Playwright's recommendation around using Locators, if

if ((await page.$('#elem-id')) !== null) {
  await page.click('#elem-id')
}
// code goes on with *next lines of code*

Does the job fine, would this solution be ok to use?

brutus_ar
  • 26
  • 4
  • 3
    It looks like this answer is a copy and paste of the much earlier answer from @theDavidBarton. How is this any different? His should probably be the accepted answer. That said, welcome to SO. It is good to see new contributors. – davidethell Jun 24 '22 at 16:55
  • I agree. If the first code snippet is fine and there is no conflict with Playwright's recommendation then the accepted answer should be indeed @theDavidBarton one – brutus_ar Jun 25 '22 at 17:08
0

Since Playwright recommends using Locators over EventHandles (citation), you could also use:

async function clickIfNotNull(page, selector){
    const yourLocator = await page.locator(selector)
    const elementIsNotNull = await yourLocator.evaluate(elem => elem !== null);
    if (elementIsNotNull) {
        await yourLocator.click()
    }
}
Graffhyrum
  • 21
  • 2
0

I would like to share another solution that a colleague who is mentoring me created that also worked perfectly fine and might be even simpler than the previous answers.

    if (await page.isVisible('#element-id'))
{
   await page.click('#element-id');
}

When testing this in Playwright it works as well as other statements detailed before. There is a change to add an else with no problem as well.

brutus_ar
  • 26
  • 4
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 30 '22 at 11:09