0

I'm trying automate an Angular application. The only drawback I have at the moment is that I don't want to use Protractor, I want to automate using Selenium/Eclipse. I have tried it but the problem is that locator keeps changing whenever I rerun the test. I have browsed through the net and found no concrete solution to this. Snippet of one field in the websites:

<input _ngcontent-wle-c93="" formcontrolname="FirstName" mattooltip="Enter First Name" maxlength="50" matinput="" placeholder="First Name" class="mat-input-element mat-form-field-autofill-control ng-tns-c47-3 ng-pristine ng-invalid ng-touched" cdk-describedby-host="" id="mat-input-0" aria-invalid="true" aria-required="false" aria-describedby="mat-error-0">

id="mat-input-0" keeps changing

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
Max_431
  • 23
  • 6
  • Then use one of the attributes that doesn't change, or add your own more stable locators (e.g. `data-test-id="some-useful-input"`). Even if you *are* using Protractor that's better than coupling your E2E tests to Angular. – jonrsharpe Sep 21 '20 at 16:41

2 Answers2

2

For your element, you have a couple of options to access it

<input _ngcontent-wle-c93="" formcontrolname="FirstName" mattooltip="Enter First Name" maxlength="50" matinput="" placeholder="First Name" class="mat-input-element mat-form-field-autofill-control ng-tns-c47-3 ng-pristine ng-invalid ng-touched" cdk-describedby-host="" id="mat-input-0" aria-invalid="true" aria-required="false" aria-describedby="mat-error-0">

Let's take it one by one

CSS_SELECTOR

drive.findElement(By.cssSelector("input[formcontrolname='FirstName'][placeholder='First Name']"));

XPATH

drive.findElement(By.xpath("//input[contains(@placeholder,'First Name')]"));

or

drive.findElement(By.xpath("//input[contains(@formcontrolname,'FirstName')]"));

or both

drive.findElement(By.xpath("//input[contains(@formcontrolname,'FirstName') and (@placeholder, 'FirstName')]"));

same for CSS_SELECTOR - I've shown to you the code with both, but you can access it even by specifying one attribute for your input element

Alin Stelian
  • 861
  • 1
  • 6
  • 16
  • Loads of Thanks. Your answer was the perfect solution. This is what I was looking for. Although CSS worked perfectly and I assume xpath would have worked as well but when I rechecked the code, it had "matinput placeholder" not just "placeholder". I tried with the matinputplaceholder but did not work. If you could just tell me why it did not work, that would be great. Again, Thanks a bunch. – Max_431 Sep 22 '20 at 09:37
  • matinput is an empty attribute, you cannot use it as [matinputplaceholder] cause placeholder is an attribute that has value, if you set matinput value in code, your browser will generate it differently and then you can use it //input[contains(@matinput, 'value') and (@placeholder,'value')] – Alin Stelian Sep 22 '20 at 09:49
0

To identify the element you have to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:

  • Using and XPATH:

    new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//input[contains(@class, 'mat-input-element') and @formcontrolname='FirstName'][@placeholder='First Name']"))).click();
    
  • Using and CSS_SELECTOR:

    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input.mat-input-element[formcontrolname='FirstName'][placeholder='First Name']"))).click()
    
  • Note : For python clients you have to add the following imports :

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352