track elements by dynamic path

Ask general questions here.
mander95
Posts: 66
Joined: Tue Jun 21, 2016 7:35 pm

track elements by dynamic path

Post by mander95 » Fri Dec 09, 2016 12:29 am

So I'm working with a website automation that has UI elements whose properties will change from time to time depending on how you log into the site. The properties however that will remain consistent, however, will be the ones listed below:

domain
button type
inner OR href

An sample element that I want to be able to track has the following path:

/dom[@caption~'^Education\ -\ View\ My\ Consu']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='https://stage-pp-web/patient/education.php?topic_id=3']

I am trying to generate a function that tracks the UI element based on the properties stated above. Is there a way I can to write this function so that it extracts the button type (I already figured out how to get the domain and inner text OR href)

This is an example equation of what I'm trying to accomplish:

public void webClickButton(Ranorex.Adapter reposItem)
{
string href = reposItem.Element.GetAttributeValueText("Href");

//use the root address to specify the domain
string node = ".//dom[@domain="+"'"+ rootAddress +"'"+ "]";
WebDocument webdoc = node;

//search for the button within this domain
ATag link = webdoc.FindSingle(".//a[@href="+"'"+href+"'"+"]");

//click the button
link.Click();

}

For this particular case, I'm asking how do I extract the "a" in .//a[@href...

Vaughan.Douglas
Posts: 250
Joined: Tue Mar 24, 2015 5:05 pm
Location: Des Moines, Iowa, USA

Re: track elements by dynamic path

Post by Vaughan.Douglas » Mon Dec 12, 2016 5:24 pm

I read through your question a couple of times and I'm still not sure what it is you're trying to do.

You're clearly using coded modules as opposed to recorded modules.

you're trying to create a method to click something that you're calling a button but I only see reference to a link. Are you calling a link (aTag) a button in generic terms?

You're saying the domain, button type and either the text or href value will remain constant, yet you seem to be using a variable to hold that information. Are you saying that all of the object you're trying to hit will have a domain, button type and text OR href properties but the actual values of those are also dynamic?

You're also passing a Ranorex Adapter object into this method, but it doesn't appear that you're using it.
public void webClickButton(Ranorex.Adapter reposItem)
{
string href = reposItem.Element.GetAttributeValueText("Href");

//use the root address to specify the domain
string node = ".//dom[@domain="+"'"+ rootAddress +"'"+ "]";
WebDocument webdoc = node;

//search for the button within this domain
ATag link = webdoc.FindSingle(".//a[@href="+"'"+href+"'"+"]");

//click the button
link.Click();

}
Doug Vaughan

mander95
Posts: 66
Joined: Tue Jun 21, 2016 7:35 pm

Re: track elements by dynamic path

Post by mander95 » Tue Dec 13, 2016 7:33 pm

So what I'm trying to do is track the aTag (sorry for the confusion) type within the path. In the path for one the buttons I'm using starts like this ".//a[@href=...". What I want to do is be able to find a way to extract the "a" which defines the type from the path. or at least be able create a condition that adjusts the tag based on the button type.The domain, I already have a way of extracting it and adding it to the aTag string which is:

//get the domain name by looking at the top of the element tree (typically, web elements have their domain at the top of the tree)
WebDocument elementParent = reposItem.Element.TopLevelAncestor;
string rootAddress = elementParent.Domain;

The reason why I can't just have a simple respoItem.click() is because the absolute path of each button will change between paths. Also, like you mentioned, the only thing that will remain constant is the href and inner text, but I'm switching to only referring to the href. So the second part of the path that extracts the href looks like this:

//use the root address to specify the domain
string href = reposItem.Element.GetAttributeValueText("Href");
string node = ".//dom[@domain="+"'"+ rootAddress +"'"+ "]";
WebDocument webdoc = node;

//search for the button within this domain
ATag link = webdoc.FindSingle(".//a[@href="+"'"+href+"'"+"]");

//click the button
link.Click();

The third part of this function should be able to find the aTag's type and change base on the reposItem.
2 different examples include

webdoc.FindSingle(".//a[@href="+href+"]");
webdoc.FindSIngle(".//li[@href="+href+"]");

so I need to be able to find the "a" or "li" and change the path based on that because that will also remain constant between the builds.

Vaughan.Douglas
Posts: 250
Joined: Tue Mar 24, 2015 5:05 pm
Location: Des Moines, Iowa, USA

Re: track elements by dynamic path

Post by Vaughan.Douglas » Wed Dec 14, 2016 3:32 pm

So what I'm trying to do is track the aTag (sorry for the confusion) type within the path. In the path for one the buttons I'm using starts like this ".//a[@href=...". What I want to do is be able to find a way to extract the "a" which defines the type from the path. or at least be able create a condition that adjusts the tag based on the button type.
The aTag object is the Ranorex adapter for link objects. I'm pretty sure any time you find a node with a HTML tag of "a" it's going to be a Ranorex.aTag object.

If all you want to do is find a generic tag with a specific href

Both of these
webdoc.FindSIngle(".//a[@href="+href+"]");
webdoc.FindSIngle(".//li[@href="+href+"]");
Can be described with this
webdoc.FindSIngle(".//*[@href="+href+"]");
If you wanted to know if the thing you found was an li tag or a tag, I think you could do this:
var myTagName = webdoc.FindSIngle(".//*[@href="+href+"]").tagname;
I'm still confused by what you're saying here:
The reason why I can't just have a simple respoItem.click() is because the absolute path of each button will change between paths. Also, like you mentioned, the only thing that will remain constant is the href and inner text, but I'm switching to only referring to the href
Furthermore this makes me think you might be taking a bunch of extra steps to accomplish whatever it is you're trying to get done.
//get the domain name by looking at the top of the element tree (typically, web elements have their domain at the top of the tree)
WebDocument elementParent = reposItem.Element.TopLevelAncestor;
It appears as if you're working with an object in the object repository reposItem. Why are you trying to get out to the WebDocument object? Are you using an object repository?

If I wanted to find and click a generic dom object (either a or li) with a specific href property AND I was using an object repository:
Ranorex.WebElement myElement = _repo.myRootOjb.SelfInfo.CreateAdapter<Ranorex.WebElement>(false);
if (_repo.myRootOjb.Self.TryFindSingle<WebElement>("descendant::*[@href=" + href + "]", myElement)) {
	myElement.Click();
} else {
	Report.Snapshot(_repo.myRootOjb.Self);
}
This is a sanitized example originally coded in VB and converted to C# using Telerik Code Converter

Let me know if we're getting any closer.
Doug Vaughan

mander95
Posts: 66
Joined: Tue Jun 21, 2016 7:35 pm

Re: track elements by dynamic path

Post by mander95 » Wed Dec 14, 2016 5:23 pm

Your previous replies are getting me closer to where I want to be with my function so thank you for that. I have attached my user code for this specific function for a complete understanding of where i stand with it right now. The last thing that I need in order to get my function working is to extract the current working domain and create a path that Ranorex recognizes and then clicks it. If it is easier to create a new element altogether like you did in your previous reply, I'll go with that route instead.


The repository item referred to in the tester function has this absolute path:

/dom[@domain='stage-pp-web']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='http://stage-pp-web/patient/education.php?topic_id=1']
Attachments
ResolveWebClicker.UserCode.cs
(2.98 KiB) Downloaded 41 times

User avatar
odklizec
Ranorex Guru
Ranorex Guru
Posts: 3945
Joined: Mon Aug 13, 2012 9:54 am
Location: Zilina, Slovakia

Re: track elements by dynamic path

Post by odklizec » Wed Dec 14, 2016 6:06 pm

Hi, you can extract domain name from an element using method posted here:
http://www.ranorex.com/forum/extract-do ... tml#p41322
Pavel Kudrys
Ranorex explorer at Descartes Systems

Please add these details to your questions:
  • Ranorex Snapshot. Learn how to create one >here<
  • Ranorex xPath of problematic element(s)
  • Ranorex version
  • OS version
  • HW configuration

Vaughan.Douglas
Posts: 250
Joined: Tue Mar 24, 2015 5:05 pm
Location: Des Moines, Iowa, USA

Re: track elements by dynamic path

Post by Vaughan.Douglas » Wed Dec 14, 2016 7:02 pm

I'm starting to get a better understanding of why you're trying to do, but I think you might be over complicating things.

You're substringing out the href property:

Code: Select all

href = href.Substring(href.IndexOf('/', 8), href.Length - href.IndexOf('/', 8));
but your href is "http://stage-pp-web/patient/education.php?topic_id=1" so the 8th index is going to be an out of bounds exception, isn't it?

It seems like you might be trying to vary the href property based on an environment. For example, let's say I've got three deployment environments Dev, Stage, and Production.

The Dev domain is dev-pp-web
The Stage domain is stage-pp-web
and the prod is prod-pp-web

As a tester you need it to work in all environments... except Prod, because you're a good tester and don't run automation in a live production environment...

you need a way to parameterize the domain value

/dom[@domain='stage-pp-web']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='http://stage-pp-web/patient/education.php?topic_id=1']

To make things even more complicated you link sits in a lists in a list that can vary from time to time.

I'd probably use an Xpath like this:
/dom[@domain~'(dev|stage)-pp-web']//div[#'mCSB_1']//ul//a[@href~'http://(dev|stage)-pp-web/patient/education.php?topic_id=1']

I'm getting pulled into something else, so let me know if we're getting closer.
Doug Vaughan

mander95
Posts: 66
Joined: Tue Jun 21, 2016 7:35 pm

Re: track elements by dynamic path

Post by mander95 » Wed Dec 28, 2016 5:22 pm

In regards to looking at the domain, I wanted to look at the current working directory rather than just the directory stated in the paths for each of the repository items. The code explained in "extract domain" looks at the path that is already in the repository when that might not always be the case if I were to see the same item but in a different environment. Is there a way to make the items adjustable for any environment or be is there a way to dynamically adjust the xpath based on where your current environment is? For example this is the path for the same button but in different domains:

Button name: Abdominoplasty

/dom[@domain='stage-pp-web']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='http://stage-pp-web/patient/education.php?topic_id=1']

/dom[@domain='viewmyconsult.com']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='https://viewmyconsult.com/patient/educa ... topic_id=1']


To be more clear, the area that says 'viewmyconsult' and 'stage-pp-web' is there a way track the domain that your currently working in and build the xpath based on that domain?

mander95
Posts: 66
Joined: Tue Jun 21, 2016 7:35 pm

Re: track elements by dynamic path

Post by mander95 » Wed Dec 28, 2016 6:06 pm

Might have found a way to find a way to get the current working domain but it requires the system.object class and for some reason, Ranorex doesn't recognize that class. Why is that?

User avatar
RobinHood42
Posts: 240
Joined: Fri Jan 09, 2015 3:24 pm

Re: track elements by dynamic path

Post by RobinHood42 » Thu Dec 29, 2016 1:59 pm

Hi,

What if you create a global parameter containing the domain.
You could do a GetValue() actions, which reads out the text attribute of the address bar of the browser. The text attribute returns the whole url, but you could check the domain with a simple string compensation (for example: String.Contains method). You could set the parameter with the correct domain and use it in your rxpath.
I hope that helps.

Cheers,
Robin

Vaughan.Douglas
Posts: 250
Joined: Tue Mar 24, 2015 5:05 pm
Location: Des Moines, Iowa, USA

Re: track elements by dynamic path

Post by Vaughan.Douglas » Tue Jan 03, 2017 3:14 pm

I feel like we're running in circles here.

If you create your dom repo object with a regular expression like /dom[@domain~'(stage-pp-web|viewmyconsult.com)'] or use another property to identify the top level object then extract the actual domain value using the method provided above.

Then you can use a regular expression to see if the href property of your link contains that domain value.

The reason this is all circular is because you have to have a root level object in order to find the descendant link object. You have to actually locate the objects before you can evaluate a property of that object. The RxPath /dom[@domain~'(stage-pp-web|viewmyconsult.com)'] will identify the object if the domain is either "stage-pp-web" or "vewmyconsult.com". Once that object is identified you can check the actual domain property and it will return a domain value of either "stage-pp-web" or "vewmyconsult.com" because it can't be both.
Doug Vaughan

mander95
Posts: 66
Joined: Tue Jun 21, 2016 7:35 pm

Re: track elements by dynamic path

Post by mander95 » Wed Jan 04, 2017 7:38 pm

I'll try adding multiple domains in the rx path and see how that works, extracting the current domain from the websearch bar worked but it seems tedious, so that's why im going to try a new approach.

mander95
Posts: 66
Joined: Tue Jun 21, 2016 7:35 pm

Re: track elements by dynamic path

Post by mander95 » Wed Jan 04, 2017 11:40 pm

I think it could work but I think I'm just writing the xPath wrong, how should i write the path so that it recognized by both domains (basically, how do i combine the 2 paths in the repository):

Abdominoplasty Path 1:

/dom[@domain='stage-pp-web']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='http://stage-pp-web/patient/education.php?topic_id=1']

Abdominoplasty Path 2:

/dom[@domain='viewmyconsult.com']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='https://viewmyconsult.com
/patient/education.php?topic_id=1']

Vaughan.Douglas
Posts: 250
Joined: Tue Mar 24, 2015 5:05 pm
Location: Des Moines, Iowa, USA

Re: track elements by dynamic path

Post by Vaughan.Douglas » Thu Jan 05, 2017 1:33 pm

mander95 wrote:I think it could work but I think I'm just writing the xPath wrong, how should i write the path so that it recognized by both domains (basically, how do i combine the 2 paths in the repository):

Abdominoplasty Path 1:

/dom[@domain='stage-pp-web']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='http://stage-pp-web/patient/education.php?topic_id=1']

Abdominoplasty Path 2:

/dom[@domain='viewmyconsult.com']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='https://viewmyconsult.com
/patient/education.php?topic_id=1']
The key is using the regular expression argument ~ versus the equals argument = .

/dom[@domain='viewmyconsult.com'] and /dom[@domain='stage-pp-web'] are combined as such:

/dom[@domain~'(viewmyconsult.com|stage-pp-web)'']

The tilde (~) indicates a regular expression pattern
Wrapping things in parenthesis indicates a group
And that pipe (|) indicates an or

So we're literally saying that the domain property can match either "stage-pp-web" or "viewmyconsult.com" but no variation.

The way I would implement this in my repository is to have my root object defined as /dom[@domain~'(viewmyconsult.com|stage-pp-web)'']
and a descendant object defined for my link as
a[@href~'http(s)?://(viewmyconsult.com|stage-pp-web)/patient/education.php\?topic_id=1']
notice I escaped the question mark between education.php and topic_id=1. If you're not familiar with regular expressions, you should look into them as they are extreamly useful and occasionally endlessly frustrating.

I use a Chrome extension regular expression tester called "RegExp tester". I think Ranorex has one built in, but habits are habits if you know what I mean.

I strongly recommend you take a few minutes to read through the RxPath reference page I was competent with both regular expressions and Xpath before picking up Ranorex but Ranorex introduces a few quirks to both. I still refer back to the documentation often.

Finally your initial RxPath "/dom[@domain='stage-pp-web']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='http://stage-pp-web/patient/education.php?topic_id=1']" isn't something I'd normally consider a robust and resilient RxPath. I tend to avoid these "/?/?/" like the plague. That's not to say you must avoid them; they do serve their purpose. I tend to stick to xPath axes if for no other reason than readability.

Your RxPath
/dom[@domain='stage-pp-web']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='http://stage-pp-web/patient/education.php?topic_id=1']
could be written as
/dom[@domain='stage-pp-web']//div[#'mCSB_1']/descendant::ul/descendant::a[@href='http://stage-pp-web/patient/education.php?topic_id=1'
Without a snapshot I can't really give you a clear direction on how to create a better RxPath, so don't take the above as the best possible solution for your situation.
Doug Vaughan

mander95
Posts: 66
Joined: Tue Jun 21, 2016 7:35 pm

Re: track elements by dynamic path

Post by mander95 » Thu Jan 05, 2017 10:22 pm

I talked to another support engineer and he recommended that I just minimize the href to not include the domain at all and instead of using "@href=..." he recommended using "@href<...." and getting rid of the domain portion in the href . The original path was:

/dom[@domain='viewmyconsult.com']//div[#'mCSB_1']/?/?/ul/?/?/a[@href='https://viewmyconsult.com/patient/educa ... topic_id=1']

This is what the path is now:

//a[@href<'/patient/education.php?topic_id=1']

It works now, thank you for the assistance