Xpath Changes When Inspecting Element

Hey all,

When I copy and paste an xpath sometimes it will change by one for reasons that I don’t understand. I’m a relative beginner so if this is obvious, I apologize!

/html/body/div[15]/div/div/div/div/div[1]

will change to

/html/body/div[14]/div/div/div/div/div[1]

for no apparent reason in between version releases on the site I’m testing. If this is too vague let me know and I’ll do my best to clear it up. Thanks!

hard to tell really… can be that devs changed some structure or in case they are using some framework to generate page this will happen.
btw. rule of thumb for x-path - shorter is better … long x-paths are very fragile and change sensitive … always try to find closest unique object and use relative path from that to object of interest.

Thanks for that. I’ll dig further into how I can use shorter and more change-resistant xpaths.

The best way to accomplish this is generally to identify an attribute on the element you are targeting, and to use a recursive xpath to find it. For example, if you lets say the very last div in the xpath you’ve shared has an id attribute and/or a class attribute:

<div id="some_id" class="some_class">

Then the most concise and “change-resistant” xpath you could possibly write would be something like this:

//div[@id='some_id']

or

//div[@class='some_class']

Basically this is preferable to a location-dependend xpath like the one you’ve shared, because it doesn’t care where the element exists in the DOM, just that it exists.

If you can share a snapshot of the HTML you are working with, I could provide a concrete example for you.

Sure, so for instance

What I’ve been doing is from this:

<div class="default-modal-bg " style="position: fixed; top: 0px; bottom: 0px; left: 0px; right: 0px; background-color: rgba(0, 0, 0, 0.3); padding: 50px; overflow-y: auto; z-index: 1000; display: flex; justify-content: space-around; align-items: flex-start;"><div class="default-modal-wrap" style="background-color: rgb(255, 255, 255);"><input class=" gv-input" type="text" placeholder="Enter filter keyword..." value=""><div class="panel-tree-picker" style="display: inline-flex; width: 100%; overflow: auto;"><div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">AMSC Code</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Agency ID</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Agency Name</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Agency State</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Bid Number</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Date Added</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Description</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">FSC Code</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);"><div style="display: flex; align-items: center;">Field Group<i class="material-icons" style="font-size: 20px;">chevron_right</i></div></div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Files</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">NAICS Code</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">NIGP Code</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">NSN Code</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Posted Date</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Script Name</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Set Aside</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Tags</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Title</div><div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">UNSPSC Code</div></div></div></div></div>

Finding the object

/html/body/div[10]/div/div/div/div/div[11]

And using that xpath in Katalon- which every time development updates something will change to div[9] (for example.)

Does that make sense?

Can you take a screenshot of the HTML as it’s presented in the browser inspector? (right click on the element you are trying to locate, and click “inspect”) It’s tough to see the structure with copy/pasted HTML.

Thanks!

<div class="default-modal-bg " style="position: fixed; top: 0px; bottom: 0px; left: 0px; right: 0px; background-color: rgba(0, 0, 0, 0.3); padding: 50px; overflow-y: auto; z-index: 1000; display: flex; justify-content: space-around; align-items: flex-start;">
	<div class="default-modal-wrap" style="background-color: rgb(255, 255, 255);">
		<input class=" gv-input" type="text" placeholder="Enter filter keyword..." value="">
			<div class="panel-tree-picker" style="display: inline-flex; width: 100%; overflow: auto;">
				<div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">AMSC Code</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Agency ID</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Agency Name</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Agency State</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Bid Number</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Date Added</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Description</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">FSC Code</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">
						<div style="display: flex; align-items: center;">Field Group<i class="material-icons" style="font-size: 20px;">chevron_right</i></div>
					</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Files</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">NAICS Code</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">NIGP Code</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">NSN Code</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Posted Date</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Script Name</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Set Aside</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Tags</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">Title</div>
					<div style="padding: 10px 40px; cursor: pointer; font-size: 18px; background: rgb(255, 255, 255); color: rgb(0, 0, 0);">UNSPSC Code</div>
			</div>
		</div>
	</div>
</div>

With such structure i would use text() to get to element i want - it’s not best since text can easily change however if you cannot influence developers to add any king of ID (unique identifier) then text is 2nd best option
e.g. to get div with text “Bid Number”
i’ll use
xpath = //div[contains(text(),"Bid") and contains(text(),"Number")]

2 Likes

Funny, I debated between a screenshot and making it easy to copy/paste for you. I think I’ve got my answer below, but thank you for your attention!

Yep this does exactly what I need. Even if the text changes it’ll be easier to see rather than copying the new (but equally fragile) xpath.

Thank you!

Personally, I would say that it’s easier to look at a screenshot from the inspector than copy/pasted HTML. There’s usually no need to copy anything; we generally are just concerned with the hierarchy and the potential hooks to use in xpath locators.

I’m glad @Andrej_Podhajsky’s solution works for you. As you can see, recursive xpaths are almost always the way to do it.

2 Likes

Noted! Thanks for that, yes definitely re recursive xpaths.