Dynamic element id's in WebDriver - webdriver

Recently I started learning WebDriver as my client that I am working for is planning to use WebDriver for automating web applications.
I have doubts regarding how WebDriver locates the elements on webpage whose id's are dynamically changing (like changing for every login to application). Can anyone explain how we can accomplish this task with WebDriver?

Locating elements with dynamic id's can be fragile. I would rather use some visible text with for example xpath expression. My point is that in most cases the visible text is usually part of the requirements or specification of the application and id's are not. Therefore the id's are more likely to change and visible text not so.
For example to locate the username field in login form I might use xpath:
//label[.='Username']//following::input[1]
This is assuming there is a label "Username" before the input field.
I have found Firebug console function $x("xpath string") to be very useful when debugging those xpaths.

For those elements on the webpage whose ids are dynamically changing:
You can try locating the elements by their Xpath locator or CSS locator
You can find more information about the locator strategies that can be employed while using WebDriver here . Have a look at these and you would figure out the various locator strategies.
In order to understand the concept for locating dynamic elements you can have a look at the Selenium1 documents here. However pls note the api in this link is for Selenium 1. But you can use the concept and the locator strategy/api provided for the WebDriver earlier to accomplish your task

We had the same problem and we ended up using jquery selectors, especially if jquery is already available at your client-side. In the ZK framework that we use, we already have some jquery extensions so we could simply write:
assertEquals(driver.findElement(By.jq("#label:eq(0)")).getText(),"ROOT_MESSAGE");
where as the By.jq() effectively boils down to :
return (WebElement)((JavascriptExecutor)context).executeScript("return jq('" + selector + "').get(0);");

You can achieve it by using contains() method which is matched element name.
WebElement cls = (new WebDriverWait(ff, 10))
.until(ExpectedConditions.elementToBeClickable(By.xpath("//a[#class='_54nc']/span/
span[contains(text(), 'Log Out')]")));

You can try:
https://github.com/sdl/Testy/
syntax is preaty simple:
// 1. import maven dependency
// 2. init Framework in your TestBase after initializing your driver
WebDriverConfig.init(driver);
// 3. any actions based on many many attributes
WebLocator logoutBtn = new WebLocator().setText("Log Out");
// make sure the element is rendered even after fiew seconds (5 by default)
logoutBtn.assertReady();
// or do any actions with elements
logoutBtn.click();
// more properties for selecting/testing specific element with wanted attributes
WebLocator closeIcon = new WebLocator().setClasses("close").setTitle("Close");
WebLocator minimIcon = new WebLocator().setClasses("minimize").setTitle("Minimize");

Related

How to reuse page_source in Appium driver queries

I have checkForKnownExceptionScreens() function to check for all the known popup windows.
The checkForKnownExceptionScreens() performs multiple queries using Appium webdriver on various id strings. For example, it invokes multiple driver.find_elements_by_id() with different ids, it also invokes driver.find_elements_by_class_name() with different class name etc.
This results in making multiple calls to the Appium server thus to the mobile device.
To make the function efficient, I want to get get the page source XML content through driver.page_source and use the XML content within my function.
Is there a way to achieve this task?
You would have to parse that xml to find if it really contains what you need.
Easier solution would be to create a list of elements on your view and iterate trough it to see if it contains your element.
Sample (java) code:
List<AndroidElement> elementsList = driver.findElements(By.xpath(".//*"));
for(AndroidElement element : elementsList){
// check if it's your element
}

How to adjust Capybara finders on a site using css-modules?

In our automated tests, a typical line in our code might look something like:
find('.edit-icon').click
We're on our way to using css-modules in our project and I've been warned that class names may change dramatically. A pretty zany example is this site that uses emojis in its class names (when you inspect the page):
css modules by Glenn Maddern
How might I best prepare for a change this drastic? I imagine many of our specs breaking, but I am a little worried about being unable to write tests at all with this new technology in our project.
Using custom capybara selectors you can abstract away from the actual css query being done and move it to one location. In your comments you mentioned the need to change to a class attribute that begins with a passed in value.
Capybara.add_selector(:class_starts_with) do
css { |locator| "[class^=\"#{locator}\"]"
end
would do that and then can be called as
find(:class_starts_with, 'something')
or if you set Capybara.default_selector = :class_starts_with it would just be
find('something')
Rather than changing default_selector another option would be to just define a helper method like find_by_class_start or something that just calls find with :class_starts_with passed (how Capybara's #find_field, etc work).
Also note the custom selector above would only really work if only one class name was set, if multiple are expected you could change the selector to "[class^=\"#{locator}\"], [class*=\" #{locator}\"]"

Converting my existing code to PageObject design pattern with PageFactory

I'm creating tests using Selenium 2 Web Driver with C#.Net. After reading through a lot of the Selenium documentation, I am not sure if I'm followign the correct design pattern and feeling unsure on how to go about testing using PageObject design patterns.
here is my current code that I'm using on my page and its working
WaitForElement(By.CssSelector("input#ctl00_ctl00_signinControl_txtUsername")).SendKeys("abc123");
WaitForElement(By.CssSelector("input#ctl00_ctl00_signinControl_txtPassword")).SendKeys("password");
SelectElement select;
IWebElement selElement = WaitForElement(By.CssSelector("select#ctl00_ctl00_ddlGoTo"));
select = new SelectElement(selElement);
select.SelectByText("Homepage");
*<more code .....>*
also I have told that I can not use Select page element using pageFactory.
Do I need to change my code the way I have coded? any feedback would be great.
The idea of the page object pattern is to have an object that represents the page. You are essentially writing an API for how to interact with the page.
For example a login page object may have the following methods:
enterUserName(String userName);
enterPassword(String password);
clickLoginButton();
The person using the page object to interact with the page does not need to care about how selenium finds elements and interacts with them. If the id on a field changes you would just need to change the locator on the page object and would not need to change all tests that call the associated page object public method.

Executing an item in the package as a Dreamweaver Template

Does anybody know if it is possible in a compound template to use a string item in the package and execute it as if were a dreamweaver template? And whether you apply the same method to other mediators (like razor)?
Thanks
Mark
I suspect this is not possible.
Package.EvaluateExpression may be useful, but as the name suggests it'll only work on expressions, not large snippets of code with embedded expressions (i.e. TEL)
Engine.GetMediator expects a Template and returns the appropriate Mediator for it. Your problem then is that the IMediator interface only defines the Transform method, which requires an Engine, a Template and a Package.
I can't think of any elegant ways around these. Maybe write your own Mediator, but that would still expect a Package, not a string, so you'd have to first store the string based Item from another TBB.
My advice: Sounds like you need to go back to the drawing board and find an alternative solution to your problem.
I'm afraid that won't be possible on just any item in the Package, since the Engine expects Templates to be based on Tridion items.
If your Template Item is based on a Tridion Item you can probably get pretty far by starting at the Engine.GetMediator method. If it isn't, you'll have to find some way to turn it into a valid Template object.
Template template = ...
IMediator mediator = engine.GetMediator(template);
mediator.Transform(engine, template, package);
When I have to create a Component object from a Tridion-based Item in the Package, I normally do something like this:
Component component = new Component(item.GetAsXmlDocument().DocumentElement,
engine.GetSession);
I haven't tried, but expect that you can do the same for a Template - given that you start with a valid Item from the Package representing a Template to begin with. You can probably clone the XML from an existing Item or find some other way to fake it.
If you get this to work, it will work across all registered template types. The Engine provides no special treatment for the types that come with Tridion.

What is a good approach to bind an entityproxy to a UI component?

I'm currently working on a GWT project. The thing is, I find very hard to believe that I need to repeat some boilerplate over and over to bind the data from an EntityProxy (say a getSomeData() method) to a UI component (say a TextBox).
How do you guys overcome this issue? For now I have to create a method to read from the TextBox and set it to the EntityProxy, and a method to write to the TextBox after reading from the EntityProxy.
Basically, it's always the same! i.e.:
// Update the text box
T someData = entity.getSomeData();
textBox.setText(someData);
// Update the entity
String value = textBox.getText();
entity.setSomeData(value);
You get my point? I'm aware there is no Reflection at client side. I could use deffered binding but I'm not sure how or if it is a good approach with RequestFactory's EntityProxys.
Thank you
I use the technique you have defined in your question to push and collect data from my controls. Recently I have found out that there is a built-in feature of GWT called Editors. I didn't have a chance to try it myself yet but perhaps you want to check it out it seems promising. Also here is another useful link from Thomas Broyer's blog about Editors

Resources