How to wait for element that not always appears?

Hi all,

I’m trying to automate the login to a website. The code works to enter user and password and click on submit, then enters without issue to main page. The issue comes when after click on submit button, appears an error. This error is shown in the same login window, but in a new element that shows only when login has some issue.

I like to continue the script if login is correct and if the new element appears (the error), I want to make something else.

I’ve seen this link of waitForVisible but in this case I don´t know how to tell the script that if all goes fine makes “something” and if “error” element appears do “something else”.

Thanks for any help

Below you find the answer that ChatGPT4 has given me for your question. I find it is pretty good and accurate.

What it missed to mention is if verifyElementPresent does not work for you, you can also use other checks:

  • sourceSearch to look in the page source code.
  • visualVerify to visually check for the error image (image of error message)
  • XClickText to use OCR to search for the error text

Let me know if you have further questions :slight_smile:

---- ChatGPT4 answer (plus my small correction):

To handle conditional logic based on whether an error appears after a login attempt in UI.Vision, you can use the verifyElementPresent command to check for the presence of the error message. If the error element is present, you can execute alternative steps; otherwise, you can proceed with the rest of your automation script.

Here’s a basic structure on how you can approach this:

  1. Login Attempt: Execute the steps to fill in the username and password, and then click on the submit button.
  2. Check for Error: Use verifyElementPresent to check for the error message. This command will set the ${!statusOK} internal variable to true if the element is found, and to false if it is not found. That is wrong. This command (like all Ui.Vision commands!) will only set the ${!statusOK} internal variable to false if it is not found and the command has an error. If there is no error (here: element is found), then commands will leave the value of ${!statusOK} unchanged.
  3. Conditional Logic Based on Error Presence: Use if and else commands to define what to do if the error message is present or not.
  4. Continue Script or Handle Error: Depending on the presence of the error, either continue with your script or handle the error accordingly.

Here’s an example script that demonstrates this logic:

{
  "Name": "LoginAutomation",
  "CreationDate": "2024-03-03",
  "Commands": [
    {
      "Command": "open",
      "Target": "https://example.com/login",
      "Value": ""
    },
    {
      "Command": "type",
      "Target": "id=username",
      "Value": "your_username"
    },
    {
      "Command": "type",
      "Target": "id=password",
      "Value": "your_password"
    },
    {
      "Command": "click",
      "Target": "id=loginButton",
      "Value": ""
    },
    {
      "Command": "verifyElementPresent",
      "Target": "xpath=//div[contains(text(),'Error message text')]",
      "Value": ""
    },
    {
      "Command": "if",
      "Target": "${!statusOK} == false",
      "Value": ""
    },
    {
      "Command": "echo",
      "Target": "Login successful, no error detected.",
      "Value": "green"
    },
    // Add your steps here to continue script after successful login
    {
      "Command": "else",
      "Value": ""
    },
    {
      "Command": "echo",
      "Target": "Login error detected. Handling error.",
      "Value": "red"
    },
    // Add your steps here to handle the login error
    {
      "Command": "end",
      "Value": ""
    }
  ]
}

Replace "xpath=//div[contains(text(),'Error message text')]" with the actual XPath or CSS selector that identifies the error message element on your login page. Also, replace "https://example.com/login", "your_username", and "your_password" with the actual URL, username, and password fields for your specific scenario.

This script demonstrates the basic logic of checking for an error after attempting to log in and branching the script based on the outcome. You can extend this by adding more commands within the if or else blocks to handle each scenario as needed.

1 Like

Hi admin, thanks so much for your detailed answer, really pedagogical. Certainly will help many out there in the future.

Actually if error is detected, I’d like to attempt 2 logins more times (3 in total). If error not detected continue with the rest of the script normally. In this case I think only would need if/end block to check error presence and go to a label to attempt login again right?

What I’m not sure is how to tell the script that only tries to login 2 more times and if the 2 more time the error appears finish the script.

Thank you again.

Here the macro with 3 login attempts:

You can change the number of login attempts in this line:

“Target”: “${loginAttempts} < 3 && ${!statusOK} == false”,

{
  "Name": "LoginWithRetriesDoRepeatIf",
  "CreationDate": "2023-04-01",
  "Commands": [
    {
      "Command": "store",
      "Target": "0",
      "Value": "loginAttempts"
    },
    {
      "Command": "do",
      "Target": "",
      "Value": ""
    },
    {
      "Command": "open",
      "Target": "https://example.com/login",
      "Value": ""
    },
    {
      "Command": "type",
      "Target": "id=username",
      "Value": "yourUsername"
    },
    {
      "Command": "type",
      "Target": "id=password",
      "Value": "yourPassword"
    },
    {
      "Command": "clickAndWait",
      "Target": "id=submit",
      "Value": ""
    },
    {
      "Command": "store",
      "Target": "true",
      "Value": "!statusOK"
    },
    {
      "Command": "verifyElementPresent",
      "Target": "css=.error",  // Use the correct selector for the error message
      "Value": ""
    },
    {
      "Command": "if",
      "Target": "${!statusOK} == false",
      "Value": ""
    },
    {
      "Command": "executeScript_Sandbox",
      "Target": "return Number(${loginAttempts}) + 1;",
      "Value": "loginAttempts"
    },
    {
      "Command": "echo",
      "Target": "Login attempt ${loginAttempts} failed, trying again...",
      "Value": "red"
    },
    {
      "Command": "end",
      "Target": "",
      "Value": ""
    },
    {
      "Command": "repeatIf",
      "Target": "${loginAttempts} < 3 && ${!statusOK} == false",
      "Value": ""
    },
    // Continue with the rest of the script after successful login or all attempts fail
    {
      "Command": "if",
      "Target": "${!statusOK} == false",
      "Value": ""
    },
    {
      "Command": "ThrowError",
      "Target": "Login failed after 3 attempts.",
      "Value": ""
    },
    {
      "Command": "else",
      "Target": "",
      "Value": ""
    },
    {
      "Command": "echo",
      "Target": "Login successful!",
      "Value": "green"
    },
    {
      "Command": "end",
      "Target": "",
      "Value": ""
    }
    // Add the rest of your script here
  ]
}

Thanks again for your great help.

In order to work for me, in “If End” block and in “Do repeatIf” block I needed to change the condition to ${!statusOK} == true.

Additionally, I got this error using “ClickAndWait” and needed to change to simple “Click” and add a Pause of 5 seconds but I think is not a best practice.

Below my current code

[error]
Line 6: Error #200: 'clickAndWait' failed. No page load event detected after 10 seconds. Try 'click' instead. Error details: Error #220: Still same ipc secret(more info)
{
  "Name": "LoginWithRetriesDoRepeatIf",
  "CreationDate": "2024-3-3",
  "Commands": [
    {
      "Command": "store",
      "Target": "0",
      "Value": "loginAttempts",
      "Description": ""
    },
    {
      "Command": "do",
      "Target": "",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "open",
      "Target": "https://myexample.com",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "type",
      "Target": "id=username",
      "Value": "yourUsername"
    },
    {
      "Command": "type",
      "Target": "id=password",
      "Value": "yourPassword"
    },
    {
      "Command": "click",
      "Target": "xpath=//button[@type='submit']",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "pause",
      "Target": "5000",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "store",
      "Target": "true",
      "Value": "!statusOK",
      "Description": ""
    },
    {
      "Command": "verifyElementPresent",
      "Target": "css=.error",  
      "Value": "",
      "Description": ""
    },
    {
      "Command": "if",
      "Target": "${!statusOK} == true",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "executeScript_Sandbox",
      "Target": "return Number(${loginAttempts}) + 1;",
      "Value": "loginAttempts",
      "Description": ""
    },
    {
      "Command": "echo",
      "Target": "Login attempt ${loginAttempts} failed, trying again...",
      "Value": "red",
      "Description": ""
    },
    {
      "Command": "end",
      "Target": "",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "repeatIf",
      "Target": "${loginAttempts} < 3 && ${!statusOK} == true",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "comment",
      "Target": "Continue with the rest of the script after successful login or all attempts fail",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "if",
      "Target": "${!statusOK} == true",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "throwError",
      "Target": "Login failed after 3 attempts.,
      "Value": "",
      "Description": ""
    },
    {
      "Command": "else",
      "Target": "",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "echo",
      "Target": "Login successful!",
      "Value": "green",
      "Description": ""
    },
    {
      "Command": "end",
      "Target": "",
      "Value": "",
      "Description": ""
    },
    {
      "Command": "comment",
      "Target": "Continue script",
      "Value": "",
      "Description": ""
    }
  ]
}

Using a small fixed PAUSE is ok if this solves the problem :wink: - Alternatively - for a dynamic wait - you cause any verify.... or CLICK command that checks for something on the new page.

For a visual wait (with image recognition) you can use visualVerify | ImageOfSomethingOnNewPage.png

All these commands wait until !TIMEOUT_WAIT value has been reached.The default value is 10s, but you can change that e. g. to 200s with store | 200 | !TIMEOUT_WAIT

Excellent help you have have me. More than I expected. I’ll have in mind those verification methods in the future.

Do you have some tutorial, lessons written or in video besides the help that have for each command? For example how to build different forms of xpaths or selectors. How to deal when frames appear, etc.

Best regards.