An element could not be located on the page using the given search parameters

Hi, everybody!
I’m trying to test an user login in an app on Android and I have a problem.
I need to check that after a user enters text in my application, whether or not an error message appears.
As I have set up the test, it should appear the first time, and not the second time.
I am able to get my test to check correctly the first time, telling me that the message appears and that the text is correct, but the second time, when I check that the error message does not appear, the console shows me this error and the test fails:

FAILED: appiumTest.Login.Login

org.openqa.selenium.NoSuchElementException: An element could not be located on the page using the given search parameters.

This is my code:

        //steps with a incorrect text
        WebElement textErrorInput = driver.findElement(By.id("com.example.prep:id/textinput_error"));

                // check textErrorInput element appeared
                if (isLoaded(textErrorInput)) {
                    Assert.assertEquals(textErrorInput.getText(), "Este teléfono no es válido.", "Text input error NOT correct");
                    System.out.println(ANSI_YELLOW + "Aparece mensaje de error y texto es correcto" + ANSI_RESET);
                } else {
                    System.out.println(ANSI_YELLOW + "No aparece mensaje de error" + ANSI_RESET);
                }

               // some steps with a correct text
               
              //
              textErrorInput = driver.findElement(By.id("com.example.prep:id/textinput_error"));

What can I do so that the test simply tells me that that element does not exist, and continues without failing?
Thanks!

i use following code to check element loaded:

    public boolean isLoaded(WebElement el) {
        boolean bool = false;
        try {
            bool = !((RemoteWebElement) el).getId().isEmpty();
        } catch (Exception ignored) {
        }
        return bool;
    }
1 Like

Yes, that is exactly the code block I use for isLoaded.
Copy&paste (maybe you can see some error in it)

 public boolean isLoaded (WebElement ele){
         boolean bool = false;
         try {
             bool = !((RemoteWebElement) ele).getId().isEmpty();
         } catch (Exception ignored) {
         }
         return bool;
     }

possibly you have error here?

1 Like

or here.

I suggest you use Appium annotations OR send locator into isLoaded.

e.g.

     @iOSXCUITFindBy(id = "your_id")
    @AndroidFindBy(id = "textinput_error")
    private WebElement textErrorInput;

    if (isLoaded(textErrorInput)) {
    ...

// or

    if (isLoadedByLoc(By.id("com.example.prep:id/textinput_error")) 
....
    public boolean isLoadedByLoc(By loc) {
        boolean bool = false;
        try {
            bool = !((RemoteWebElement) driver.findElement(loc)).getId().isEmpty();
        } catch (Exception e) {
        }
        setDefaultTiming();
        return bool;
    }
1 Like

Aleksei

driver.findElement(By.id(“com.example.prep:id/textinput_error”))

Maybe, but in the first case it works correctly.
The problem is the second time I want to check if the text appears.
It seems that, since the text does not appear (because it should not) instead of following my code and passing the test only indicating that it does not appear, it throws me an error telling me that it cannot find the element.
And you don’t have to find it, because it’s not there.
What I can’t get is for the test to continue, since it gives me the error that it can’t find it.

I wrote you 2 ways how avoid your error and proceed. Just try any of them.

1 Like

Aleksei

@AndroidFindBy
My code says: The annotation @AndroidFindBy is disallowed for this location

With the other method, same problem...

I´m sorry. I really appreciate your help, but I´m starting to think it´s hopeless :D

cause it should be before! example:

public class ExpireCardPage extends BasePage {

    @iOSXCUITFindBy(id = "RECARD1View")
    @AndroidFindBy(id = "iv_card_expires_in_days")
    WebElement mainContainer;

    // header
    @iOSXCUITFindBys(value = {
            @iOSXCUITBy(id = "RECARD1View"),
            @iOSXCUITBy(id = "generated_Label"),
    })
    @AndroidFindBy(id = "tv_recard1_uni_tv_title")
    WebElement expirationMessageText;

    // body

    //footer
    @iOSXCUITFindBy(id = "getReplacementButton")
    @AndroidFindBy(id = "pb_get_replacement")
    WebElement getReplacementButton;

    public ExpireCardPage(Page page) {
        super(page);
    }

    public boolean isLoaded(int sec) {
        Logger.log("sec: '" + sec + "'");
        setLookTiming(sec);
        return super.isLoaded(mainContainer);
    }

    public ExpireCardPage isExpireCardPageLoaded() {
        Assert.assertTrue(isLoaded(-1), Logger.createAssertionLog("'ExpireCardPage' NOT loaded"));
        return this;
    }

    @Step("Tap 'Get replacement' button")
    public AdrConfirmPage tapGetReplacementButton() {
        Logger.log();
        Assert.assertTrue(tap(getReplacementButton), Logger.createAssertionLog("FAILED"));
        return new AdrConfirmPage(page);
    }
}

or first found in internet → 13. Implementing Page Factory in Appium based Framework - naveen automationlabs

BUT ! you free to use second example

// or

    if (isLoadedByLoc(By.id("com.example.prep:id/textinput_error")) 
....
    public boolean isLoadedByLoc(By loc) {
        boolean bool = false;
        try {
            bool = !((RemoteWebElement) driver.findElement(loc)).getId().isEmpty();
        } catch (Exception e) {
        }
        setDefaultTiming();
        return bool;
    }
1 Like

With the second example, I still have the same problem.

With the annotation it seems to work, but now, the test passes correctly, but saying that in the first case (in which the error message does appear and the text must also be recognized) it says that the message does not appear, that is, in both cases the text recognizes that the message error does not appear… so something continues to fail

Add all your code so we can where issue is

1 Like

Today I realized that I needed to put the locator in a place, and now what happens is that the test passes correctly, but telling me that the second time the error message also appears, when it does not.
This is the whole code.

       public class Login extends BaseTest {
        	        
        	public static final String ANSI_YELLOW = "\u001B[33m";
        	public static final String ANSI_RESET = "\u001B[0m";
        	
        	@AndroidFindBy(id = "com.example.prep:id/textinput_error")
        	private WebElement displayedError;
        	
        	@Test
        	public void Login() throws MalformedURLException, InterruptedException{
        ...
        //Number insertion check
        		WebElement inputNumber = driver.findElement(By.xpath("//android.widget.EditText"));
        		WebElement continueButton = driver.findElement(By.id("com.example.prep:id/fragment_validate_phone_number_button"));
        			
        		//Input a wrong number & check <<Continuar>> button
        			System.out.println(ANSI_YELLOW + "***Comprobación de inserción de número de teléfono con número inválido***" + ANSI_RESET);
        		
        		int wrongNumber = 5;
        		
        		for (int i = 1; i <= 9; i++) {
        		    String phoneNumber = "+34 ";
        		    for (int wn = 0; wn < i; wn++) {
        		        phoneNumber += wrongNumber;
        		    }
        		    
        		    inputNumber.sendKeys(phoneNumber);
        		    
        		    if (!continueButton.isEnabled()) {
        		        System.out.println(ANSI_YELLOW + "Con " + i + " cifras, el botón de <<Continuar>> está deshabilitado" + ANSI_RESET);
        		    }
        		    else {
        		    	System.out.println(ANSI_YELLOW + "Con " + i + " cifras, el botón de <<Continuar>> está habilitado" + ANSI_RESET);
        		    }    
        		}
        		
        		//Check if error text appeared
        		WebElement displayedError = driver.findElement(By.id("com.example.prep:id/textinput_error"));
        		String errorText = driver.findElement(By.id("com.example.prep:id/textinput_error")).getText();	

        		driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));

        		if (isLoaded(displayedError)) {
                    Assert.assertEquals(errorText, "Este teléfono no es válido.");
                    System.out.println(ANSI_YELLOW + "Aparece mensaje de error y texto es correcto" + ANSI_RESET);
                } else {
                    System.out.println(ANSI_YELLOW + "No aparece mensaje de error" + ANSI_RESET);
                }
        		
        		//Input a right number & check <<Continuar>> button
        		System.out.println(ANSI_YELLOW + "***Comprobación de inserción de número de teléfono con número válido***" + ANSI_RESET);
        		
        		int rightNumber = 7;
        		
        		for (int i = 1; i <= 9; i++) {
        		    String phoneNumber = "+34 ";
        		    for (int rn = 0; rn < i; rn++) {
        			phoneNumber += rightNumber;
        		    }
        		    
        		    inputNumber.sendKeys(phoneNumber);
        		    
        		    if (!continueButton.isEnabled()) {
        		        System.out.println(ANSI_YELLOW + "Con " + i + " cifras, el botón de <<Continuar>> está deshabilitado" + ANSI_RESET);
        		    }
        		    else {
        		    	System.out.println(ANSI_YELLOW + "Con " + i + " cifras, el botón de <<Continuar>> está habilitado" + ANSI_RESET);
        		    }
        		 }	
        		
        		//Check if error text appeared
        		if (isLoaded(displayedError)) {
                    Assert.assertEquals(errorText, "Este teléfono no es válido.", "Text input error NOT correct");
                    System.out.println(ANSI_YELLOW + "Aparece mensaje de error y texto es correcto" + ANSI_RESET);
                } else {
                    System.out.println(ANSI_YELLOW + "No aparece mensaje de error" + ANSI_RESET);
                }
        }
        }

In both cases, both when entering a number that does not exist or one that does, the code throws the same message:
“Aparece mensaje de error y texto es correcto”.
Which seems to mean that in both cases it finds the error message, but when it checks with the correct number it doesn’t appear, so I don’t understand why it now acts like it does

try a bit update example. check TODO I added.

public class Login extends BaseTest {

    public static final String ANSI_YELLOW = "\u001B[33m";
    public static final String ANSI_RESET = "\u001B[0m";

    @AndroidFindBy(className = "android.widget.EditText")
    private WebElement numberInput;

    @AndroidFindBy(id = "fragment_validate_phone_number_button")
    private WebElement continueButton;

    @AndroidFindBy(id = "textinput_error") // no package name needed here. Appium will add it automatically
    private WebElement errorText;

    @Test
    public void Login() {

        //Number insertion check

        //Input a wrong number & check <<Continuar>> button
        System.out.println(ANSI_YELLOW + "***Comprobación de inserción de número de teléfono con número inválido***" + ANSI_RESET);

        int wrongNumber = 5;

        for (int i = 1; i <= 9; i++) {
            String phoneNumber = "+34 ";
            for (int wn = 0; wn < i; wn++) {
                phoneNumber += wrongNumber;
            }

            numberInput.sendKeys(phoneNumber);

            if (!continueButton.isEnabled()) {
                System.out.println(ANSI_YELLOW + "Con " + i + " cifras, el botón de <<Continuar>> está deshabilitado" + ANSI_RESET);
            } else {
                System.out.println(ANSI_YELLOW + "Con " + i + " cifras, el botón de <<Continuar>> está habilitado" + ANSI_RESET);
            }
        }

        //Check if error text appeared
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
        // TODO: update `isLoaded` to accept number of seconds! and restore default search value!
        if (isLoaded(errorText)) {
            Assert.assertEquals(errorText.getText(), "Este teléfono no es válido.");
            System.out.println(ANSI_YELLOW + "Aparece mensaje de error y texto es correcto" + ANSI_RESET);
        } else {
            System.out.println(ANSI_YELLOW + "No aparece mensaje de error" + ANSI_RESET);
        }
        // TODO restore default timeout! 10?
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));

        //Input a right number & check <<Continuar>> button
        System.out.println(ANSI_YELLOW + "***Comprobación de inserción de número de teléfono con número válido***" + ANSI_RESET);

        int rightNumber = 7;

        for (int i = 1; i <= 9; i++) {
            String phoneNumber = "+34 ";
            for (int rn = 0; rn < i; rn++) {
                phoneNumber += rightNumber;
            }

            numberInput.sendKeys(phoneNumber);

            if (!continueButton.isEnabled()) {
                System.out.println(ANSI_YELLOW + "Con " + i + " cifras, el botón de <<Continuar>> está deshabilitado" + ANSI_RESET);
            } else {
                System.out.println(ANSI_YELLOW + "Con " + i + " cifras, el botón de <<Continuar>> está habilitado" + ANSI_RESET);
            }
        }

        //Check if error text appeared
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
        if (isLoaded(errorText)) {
            Assert.assertEquals(errorText.getText(), "Este teléfono no es válido.", "Text input error NOT correct");
            System.out.println(ANSI_YELLOW + "Aparece mensaje de error y texto es correcto" + ANSI_RESET);
        } else {
            System.out.println(ANSI_YELLOW + "No aparece mensaje de error" + ANSI_RESET);
        }
    }
}

It still doesn’t work. Now, in both cases the test says that the error message does not appear. :cry:

share result:

System.out.println(driver.getPageSource());

on problematic screen at https://gist.github.com/ as link here.

Test after changes has same flow? One time we have error, one not - correct?

I don’t think I can do this with a mobile app.

You can. Just try…

Finally, I solved it with another method.
In case it is useful to you, here is an example.

List<WebElement> errorFrame = driver.findElements(By.id("com.example.prep:id/textinput_error"));
		if (errorFrame.isEmpty()) {
			System.out.println(ANSI_YELLOW + "No aparece mensaje de error" + ANSI_RESET);
		} else {
			Assert.assertEquals(errorText, "Este teléfono no es válido.");
			System.out.println(ANSI_YELLOW + "Aparece mensaje de error y texto es correcto" + ANSI_RESET);
		}