Webdriver Selenium different behavior on different computers - c#

I wrote some code to do repetitive tasks with the Webdriver in C#.
My code works well on my PC but it is grabbing a different element on my boss's PC.
The element I'm looking for:
var InventMgmt = driver.FindElement(By.XPath("//*[#id='ROOT/Inventory Management']/div/span"));
This element is from a WebApp my company is using and it's the same across the network.
The problem is that the Webdriver is clicking a completely different element that is not listed in my code.
Both PCs are using the same Corporate OS (Windows 10), with the same browser versions.
After reviewing my code and Inspecting Element in my boss's browser, I'm starting to believe the issue can only be coming from my boss's PC...what could cause this kind of issue?
Here's the innerHTML of the elements I'm looking for and the one that are actually being clicked:
Trying to click the "Inventory Management" span:
<div id="ROOT/Inventory Management" class="x-panel x-panel-noborder x-tree x-panel-collapsed" style="width: auto;">
<div class="x-panel-header x-panel-header-noborder x-unselectable x-accordion-hd" id="ext-gen186" tabindex="0" role="tab" aria-expanded="false" style="cursor: pointer;">
<span class="x-panel-header-text" id="ext-gen190">Inventory Management</span>
</div>
</div>
Element being clicked is the div with id "ROOT/Support Table":
<div id="ROOT/Support Table" class="x-panel x-panel-noborder x-tree" style="width: auto;">
<div class="x-panel-header x-panel-header-noborder x-unselectable x-accordion-hd" id="ext-gen248" tabindex="0" role="tab" aria-expanded="true" style="cursor: pointer;">
<span class="x-panel-header-text" id="ext-gen252">Support Table</span>
</div>
</div>

You may want to check your browser 'Zoom Level'. It should be 100% for your automation to work as expected. I ran into a similar situation once.
I recommend restricting the driver from starting if zoom levels are not 100.
InternetExplorerOptions ieOptions = new InternetExplorerOptions();
ieOptions.IntroduceInstabilityByIgnoringProtectedModeSettings = true;
ieOptions.IgnoreZoomLevel = false;
IWebDriver driver = new InternetExplorerDriver(IEDriverFolder, ieOptions);

Related

How to click on an icon through xpath consistently using Selenium

Please see below the xpath expression copied from the developer tools.
//*[#id="parentDiv"]/table/tbody/tr[1]/td[8]/div/profile-link-column/a/i
I want to click on the 8th table data in first row(actually its a small icon), so this works fine 3 out of 10 times.
Can somebody suggest a more reliable approach?
This is my HTML:
<td>
<!--anchor-->
<div class="animated-slide-in au-enter-active">
<profile-link-column device-id="${value.value}" class="au-target" au-target-id="395">
<a click.trigger="viewProfile()" class="au-target" au-target-id="55">
<i class="fa fa-newspaper-o"></i>
</a>
</profile-link-column>
</div>
<!--anchor-->
<!--anchor-->
<!--anchor-->
<!--anchor-->
<!--anchor-->
</td>
Use css here
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.findElement(By.cssSelector("i.fa.fa-newspaper-o")).click
check whether it works fine, if it doesn't work, then please paste the error, If it's related to visibility error, then I think the problem is, <profile-link-column device-id="${value.value}" class="au-target" au-target-id="395"> <a click.trigger="viewProfile()" class="au-target" au-target-id="55"> <i class="fa fa-newspaper-o"></i> </a> </profile-link-column> is hidden in your html.
To click on the desired element you have to induce WebDriverWait for the element to be clickable as follows :
new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(ExpectedConditions.ElementToBeClickable(By.XPath("//td/div[#class='animated-slide-in au-enter-active']/profile-link-column[#class='au-target']/a[#class='au-target']/i[#class='fa fa-newspaper-o']"))).Click();

Handling dynamically generated elements in selenium webdriver via C#

I am trying to automate testing of a webpage that contains a list of items.
It's a button "Create" in Google Drive with expanding elements.
I have used XPath locator to find button "Create"(driver.FindElement(By.XPath("")), but I don't know how to get access to the expanded elements and click on them by using C# and webdriver.
Here is the code below. Help me, please.
`<div tabindex="0" class="j-Ta-pb f-e f-e-dg a-Da-e" role="button" aria-label="Создать" style="-moz-user-select: none;" guidedhelpid="new_menu_button" aria-expanded="false" aria-haspopup="true">
<div class="j-Ta-pb f-e-og-aa">
<div class="j-Ta-pb f-e-qb-aa">
<div class="j-Ta-pb f-e-rf" aria-hidden="true">Создать</div>
<div class="j-Ta-pb f-e-Tc"> </div></div></div></div>`
You should base on static part. Assuming j-Ta-pb is static/unchanged all the time, you could use this xpath
//div[contains(#class, 'j-Ta-pb')]

WebDriver reporting child div as "Not Visible" after parent div has been moved too far up, on scrolling SPA

The webpage in question is an SPA, I could describe it as a single large div with several div "boards" inside it, which we scroll into view by applying a webkit transform on the parent div.
Unfortunately, once scrolled too far, the elements returned by WebDriver are "disabled" - the WebElement property "Displayed" is false, the Text property is blank, and I can't execute any clicks/actions on the element. It is however visible on the page at the time and perfectly functional.
While investigating the problem, I created a small test webpage to see under what conditions this occurs.
Link to JSFiddle sample page to show functionality
NB Note that we are not using IFrames in this website, JSFiddle is just to demonstrate functionality.
<html><head>
<script type="text/javascript" src="jquery-1.8.3.js"></script>
<style type="text/css">
.board-nav {
font-size: 12px;
color: #1b1a1a;
margin-right: 10px;
vertical-align: middle;
}
.scroller{
-webkit-transition: -webkit-transform 0ms; transition: -webkit-transform 0ms;
-webkit-transform-origin: 0px 0px;
-webkit-transform: translate(0px, 0px) scale(1) translateZ(0px);
transition-property: transform;
transform-origin: 0px 0px 0px;
transform: translate(0px, 0px) scale(1) translateZ(0px);
height: 4000px;
}
</style>
<script type="text/javascript">
var boardPositions = [0, -878, -1748, -2598, -3468];
var $scroller = null;
function changeBoard(event) {
var newValue = 'translate(0px, ' + boardPositions[event.target.id] + 'px) scale(1) translateZ(0px)';
$('.scroller').css('-webkit-transform',newValue);
$('.scroller').css('transform', newValue);
}
$(document).ready( function(){
var $boards = $('.board-nav');
$boards.on('click', changeBoard);
});
</script>
</head><body>
<div>
<div class="board-nav" id="0">Info</div>
<div class="board-nav" id="1">Board1</div>
<div class="board-nav" id="2">Board2</div>
<div class="board-nav" id="3">Board3</div>
<div class="board-nav" id="4">Board4</div>
</div>
<div id="content" style="width:1612px; height:864px; position:absolute; left:58px; overflow:hidden">
<div class="scroller">
<ul class="vertical">
<li class="v" id="li0">
<div class="target"><span>Info</span></div>
</li>
<li class="v" id="li1">
<div class="target"><span>Board1</span></div>
</li>
<li class="v" id="li2">
<div class="target"><span>Board2</span></div>
</li>
<li class="v" id="li3">
<div class="target"><span>Board3</span></div>
</li>
<li class="v" id="li4">
<div class="target"><span>Board4</span></div>
</li>
</ul>
</div>
</div>
</body></html>
It seems that as soon as the parent div Y location becomes less than around -2000, all child elements become "disabled" in this manner. Prior to this (around -1900 for example), the elements are returned with all information valid. I can switch from Board 3, back to Board 2, and then all elements are returned correctly again. Back to Board 3 - all boards "disabled". So this seems to be a browser WebDriver limitation.
WebDriver C# test code :
var driver = new FirefoxDriver();
driver.Manage().Window.Maximize();
driver.Navigate().GoToUrl("testpage.html");
var elements = driver.FindElements(By.ClassName("v"));
return elements[3].FindElement(By.TagName("span")).Text;
Firefox handles this the best - it at least shows Info/Board1/Board2 before giving up. Chrome doesn't handle any of the Boards, returning the same Displayed = false, blank Text for all boards.
So my question is - is there any way to get around this? I can test the text on the other boards are correct, while Board1/Info is showing, but won't be able to interact with the last 2 Boards.
ANSWER:
Just resolved my problem by adding a height attribute to the parent div "scroller" element - my guess is WebDriver couldn't determine the height of the parent div and so assumed beyond a certain location it was no longer visible.
I've updated the code above and JSFiddle with the solution
I guess this happens Firefox and IE, but not Chrome? If so, then we are experiencing the similar issue. I suspect Chrome doesn't care about the WebDriver W3C standards and determines the visibility in a slightly different way.
If this answer is not related to your question, I hope it will still be beneficial for those find this through search engine.
The issue I'm facing is that Selenium returns elements as invisible, but real end users can see and perform actions without any issues. The best solution here would be change site's source code to make Selenium's FirefoxDriver and InternetExplorerDriver happy. As this is related to elements' positions and overlapping, which seems pretty hard to reproduce and fix.
However, apart from that, here are few workarounds and hacks through Selenium might be helpful.
Use element.GetAttribute("textContent") instead of element.Text for those invisible elements
return elements[3].FindElement(By.TagName("span")).GetAttribute("textContent");
Use Actions click or JavaScript click, instead of normal click. For example, if you need this method many time, you might want to create extension methods for either IWebElement or IWebDriver.
// example of JavaScriptClick extension method for IWebDriver
// use as driver.JavaScriptClick(element);
// or you can make it IWebElement's extension and pass in IWebDriver
// or just create a normal method and pass in both driver and element
public static void JavaScriptClick(this IWebDriver driver, IWebElement element) {
IJavaScriptExecutor executor = driver as IJavaScriptExecutor;
executor.ExecuteScript("arguments[0].click();", element);
}
public static void ActionsClick(this IWebDriver driver, IWebElement element) {
new Actions(driver).Click(element).Perform();
}
Related reading:
W3C WebDriver Standards - Determining Visibility
Why does the Selenium Firefox Driver consider my modal not displayed when the parent has overflow:hidden?
“Element is not currently visible and so may not be interacted with” but another is?
Selenium dom.js source

"Element is not currently visible and so may not be interacted with" but another is?

I've created another question which I think is the cause for this error: Why does the Selenium Firefox Driver consider my modal not displayed when the parent has overflow:hidden?
Selenium version 2.33.0
Firefox driver
The code that causes the error:
System.Threading.Thread.Sleep(5000);
var dimentions = driver.Manage().Window.Size;
var field = driver.FindElement(By.Id("addEmployees-password")); //displayed is true
field.Click(); //works fine
var element = driver.FindElement(By.Id(buttonName)); //displayed is false
element.Click(); //errors out
The button that its trying to click:
<div id="addEmployees" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="addEmployeesLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3>Add Employee</h3>
</div>
<div class="modal-body">
<p class="alert alert-info">
<input name="addEmployees-username" id="addEmployees-username" />
<input name="addEmployees-password" id="addEmployees-password" type="password" />
<input name="addEmployees-employee" id="addEmployees-employee" />
</p>
</div>
<div class="modal-footer">
<button name="addEmployees-add" id="addEmployees-add" type="button" class="btn" data-ng-click="submit()">Add</button>
</div>
</div>
If I change the call to FindElements then I get ONE element, so there isn't anything else on the page.
If I FindElement on a field that occurs right before the button, say addEmployees-employee, then addEmployees-employee is displayed
In the browser itself, it shows up fine, all i need to do is actually click the button and the desired behavior executes, but the webdriver refuses to consider the element displayed
How is it that one field can be considered displayed and the other is not?
The modal with the add button in the bottom right, all the other elements are displayed = true
The window size is 1200x645 per driver.Manage().Window.Size;
The element location is: 800x355y per driver.FindElement(By.Id(buttonName)).Location
The element dimentions are: 51x30 per driver.FindElement(By.Id(buttonName)).Size
The password element location is: 552x233y per driver.FindElement(By.Id("addEmployees-password")).Size
Brian's response was right: use an explicit wait versus Thread.Sleep(). Sleep() is generally brittle, you're losing five seconds needlessly, and moreover it's just a really rotten practice for automated testing. (It took me a long, LONG time to learn that, so you're not alone there.)
Avoid implicit waits. They generally work for new items being added to the DOM, not for transitions for things like a modal to become active.
Explicit waits have a great set of ExpectedConditions (detailed in the Javadox) which can get you past these problems. Use the ExpectedCondition which matches the state you need for your next action.
Also, see Ian Rose's great blogpost on the topic, too.
Selenium WebDriver does not just check for opacity != 0, visibility = true, height > 0 and display != none on the current element in question, but it also searches up the DOM's ancestor chain to ensure that there are no parent elements that also match these checkers.
(UPDATE After looking at the JSON wire code that all the bindings refer back to, SWD also requires overflow != hidden, as well as a few other cases.)
I would do two things before restructuring the code as #Brian suggests.
Ensure that the "div.modal_footer" element does not have any reason for SWD to consider it to not be visible.
Inject some Javascript to highlight the element in question in your browser so you know absolutely you have selected the right element. You can use this gist as a starting point. If the button is highlighted in a yellow border, then you know you have the right element selected. If not, it means that the element selected is located elsewhere in the DOM. If this is the case, you probably don't have unique IDs as you would expect, which makes manipulation of the DOM very confusing.
If I had to guess, I would say that number two is what you are running into. This has happened to me as well, where a Dev reused an element ID, causing contention in which element you're supposed to find.
After discussing this with you in chat, I think the best solution (for now, at least) is to move the button out of the footer for your modal and into the body of it.
This is what you want (for now):
<div class="modal-body">
<p class="alert alert-info">
<input name="addEmployees-username" id="addEmployees-username" />
<input name="addEmployees-password" id="addEmployees-password" type="password" />
<input name="addEmployees-employee" id="addEmployees-employee" />
<button name="addEmployees-add" id="addEmployees-add" type="button" class="btn" data-ng-click="submit()">Add</button>
</p>
</div>
And not this:
<div class="modal-body">
<p class="alert alert-info">
<input name="addEmployees-username" id="addEmployees-username" />
<input name="addEmployees-password" id="addEmployees-password" type="password" />
<input name="addEmployees-employee" id="addEmployees-employee" />
</p>
</div>
<div class="modal-footer">
<button name="addEmployees-add" id="addEmployees-add" type="button" class="btn" data-ng-click="submit()">Add</button>
</div>
I had the same issue of element not visible so cannot be interacted with. it just got solved. i updated my selenium stand alone server. previous version was 2.33.0 and now it is 2.35.0
In my case the element was already present in the page but it was disabled,
so this didn't work (python):
wait.until(lambda driver: driver.find_element_by_id("myBtn"))
driver.find_element_by_id("myBtn").click()
it failed with error:
“Element is not currently visible and so may not be interacted with"
To solve my problem, I had to wait a couple of seconds ( time.sleep(5) ) until the element became visible.
You can also enable the element using JavaScript, a python example:
driver.execute_script("document.getElementById('myBtn').disabled='' ")
driver.execute_script("document.getElementById('myBtn').click() ")

unable to click element with value zero

I am trying to click on the div tag that has id="0". Although it can find that id, unable to click on it. clicking on other ids work.
This was working in Firefox 12 but failing in 13
I am using Selenium2 with C#
driver.FindElement(By.XPath("//div[#class='MenuItem' and #id='0']")).Click();
<div style="position: absolute; top: 72px; left: 9px; " id="file" class="Menu">
<div class="MenuItem" id="0"> <img src="images/UI/Icons/folder.png">Folder</div>
<div class="MenuItem" id="1"> <img valign="middle" src="images/UI/Icons/tree/folderBlogClosed.png">Blog</div>
<div class="MenuItem" id="2"> <img valign="middle" src="images/UI/Icons/folderBoard.png">Discussion Board</div>
</div>
Elements with ID attributes that start with numbers are invalid HTML. While most browsers will render this just fine, it's entirely possible that attempting to use JavaScript to locate the element by the ID (as Selenium WebDriver does) will fail.
Is there a reason you're using an XPath and not just selecting by the ID?
driver.FindElement(By.Id("0"));
HTML id's should be unique on a page.
I resolved this issue by using mouse actions
. Thank you all for your input.
Actions builder = new Actions(driver);
IWebElement tagElement = driver.FindElement(By.XPath("//div[#id='0' and #class='MenuItem']"));
//mouse hover on first item
builder.MoveToElement(tagElement).Perform();
//click on first item
driver.FindElement(By.XPath("//div[#id='0' and #class='MenuItem']")).Click();

Categories

Resources