WebUI.getText() doesn't work for all elements on page

The rundown:
I have a script that runs through a site checkout flow, and then compares the values for each line item/fee before the order is placed (order summary) and after the order is placed (order confirmation). I have six values that get grabbed by WebUI.getText(), all on the same page and mostly within the same table. Four of that six have no issue, but the text for “Subtotal” and “Order Total” are being read as “” (no value), but the rest of the values are read just fine. My initial thought was that the locator for those two values were not correct, but that didn’t work out.


I added waits to see if the values weren’t initially available, but that didn’t resolve it. Here’s the method where it all happens:

		//Check the existing orderInformation map against the text visible on page
		KeywordUtil.logInfo("Verifying the information from Order Summary matches Order Confirmation")
		WebUI.delay(5)
		//Get the values from the page
		def confirmItemName = WebUI.getText(findTestObject('Object Repository/Published Site/Secure Checkout/CMI/Order Confirmation/p_itemName'))
		def confirmSubtotal = WebUI.getText(findTestObject('Object Repository/Published Site/Secure Checkout/CMI/Order Confirmation/p_subtotal'))
		def confirmTax = WebUI.getText(findTestObject('Object Repository/Published Site/Secure Checkout/CMI/Order Confirmation/p_taxes'))
		def confirmOrderTotal = WebUI.getText(findTestObject('Object Repository/Published Site/Secure Checkout/CMI/Order Confirmation/p_orderTotal'))
		def confirmServiceCharge = WebUI.getText(findTestObject('Object Repository/Published Site/Secure Checkout/CMI/Order Confirmation/p_serviceCharge'))

		//compare it to the expected values
		def compare1 = WebUI.verifyMatch(orderInformation.get("Item Name"), confirmItemName, false, FailureHandling.OPTIONAL)
		def compare2 = WebUI.verifyMatch(orderInformation.get("Sub Total"), confirmSubtotal, false, FailureHandling.OPTIONAL)
		def compare3 = WebUI.verifyMatch(orderInformation.get("Tax"), confirmTax, false, FailureHandling.OPTIONAL)
		def compare4 = WebUI.verifyMatch(orderInformation.get("Order Total"), confirmOrderTotal, false, FailureHandling.OPTIONAL)
		def compare5 = verifyFulfillmentFee()
		def compare6 = WebUI.verifyMatch(orderInformation.get("Service Charge"), confirmServiceCharge, false, FailureHandling.OPTIONAL)
		/* Debug */
		//def compare2 = true
		//def compare4 = true
		if(compare1 & compare2 & compare3 & compare4 & compare5 & compare6) {
			def orderIdOnCheckout = WebUI.getText(findTestObject('Object Repository/Published Site/Secure Checkout/CMI/Order Confirmation/div_orderNumber'))
			def orderDateTime = WebUI.getText(findTestObject('Object Repository/Published Site/Secure Checkout/CMI/Order Confirmation/div_orderDateTime'))
			orderInformation.put("OrderId", orderIdOnCheckout)
			orderInformation.put("Order Date", orderDateTime)
			return true
		} else {
			KeywordUtil.markErrorAndStop("Checkout doesn't match!")
			return false
		}
	} 

This had been working flawlessly a few weeks ago, but then the developers took it back to make additional changes elsewhere, and there has been a few Chrome updates since then. I also tried running it on other browsers with the same result. Any ideas?

Right off the bat, no… but let’s see if we can move you forward.

You’re obviously comfortable in DevTools. Can you use CSS selectors directly comparable to you XPaths and prove to yourself that the elements work as expected in DevTools?

You’ll want to use lines like this in the DevTools console:

document.querySelector("your css selector for subtotal").innerText;

Had you given me a screenshot of your HTML, I might have been able to write a fully working querySelector for you :confused:

Ah, whoops! Here’s a screenshot of the HTML in question. Each of the line items are structured this way.


Using dev tools’ messy CSS selector of

body > div.site-wrapper > div > div > div > div.order-status-app > div > div.order-status-wrapper.order-section > div > div:nth-child(2) > div > div:nth-child(3) > p:nth-child(2)

to find inner text did indeed return the $1.00 I was expecting.

Here’s a shorter (and hopefully less fragile) CSS selector:

div.order-summary-section div.line-item:nth-of-type(1) p+p

So…

document.querySelector("div.order-summary-section div.line-item:nth-of-type(1) p+p").innerText;

That should retrieve the subtotal.

Here it is broken down in English:

  • div.order-summary-section
    ** Find a div with class=order-summary-section
  • div.line-item:nth-of-type(1)
    ** Inside the first div, find a div with class=line-item but only select the FIRST one found
  • p+p
    ** Inside that div, look for a pair of p element siblings - select the second sibling

So, if you need to dig into, say, the fifth line-item:

document.querySelector("div.order-summary-section div.line-item:nth-of-type(5) p+p").innerText;

nth-of-type(5) landed on the taxes field, but it’s easy enough to point in the right spot.
They’re all returning their visible values in DevTools console. Should I slot that code into my method somewhere or just replace the locator in the object?

Toss a coin. I’m a CSS guy (not an XPath guy). If I used Test Objects (I don’t) I’d replace the xpath stuff with CSS. :upside_down_face:

In actual fact, I’d use JavaScript, pretty much like you did with querySelector above.

Here is a XPath guy intervening your productive discussion.

I would suggest a XPath expression:

//div[contains(@class,'order-summary-section')]//p[contains(. ,'Subtotal')]/following-sibling::p[1]

This XPath expression selects a <p> element which is just next to <p>Subtotal</p> which is inside <div class="order-summary-section"> in the target HTML document.

Or even shorter one:

//p[contains(. ,'Subtotal')]/following-sibling::p[1]

This XPath expression selects a <p> element which is just next to <p>Subtotal</p> which is inside <div class="order-summary-section"> in the target HTML document. However here I assume that there is only one <p>Subtotal</p> in the document.

If you want to learn more about XPath following-sibling axes, read this artile.

These expressions do not depend on the relative position of the parent node <div class="line-item"></div>. The relative position (5) of the parent node tends to change when the Web page is redesigned. These expressions rather use the text Subtotal as the key to identify the data item you want ($1.00).

A human-visible text (such as Subtotal) in a Web page tends to be sustained/unchanged when the Web page is redesigned. So the above expression could be a bit more robust against the HTML change.