简体   繁体   中英

Alternative to finding elements using hard coded Xpath

I have a html below that contains simply div tags that within contain text fields and a display for validation messages:

<div class="payment-form">
   <div class="payment-form__payment-type">
      <div class="false-label">Payment type</div>
      <div class="form-column">
         <div class="false-label">Name on card</div>
         <div class="form-element-wrapper form-element-wrapper--input-text clearfix form-element-wrapper--error form-element-wrapper--show-label"><label for="name-on-card">Name on card</label> <input name="name-on-card" data-payment-jet2="holderName" id="name-on-card" type="text" maxlength="32" data-vv-id="_0zd5ajemk" aria-required="true" aria-invalid="true"></div>
         <p class="validation-message validation-message--active" style="">Please correct the name on card</p>
      </div>
      <div class="form-column">
         <div class="false-label">Card number</div>
         <div class="form-element-wrapper form-element-wrapper--input-text clearfix form-element-wrapper--error form-element-wrapper--show-label"><label for="card-number">e.g 1111-2222-3333-4444</label> <input type="hidden" data-payment-jet2="number"> <input name="card-number" id="card-number" type="tel" maxlength="23" class="js-payment-card-number" data-vv-id="_wn4jqw3yg" aria-required="true" aria-invalid="true"></div>
         <p class="validation-message validation-message--active" style="">Please correct the card number</p>
      </div>
   </div>
</div>

Now the problem I am having is with the validation messages which are the same class:

<p class="validation-message validation-message--active" style="">

In my selenium I want to ensure the correct validation is displayed but because they have the same class, I cannot differentiate between then unless I use a hard coded dirty xpath like:

public static By NameOnCardValidation => By.XPath("/html/body/div[1]/div[3]/section/div[6]/div[2]/div/div/div/div/div[3]/p");
public static By CardNumberValidation => By.XPath("/html/body/div[1]/div[3]/section/div[6]/div[2]/div/div/div/div/div[4]/p");

Thus makes maintenance difficult as if there are any changes to the website, then I will have to keep updating these xpaths.

My question is that can you see a way where I can locate the validation messages a lot easier without entering a hard coded xpath like above? Just to let you know the messages in the validation may change so it would not be a good idea to look for the text within the validation message.

Thanks,

As you mentioned that the messages in the validation may change so we will create xpath those are independent of the Messages . Through our dynamic xpath we will be able to control all the <p> tags which may contain any message as follows :

public static By NameOnCardValidation => By.XPath("//div[@class='payment-form']//following::p[1]");
public static By CardNumberValidation => By.XPath("//div[@class='payment-form']//following::p[2]");

My question is that can you see a way where I can locate the validation messages a lot easier without entering a hard coded xpath like above?

In such cases we do it in a simple and general way (using JBehave and java, but that's implementation details that do not matter)


At the story level there is simple Then step:

When an user performs some action
Then a message appears on the screen: some message

and it's implementation looks like this:

@Then("a message appears on the screen: $message")
public void shoudMeassageAppearOnTheScreen( String message ){
      String xpath = String.format( 
           "//*[contains( @class, 'validation-message' ) and text() = '%s' ]", message 
      );

       WebDriverWait wait = new WebDriverWait( driver, 5 );
       try{ 
          wait.until( ExpecedConditions.visibilityOfElementLocated( By.xpath( xpath ));
      }catch( Exception e ){
         throw new RuntimeException( "Message is not visible: " + message, e );
      }
}

so we are waiting 5 seconds for the message, if it is not visible, then an exception is thrown with a understandable error message, and a test fails (due to the exception thrown to the log).

Providing that the error message it self doesn't change you should be able to use the following Xpath:

 //p[contains(text() ='Please correct the card number')]

No matter where it is on the page it should continue to work as long as the actual error message doesn't change. I try to use the [contains] approach for all of the work I do with selenium. It makes the application more sturdy and less affected by html changes. If you have any control over the page then adding an id to the paragraph would probably be a better way to do it. Then you can use something like:

 //p[@id='cardnumber_error']

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM