Is it possible to locate element by partial id match in Selenium - selenium

I am trying to locate elements with generated ids wherein some part of the ID is known; for example:
id="page_x002e_x0023_default-create-firstname"
in which the last 3 words (_default-create-firstname) are known but anything preceding that is subject to change.
Is this possible?

You can apply an ends-with CSS selector:
By.cssSelector("[id$=default-create-firstname]")
Update
Some time went by since the answer was posted. Here some update from the linked mozilla developer page and comments below:
New use By.css instead of By.cssSelector
By.css("[id$=default-create-firstname]")
Also see the four possibilities of
beginning with
anywhere inside
anywhere inside regardless capitalization
end with
/* Internal links, beginning with "#" */
a[href^="#"] {
background-color: gold;
}
/* Links with "example" anywhere in the URL */
a[href*="example"] {
background-color: silver;
}
/* Links with "insensitive" anywhere in the URL,
regardless of capitalization */
a[href*="insensitive" i] {
color: cyan;
}
/* Links that end in ".org" */
a[href$=".org"] {
color: red;
}

If you want to go down the xpath route then you could use contains(), like this:
//*[contains(#id,'_default-create-firstname')]
This will search the entire page for an id that contains the text "_default-create-firstname". It can be easily made more specific

You can try out this in Java-Selenium: you can use either ends-with() or contains(). I think Both should work.
driver.findElement(By.xpath("//*[ends-with(#id,'_default-create-firstname')]"));
driver.findElement(By.xpath("//*[contains(#id, '_default-create-firstname')]"));

This works with selenium vba
.FindElementsByXPath( "//*[contains(#class, 'unique-string')]" )

Work one
driver.find_element_by_xpath("//*[contains(#id, 'jobs-search-box-keyword-id')]")
Not work ones, all got the same error, TypeError: 'str' object is not callable
1. driver.find_element(By.XPATH("//*[contains(#id, 'jobs-search-box-keyword-id')]")).text
2. driver.find_element(By.XPATH("//*[contains(#id, 'jobs-search-box-keyword-id')]").text).text
3. driver.find_element(By.XPATH("//*[contains(#id, 'jobs-search-box-keyword-id')]")).get_attribute("innerHTML")
4. driver.find_element(By.XPATH("//*[contains(#id, 'jobs-search-box-keyword-id')]").get_attribute("innerHTML")).get_attribute("innerHTML")
I use python 3.7.6, selenium 3.141.0

I use: a[id*='example']
when my ID is something like example_12

Related

Materialize select element will not show passed options (empty ul)

My question is probably really easy. I want to populate a Materialize select element with a few options. I don't want to put my options in the HTML, I want to do it from a JSON with javascript (I get the json from a different service). In my HTML file, I just have an empty select.
In the documentation, I see that during the select initalization, you can pass an options object. I assume this can be used to populate the select dropdown. A bit lower it is stated that the correct key is dropdownOptions, and you are supposed to pass an UL to it. I did so, but the UL is empty. Console log shows that the ul is built correctly. What am I missing?
let ul = document.createElement("ul");
arr.forEach(oddelek => {
let li = document.createElement("li");
li.appendChild(document.createTextNode("Four"));
ul.appendChild(li);
});
console.log(ul); // looks good
M.FormSelect.init(selects, {
"dropdownOptions": ul
});
What could be the reason that only an empty ul appears?
Because the above code didn't work, I decided to just add the elements to the HTML with javascript, and then run the init with an empty options object. But it doesn't work, the dropdown is still empty.
The init with empty options object works perfectly if the items are added manually in the html, but does not work if they are added through javascript. I have no idea why, I call the init after I add the elements. Inspecting the resulting html without the init looks just like in the documentation. Any advice?

How to select the element in HTML tags based on its text in Behat?

I'm running the following Behat scenario:
Then I should see "Testing body" in the "strong" element
for the following HTML snippet:
<strong>Testing body</strong>
However I am getting an error:
The text "Testing body" was not found in the text of the element matching css "strong"
What is the best way to check if element contains below tags?
<em>Testing body</em>
<ol><li>Testing body</li>
</ol>
<ul><li>Testing body​​​​​​​</li>
</ul>
I am trying to use wysiwyg.feature with syntax:
Then I should see "Testing body" in the "<Element>" element with the "<Property>" CSS property set to "<Value>" in the "Pearson Content" region
Make sure the selector used is unique.
Depending on the method used you might need id|name|label|value or css selector.
I your case the selector used is too general, you need to narrow the section by adding an extra element in front of this to tell him to search in a smaller section.
For example: #myid strong -> will search strong in the element that has the id myid
Same thing for the other elements, you could have ol>li or ul>li, but if more elements are found you will need to add an extra selector in front to narrow the section.
Always check the CSS manually in the browser and make sure is unique or the element that you need is found first.
If you want to check for an element that contains some text, you could use XPath like this:
//strong[contains(text(), 'Testing body')]
You can also use a css if you can identify this section as I said above, but I need more from the html, a large section in order to get a better selector.
The following method may help:
/**
* #Given I should see :text in the :tag element
*/
public function iShouldSeeInTheElement($text, $tag) {
$this->verifyElementByXpath("//${tag}[contains(text(), '${text}')]");
}
Instead of contains, you can also use starts-with and other.
Note: I haven't tested it, so please suggest improvements if you do.

How to identify and switch to the frame in selenium webdriver when frame does not have id

Can anyone tell me how I can identify and switch to the iframe which has only a title?
<iframe frameborder="0" style="border: 0px none; width: 100%; height: 356px; min-width: 0px; min-height: 0px; overflow: auto;" dojoattachpoint="frame" title="Fill Quote" src="https://tssstrpms501.corp.trelleborg.com:12001/teamworks/process.lsw?zWorkflowState=1&zTaskId=4581&zResetContext=true&coachDebugTrace=none">
I have tried by below code but it is not working
driver.switchTo().frame(driver.findElement(By.tagName("iframe")));
driver.switchTo().frame() has multiple overloads.
driver.switchTo().frame(name_or_id)
Here your iframe doesn't have id or name, so not for you.
driver.switchTo().frame(index)
This is the last option to choose, because using index is not stable enough as you could imagine. If this is your only iframe in the page, try driver.switchTo().frame(0)
driver.switchTo().frame(iframe_element)
The most common one. You locate your iframe like other elements, then pass it into the method.
Here locating it by title attributes seems to be the best.
driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[title='Fill Quote']")));
// driver.switchTo().frame(driver.findElement(By.xpath(".//iframe[#title='Fill Quote']")));
you can use cssSelector,
driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[title='Fill Quote']")));
You also can use src to switch to frame, here is what you can use:
driver.switchTo().frame(driver.findElement(By.xpath(".//iframe[#src='https://tssstrpms501.corp.trelleborg.com:12001/teamworks/process.lsw?zWorkflowState=1&zTaskId=4581&zResetContext=true&coachDebugTrace=none']")));
Make sure you switch to default content before switching to frame:
driver.switchTo().defaultContent();
driver.switchTo().frame(x);
x can be the frame number or you can do a driver.findlement and use any of the options you have available eg: driver.findElementByName("Name").
1) goto html view
2) type iframe and find your required frame and count the value and switch to it using
oASelFW.driver.switchTo().frame(2);
if it is first frame then use oASelFW.driver.switchTo().frame(0);
if it is second frame then use oASelFW.driver.switchTo().frame(1); respectively
You can use Css Selector or Xpath:
Approach 1 : CSS Selector
driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[title='Fill Quote']")));
Approach 2 : Xpath
driver.switchTo().frame(driver.findElement(By.xpath("//iframe[#title='Fill Quote']")));
https://seleniumatfingertips.wordpress.com/2016/07/05/handling-frames-in-selenium-webdriver-with-java/
Easiest way of doing this is like this. If its a frame you can right click on the field and if you see the choice of "open frame in a tab" do it.
Then take the URL of the frame and that is what you put in your Python script using "driver.get (http://blah blah..)
Then Selenium can find your named element. This saved me hours of trying all the suggestions here which was learning about but didn't work. Problem with mine was it was in a frame.
I'm using Linux which gives me the right-click option of opening the frame, on its own, in another tab. I don't use Windows so don't know if you would get that option in you right-click menu.
Ganzarola
I struggled with this for a while; a particularly frustrating website had several nested frames throughout the site. I couldn't find any way to identify the frames- no name, id, xpath, css selector- nothing.
Eventually I realised that frames are numbered with the top level being frame(0) the second frame(1) etc.
As I still didn't know which frame the element I needed was sitting in, I wrote a for loop to start from 0 and cycle to 50 continually moving to the next frame and attempting to access my required element; if it failed I got it to print a message and continue.
Spent too much time on this problem for such a simple solution -_-
driver.switch_to.default_content()
for x in range(50):
try:
driver.switch_to.frame(x)
driver.find_element_by_xpath("//*[#id='23']").click()
driver.find_element_by_xpath("/html/body/form/table/tbody/tr[1]/td/ul/li[49]/a").click()
except:
print("It's not: ", x)
continue
There are three ways to switch to the frame
1)Can use id
2)Can use name of the frame
3)Can use WebElement of the frame
2->driver.switchTo().frame("name of the frame");
I think I can add something here.
Situation I faced
I cannot or not easily use the debug tools or inspection tools like firebug to see which frame I am currently at and want to go to.
The XPATH/CSS selector etc. that the inspection tool told me doesn't work since the current frame is not the target one. e.g. I need to first switch to a sub-frame to be able to access/locate the element from XPATH or any other reference.
In short, the find_element() or find_elements() method doesn't apply in my case.
Wait Wait! not exactly
unless we use some fazzy search method.
use find_elements() with contains(#id,"frame") to filter out the potential frames.
e.g.
driver.find_elements(By.XPATH,'//*[contains(#id,"frame")]')
Then use switchTo() to switch to that frame and hopefully the underlying XPATH for your target element can be accessed this time.
If you're similar unlucky like me, iteration might need to be done for the found frames and even iterate deeper in more layers.
e.g.
This is the piece I use.
try:
elf1 = mydriver.find_elements(By.XPATH,'//*[contains(#id,"rame")]')
mydriver.switch_to_frame(elf1[1])
elf2 = mydriver.find_elements(By.XPATH,'//*[contains(#id,"rame")]')
mydriver.switch_to_frame(elf2[2])
len(mydriver.page_source) ## size of source tell whether I am in the right frame
I try out different switch_to_frame(elf1[x])/switch_to_frame(elf2[x]) combinations and finally found the wanted element by the XPATH I found from the inspection tool in browser.
try:
element = WebDriverWait(mydriver, 10).until(
EC.presence_of_element_located((By.XPATH, '//*[#id="C4_W16_V17_ZSRV-HOME"]'))
)
#Click the link
element.click()
I could solve that with the following code
browser.switch_to.frame(browser.find_element_by_tag_name('iframe'))

getAttribute not returning complete value for style in selenium

I am using the selenium getAttribute("style") method on the following id element:-
<div id="ntsDiv_1" style="width: 250px; text-align: left; white-space: normal; top: 1090px; left: 131px; visibility: hidden;" class="mlt-pop-container">
but the API is returning only the half of the value. It is returning width: 250px; text-align: left; white-space: normal; and the remaning portion of the style is clipped.
I'm trying to extract the value of the visibility, but the method is not returning the complete value of style. Hence, i am unable to determine the correct value of visibility.
I executed System.out.println("Style is:- "+super.getElement(NEXTAG_STORES_DIV).getAttribute("style"));
NEXTAG_STORES_DIV corresponds to the xpath of the id element, and super.getElement extracts element by xpath
Please help me out!!
I just tried this with Selenium 2.30.0 and it works fine, the whole attribute is returned.
Try the following things (all the examples assume element is the WebElement you need to test):
Make really sure only a part of the attribute is returned. Aren't you just printing it into console? Many consoles have a limited line length. Try setting your console to show long lines. Check programatically the length of the returned value, or try evaluating
element.getAttribute("style").contains("visibility")
Try upgrading your Selenium library, if you can. I am not aware of any bug related to attribute getting, but there might have been some which is now (with version 2.30.0) solved.
Try it in a different browser / OS / architecture. If it works somewhere, you'll know it's an issue of a particular browser / driver / OS / architecture / whatever and you might be able to focus it down and either fix it or file a bug.
If you simply want to know whether an element is visible or not, the correct and generally preferred way is to call
element.isDisplayed()
This method takes care of all the rules you might need to inspect in order to determine whether it actually is visible or not.
If the style value changes dynamically on the page (i.e. it's not statically written in the source code of the page), WebDriver can't really see it as it doesn't pick up dynamic changes. Try accessing the value via JavaScript:
if (!driver instanceof JavascriptExecutor) {
throw new IllegalStateException("JavaScript not enabled for this driver!");
}
JavascriptExecutor js = (JavascriptExecutor)driver;
String styleAttribute = (String)js.executeScript("return arguments[0].style", element);
If you actually need to get the computed value of the CSS visibility attribute that is actually used by the browser and not the one in the style atribute (if there either isn't any or is somehow overridden), you need to use the JavaScript's getComputedStyle() method. One way (described by this article on quirksmode.org) is this:
var elem = arguments[0];
if (elem.currentStyle) {
var vis = elem.currentStyle['visibility'];
} else {
var vis = document.defaultView.getComputedStyle(elem, null).getPropertyValue('visibility');
}
return vis;
Again, this should be invoked via
String visibility = (String)js.executeScript(here_goes_the_whole_script, element);

MVC3 WebGrid Formatting or Styling Column Headers

I'm using the new MVC3 WebGrid. So far so good, just having issues styling/formatting the column headers. The best I've got is a workaround that applies the same css class from the first row of the WebGrid to the table header.
var headerCells = $("#grid tr:eq(0) th");
var firstRowCells = $("#grid tr:eq(1) td");
$.each(firstRowCells, function (index, value) {
$(headerCells[index]).addClass($(firstRowCells[index]).attr("class"));
});
This example obviously lacks a check to make sure there are rows or indeed the specifed element id, but it applies the css class from the first row to the header row meaning you can style independently of each other.
td.my-column-style { width:100px }
th.my-column-style { text-align:right;}
Is there a built in way of styling the column header elements (not just using the headerStyle property)?
No, as of now there is no built-in way to style the header cells independently, only the header row via the headerStyle property.
I think your workaround is good enough.
I know this is an old question, but this may be useful to viewers who stumble across it.
The :nth-child css pseudo selector is your friend, if you don't want to rely on javascript to copy the classes. It is easy to add a class to your webgrid using the tableStyle property, and then you can style the individual headers with the following bit of css:
.webgridclass tr th:nth-child(1){
background:#ff0;
}
.webgridclass tr th:nth-child(2){
background:#f60;
}
Unfortunately, this is not supported in IE8 and earlier IE, but it does have full support in all proper browsers (newer than FF3).
We can do this using of Javascript code as below.
JsFiddle Example
$("table tr th:nth-child(n)").addClass("col-md-1");