0

I've got not very common task to take care of.

We need to create several test suites for some forms in one complex web application. I'm a rookie in this field and Selenium was the first (and pretty much advertised all around) tool I've tried. The problem is that all of form elements' ids/names/css path used on aforementioned pages contain random fragments which will change each and every time corresponding page is refreshed (they still contain enough of unique characters to distinguish between with certainty, with, for example, regular expressions).

When I'm telling "random with enough unique characters ", I mean something similar to that:

constant_part_1_random-fragment-new-each-time_constant_part2

Those constant parts by itself unique enough to discern different elements by them, but you can't use exact matching as the whole string changes every time. So Selenium creates test suites in full-auto mode OK, but when I try to run it - BLAM! - it doesn't work because all element locators in each step of newly composed test suite now contain already stale path/names/ids, so no element can be found.

Of course, regular expressions was the first solution that came to my mind, but I failed to comprehend can they be used in Selenium at all, and if they can, than can they be used in locators? Some people around the net tell they can't, others say they can..

Or may be it's Selenium who is flawed? May be there are better solutions of this sort which will allow me to quickly compose those test suites? Or at least will be able to use regexps to their fullest?

1

I prefer to use XPATH against CSS selectors, because in dynamic applications, the CSS can by changed. In this case, there is possibility to use Xpath locators with functions contains, starts-with, ends-with:

driver.findElement(By.XPATH, '//element[contains[@attribute,'text']]')

driver.findElement(By.XPATH, '//element[starts-with[@attribute,'text']]')

driver.findElement(By.XPATH, '//element[ends-with[@attribute,'text']]')
  • element - The HTML element
  • attribute - The HTML's inner attribute (id, class, value..etc)
  • text - Specific or unique text
0

CSS3 includes "begins with" and "ends with" test. If the two constants are enough to distinguish a node, and if they always appear at the beginning and end of an attribute, you can chain two tests together:

div[id^=constant_part_1][id$=constant_part_2]

If that doesn't work, befriend the developers and ask for ids or names that are (in order of preference):

  1. constant and human readable
  2. constant
  3. calculable

If you can't get names or ids, ask for class names--again, constant or at least calculable.

If you can't get calculable class names, the next thing to do is to find anything stable--such as the text content of descendant nodes. For that, you might need to use XPath (until CSS4's subject selector becomes widely implemented).

If you can't find stable content, the best I know how to do is to guess at DOM structure and indexes. Those are almost certainly too volatile to identify the desired elements reliably from one build to the next--or one query to the next. But I don't know how to get reliability without calculable classes, names, ids, or content.

  • Sorry, it seems I'm even more rookie than I thought.. Where should I put this? In Selenium GUI I start editing some step, I'm selecting the "css selector" for its locator ok, and now I'm given this string (literally) to edit for this type of selector: – tapestreman Jan 21 '15 at 6:17
  • This one string: "#ctl43_manager_TabControl_hereislongrandomsequence_parameter1". Where should I place those divs, should I place them in this selector string? I don't see any opportunities to choose css3 or css4, I'm only able to select "css_selector" option from the dropdown.. – tapestreman Jan 21 '15 at 6:24
  • I probably should have mentioned that these elements I'm intrested in are mostly all input fields and some buttons (like "Save", "Add"). So Selenium generated "sendKeysToElement" actions for those input fields and clickElement actions for buttons. – tapestreman Jan 21 '15 at 6:35
  • I don't know the Selenium GUI, but if it allows you to specify a CSS selector, that's where the expression goes. If div isn't right, use the appropriate element type instead. Or you can use * there to match any element. So: *[id^='ctl43_manager_TabControl'][id$='parameter1']. You don't have to select the version of CSS. Just choose 'css_selector'. If your browser implements CSS3, you can use the "begins with" and "ends with" operators. I think all modern browsers implement CSS3 these days. – Dale Emery Jan 21 '15 at 11:43
0

Do you need to select both constants, or can you get by with either? If either, you can use wildcard css attribute selectors to select an element having an attribute value starting or ending with a given string:

// find input tag having id attribute starting with 'constant1'
driver.findElement(By.CssSelector("input[id^='constant1']"))

// find input tag having id attribute ending with 'constant2'
driver.findElement(By.CssSelector("input[id$='constant2']"))

If you need both constant1 and constant2 in order to identify a given element, I'm not sure if CSS or XPath selectors can do the job. Might be easier to use javascript to find the element and give it a static attribute you can hook into with a selector.

Edit: thinking about it more, if you need both then something like this might be easiest. Find all the elements with one of the constants and loop through for the one that has the other constant:

WebElement correctElement;
List<WebElement> problemElements = driver.findElements(By.CssSelector("input[id^='constant1']"))
for (WebElement problemElement : problemElements) {
    if (problemElement.getAttribute("id").endsWith("constant2") {
        correctElement = problemElement;
        break;
     }
// now do stuff with correctElement

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.