I have a set of common methods which I run for each test. Like I need to add a few items in my cart and the whole test runs for each item. But for the first item it runs fine and when the process is repeated for the second item it fails while verifying a text and I get a StaleElementReferenceException.
How do I look up the item again or solve this ? Thanks.
Code where it fails:
public bool VerifyItemPresentInCart()
{
//Get the cartsize and verify if one item present
IWebElement cartSize = driver.FindElement(By.CssSelector("div[class='cart-size']>div"));
string actualMsg = cartSize.Text;
string expectedMsg = "1";
VerifyIfTextPresentMethod(expectedMsg,actualMsg);
return true;
}
Error at
IWebElement cartSize = driver.FindElement(By.CssSelector("div[class='cart-size']>div"));
Update: html code
<a class="header-button show-cart has-cart-items" data-view-name="cart-badge" data-view-cid="view5" data-model-cid="c6" data-tappable="true">
Cart
<div class="cart-size">
<div>3</div>
</div>
New code:
IWebElement cardDetails = driver.FindElement(By.CssSelector("div[class='form-field clear-fix']>label[for='cardNumber']>div"));
I would try joining your lines of code:
IWebElement cartSize = driver.FindElement(By.CssSelector("div[class='cart-size']>div"));
string actualMsg = cartSize.Text;
So that they are:
string actualMsg = driver.FindElement(By.CssSelector("div[class='cart-size']>div")).Text;
This means that the text will be retrieved on the element as it is selected. I am wondering if between getting a handle on the element via its parent and retrieving the text you are losing focus on that element. Alternatively, remove the >div from your css and see if it retrieves the text anyway.
This not working suggests the situation you are facing is the point under the title The Element is not Attached to the DOM. The fact that your target text is within only divs suggests that this area is being styled by javascript and thus may only be active at certain times. If this element is not active, but is accessible, you can still receive the StaleElementReferenceException, as indicated at that page. Your next step would be to see if you can click a parenting div to activate this target div prior to accessing its text (eg. make sure the element is attached to the DOM then call the code you have provided).
Related
I am trying to locate a dropdown menu button from the following website:
Inspect Element snippet of 'CRO Dashboard DropDown Menu'
My aim is to locate the dropdown button element and click it to open the menu to then continue other operations on it.
The following error occurs when trying to locate the dropdown menu button by id:
OpenQA.Selenium.NoSuchElementException: 'no such element: Unable to locate element: {"method":"css selector","selector":"#dashboardSelectorLink"}
Referring to the image, from the highlighted part I tried to use various locators like finding element by id, css selector, class names, and even xpath but still the program could not locate it so that I can click the element.
Here is some of the code I tried:
dropdown = FindElementByCSS(dropdown, ".ms-crm-ImageStrip-Dropdown_Arrow");
dropdown = FindElementByXPath(dropdown, "//a[#id='dashboardSelectorLink']/span[2]/img");
dropdown = driver.FindElement(By.CssSelector("a[id=\"dashboardSelectorLink\"]"));
dropdown = FindElementByID(dropdown, "dashboardSelectorLink");
dropdown = FindElementByXPath(dropdown, "//cssclass[#id='dashboardSelectorLink']");
dropdown = FindElementByCSS(dropdown, "cssclass[id = 'dashboardSelectorLink']");
dropdown = FindElementByID(dropdown, "dashboardSelectorLink");
dropdown = FindElementByClass(dropdown, "cssclass[id= 'dashboardSelectorLink']");
dropdown = FindElementByID(dropdown, "dashboardSelectorContainer");
The variable 'dropdown' is of IWebElement type and I am using a chrome driver for Selenium C#.
For context, the code is in the following function:
public void EnterDashboardArea()
{
IWebElement navbtn = null;
IWebElement category = null;
IWebElement dropdown = null;
navbtn = FindElementByID(navbtn, "Tab1");
ClickElement(navbtn);
category = FindElementByID(category, "MNG");
ClickElement(category);
Thread.Sleep(5000); //pausing the program so the page fully loads and all elements appear
dropdown = driver.FindElement(By.CssSelector("img[class='ms-crm-ImageStrip-Dropdown_Arrow']"));
ClickElement(dropdown);
}
In the function EnterDashboardArea(), the web elements initially are set to none where they are then filled by the functions 'FindElementByX' as they return an element value.
The functions 'FindElementByX' are created by myself, one e.g. is:
public IWebElement FindElementByID(IWebElement ele, string id) {
ele = driver.FindElement(By.Id(id));
return ele;
}
I even tried installing the selenium chrome extension in order to locate the target exactly but still no success.
What can I do please? - Thanks
Could it be that you are trying to retrieve the element before the element has been loaded into the DOM? Try to set a timeout before reading the element.
Also: is the element contained within a container that is initially hidden, before you open it? Maybe you have to click some button that shows the container and the target element within, before trying to read the element.
I've got a webpage with a button which Selenium keeps insisting is not visible, although it most definitely is.
The page source:
<button id="product-catalog-page_order-selected-button" class="btn btn-grey
mq-apla-button opens-overlay" data-bind="click: runOrderWizard, enable:
hasSelection"><span localize-me="">Order Selected</span></button>
<span localize-me="">Order Selected</span>
Below this, there is a dynamic table with a list of entries. The entries have a checkbox in the first cell. Before checking this box, the above button is disabled. However, immediately after clicking it the button is enabled.
I've tried accessing (clicking) this button with both the ID and the XPath. I've tried the XPath for both the <button and the <span elements. Every time I try, I get this error:
Result StackTrace:
at OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError(Response
errorResponse)
at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String
driverCommandToExecute, Dictionary`2 parameters)
at OpenQA.Selenium.Remote.RemoteWebElement.Click()
at Common.Navigation.Elements.Button.ClickById(String id) in d:\Source
\Workspaces\QA\NewMySite\Common\Elements\PageElements.cs:line 51
at MyAutomation.Pages.NewOrderPage.OrderSelected() in d:\Source
\Workspaces\QA\NewMySite\MyAutomation\Pages\NewOrderPage.cs:line 36
at Tests.RegressionTests.Ordering.Ordering.User_Order_New_Hardware() in
d:\Source\Workspaces\QA\NewMySite\Tests\RegressionTests\Ordering
\Ordering.cs:line 29
Result Message:
Test method
Tests.RegressionTests.Ordering.Ordering.User_Order_New_Hardware threw
exception:
OpenQA.Selenium.ElementNotVisibleException: **element not visible**
(Session info: chrome=62.0.3202.94)
(Driver info: chromedriver=2.33.506120
(e3e53437346286c0bc2d2dc9aa4915ba81d9023f),platform=Windows NT 10.0.15063
x86_64)
I've also stopped the Selenium test immediately after the checkbox is clicked and before the button is clicked (there's a 3 sec. hard wait). Then I've manually tried to click the button, and it works fine.
There are no duplicate IDs, either; Only one element has this ID on the page.
Any ideas what I'm doing wrong here, or how to get around this if it's Selenium being dumb?
Here's the relevant program/test code:
Button.ClickById("product-catalog-page_order-selected-button"));
public class Button {
public static void ClickById (string id) {
FindById(id).Click();
}
private static IWebElement FindById (string id) {
return GCDriver.Instance.FindElement(By.Id(id));
}
}
I've also tried waiting for the element to be visible, using this code. No luck. The wait just times out.
Wait.WaitForVisibleId("product-catalog-page_order-selected-button");
public class Wait {
public static void WaitForVisibleId (string id) {
GCDriver.WaitForVisibleId(id);
}
}
public class GCDriver {
public static void WaitForVisibleId (string id) {
var wait = new WebDriverWait(GCDriver.Instance,
TimeSpan.FromSeconds(30));
wait.Until(driver => driver.FindElement(By.Id(id)).Displayed);
}
}
A while back, I had another button on this very site that I couldn't access with Selenium. That was a file upload button. I don't remember the Exception, but I solved that one with this code:
public static void ActionsUploadButtonId (string id, string filepath) {
Actions actions = new Actions(GCDriver.Instance);
actions.MoveToElement(GCDriver.Instance.FindElement(By.Id(id)));
actions.Click();
actions.Build().Perform();
}
This doesn't work here, though. It seems to do something, though: When I feed the ID of the problematic button ("product-catalog-page_order-selected-button") to that method, it selects the VERY FIRST clickable element on the page, which is the Front Page link, with its own unique ID, located several hundred lines of HTML code above the element with the actual ID.
Update
To troubleshoot, I followed a tip I found in another thread on Stack Overflow: To use Submit() instead of Clic(). However, that resulted in another (probably logical) exception:
OpenQA.Selenium.NoSuchElementException: no such element: Element was not in a form, so could not submit.
Update 2
I also tried getting the button by the class. There are two button with the exact same classes, but maybe it then would get the first one? Anyway, that results in the exact same ElementNotVisible exception.
Update 3
Both waiting for visible and waiting for clickable times out.
wait.Until(driver => driver.FindElement(By.Id(id)).Displayed);
wait.Until(ExpectedConditions.ElementToBeClickable(By.Id(id)));
Update 4
The html code for the checkbox (which enables the button when selected):
<td class="table-column-checkbox">
<input type="checkbox" data-bind="checked: $parent.selected, checkedValue: href" value="/Api/CatalogProducts/ProductOfferings/PO-6E32-CE4C-C169">
</td>
Update 5
The button is invisible to Selenium whether or not it's enabled or not:
Checkbox not selected
Button disabled
Result: OpenQA.Selenium.ElementNotVisibleException: element not visible
Checkbox selected
Button enabled
Result: OpenQA.Selenium.ElementNotVisibleException: element not visible
Update 6
Looking at the source code, there are no elements on the page set to "invisible", so that should eliminate any invisible parent element messing up.
The only thing of not I can find is that there are two blocks of HTML code with a button with the same ID that are commented out on the page. These appear before the button in question, but I wouldn't expect Selenium to bother about commented-out HTML code?
I've never found Selenium to be wrong about things like this. I would always assume that Selenium is correct and your locator is off or something is going on in the page that you aren't aware of.
The first way I find locators is using the dev console in Chrome. I personally like the Chrome dev tools the best but it's a personal preference (mostly). Use $$(locator) to test CSS selectors and $x(locator) to test XPath. Those will return a collection of elements found by those locators. You can instantly tell if you are finding more than one and if the one you want is not the first one, etc. I generally do this just by browsing to the page but if you are still having issues, put a breakpoint and stop on the offending line and then do this in the browser.
If that still doesn't work, I would add some debug commands to investigate the page before the offending line, e.g.
Console.WriteLine(Driver.FindElements(locator).Count);
and make sure the locator is finding the right elements, the expected number of elements are found, etc.
You can also put a breakpoint on the line that is causing the problem, run the script in debug mode, and then use the Immediate window to test code.
Other comments
I mentioned in a comment that you should pass By classes around instead of strings and you asked for an example.
public class Button
{
public static void Click(By locator)
{
Find(locator).Click();
}
private static IWebElement Find(By locator)
{
return GCDriver.Instance.FindElement(locator);
}
}
and you would call it like
Button.Click(By.Id("id"));
Your WaitForVisible() method is more complicated than it needs to be. You should read up on ExpectedConditions. There are a lot of already available things to wait for that will take care of 90+% of the waits you will need. I would also pass in a TimeSpan so that you can have control over the wait time instead of always having to wait a hardcoded 30s.
public class GCDriver
{
public static void WaitForVisible(By locator, TimeSpan timeout)
{
new WebDriverWait(GCDriver.Instance, timeout).Until(ExpectedConditions.ElementIsVisible(locator));
}
}
You could even go one step further and pass in a Func that will allow you to wait for anything, not just visible.
public class GCDriver
{
public static void Wait(Func<IWebDriver, IWebElement> func, TimeSpan timeout)
{
new WebDriverWait(GCDriver.Instance, timeout).Until(func);
}
}
and call it like
GCDriver.Wait(ExpectedConditions.ElementIsVisible(locator), TimeSpan.FromSeconds(10));
After hours of troubleshooting I was able to found the cause. Or, at least, part of it.
When I used FindElements instead of FindElement, it counted TWO elements with the same ID. These were not visible when I took a snapshot of the page source at the time of the button click.
However, the reason for this is that the page containing the button has 3 tabs. The button should be the same for all tabs, since it's an "Order Selected" button and the tabs contain lists of things to order. But since unique IDs have only recently been implemented, this page wasn't created with that in mind.
So, the DOM contains at least 2 identical IDs which are not visible in the page source. The strange thing though, is that FindElements should have returned 3 elements and not 2. Or possibly the DOM is even more messy.
Anyway: When I told Selenium to click the SECOND element, like this, it
GCDriver.Instance.FindElements(By.Id(id))[1].Click();
it worked.
I am trying to access a radio button. From my research I found the element using the name, since the elements of a radio button have the same name. I want to select the second button, but I get an element not visible exception and the location property of the element returned is outside the window. However, I can see the element on the page.
The exception: An exception of type 'OpenQA.Selenium.ElementNotVisibleException' occurred in WebDriver.dll but was not handled in user code
ReadOnlyCollection<IWebElement> webElements = webElement.FindElements(By.Name("thename"));
webElements[1].SendKeys(Keys.Return);
I tried to move to location using the execute javascript as well as the Actions method. Neither worked.
I tried all possible keys to send to click for the Actions method:
Actions actions = new Actions(webDriver);
actions.MoveToElement(webElements[1]);
actions.SendKeys(Keys.Return);
actions.SendKeys(Keys.Enter);
actions.SendKeys(Keys.ArrowDown);
actions.Click();
actions.Perform();
For the javascript executor I tried two methods. To scroll into view, and to scroll by the amount that the Location property of webElement[1] told me it was off by.
IJavaScriptExecutor js = webDriver as IJavaScriptExecutor;
string title = (string)js.ExecuteScript("arguments[0].scrollIntoView(true);", webElements[1]);
string title1 = (string)js.ExecuteScript("javascript:window.scrollBy(557329,136);");
I still keep getting the location not visible exception.
A quick check you could do is open the developer tools in browser and in the console see if document.querySelector("[name='thename']") finds the element. If not, maybe that element is in an iframe or the name you are using may have a typo. You will also want to make sure that the radio button you are trying to access is below 'webElement' in the DOM tree. It's also possible that the page is still loading when you are checking for the element. To check for this put in a wait before trying to find the element so the page can load fully.
I am running into an issue where I need to click on an element twice. The first time the element is clicked it expands a tree on the page, the second time closes the tree. There is no issue when clicking the element the first time.
Here is the part of the HTML code I am working with: (The element I am clicking is the 'a' tag.)
<div id="uasMainForm:uasTabs:0:agencyTree-d-rt-c" name="c">
<div title="" class="iceTreeRow" id="uasMainForm:uasTabs:0:agencyTree-d-4" name="nd">
<a id="uasMainForm:uasTabs:0:agencyTree:4" onclick="document.forms['uasMainForm']['uasMainForm:uasMainForm:uasTabs:0:agencyTree_idtn'].value='4';iceSubmitPartial( document.forms['uasMainForm'], this,event); return false;" onblur="setFocus('');" href="javascript:;">
The weird thing is, if I run the second click immediately after running the first it closes the tree perfectly, but if I break it up with a MessageBox or some other code it throws an error when trying to perform the second click.
Here is code that works:
agency = ie.ElementOfType<Div>(Find.ByText(agencyName));
agencyTab = agency.ElementWithTag("a", Find.ByIndex(0));
agencyTab.Click();
//MessageBox.Show("Hey!");
agencyTab.Click();
Here is the code that does not work:
agency = ie.ElementOfType<Div>(Find.ByText(agencyName));
agencyTab = agency.ElementWithTag("a", Find.ByIndex(0));
agencyTab.Click();
MessageBox.Show("Hey!");
agencyTab.Click();
The above code throws the error: Could not find A element tag matching criteria: Index = 0
I have also tried Find.ById instead of ByIndex with the same result. Can anyone shed some light on what could be causing this error when breaking up the two click events, but not when the click events happen back to back?
I'm still not sure why this issue was occuring but I found a way around it. First I save the Id of the containing Div right before I do the first click:
var agency = ie.ElementOfType<Div>(Find.ByText(agencyName));
//Set current agency Id
currentAgency = agency.Id;
var agencyTab = agency.ElementWithTag("a", Find.ByIndex(0));
agencyTab.Click();
Then, when I want to perform the second click, I use the Id I saved earlier to find the containing Div again:
//Close old agency's tree
var agency2 = ie.ElementOfType<Div>(Find.ById(currentAgency));
var agencyTab2 = agency2.ElementWithTag("a", Find.ByIndex(0));
agencyTab2.Click();
For the last two weeks I have been kind of stuck on a problem.
I am developing some web scrapers using C# and I am using a WinForms WebBrowser control in my application. I am able to fill up the web form which is opened in my browser and submit it automatically by using the following code:
HtmlElement submitButton = document.GetElementById("Element_ID″);
submitButton.InvokeMember(“click”);
So far everything is fine, but the problem is that there is one another element in the web form that I want to click too, but this element does not have any id or name so I don't know how to click this one.
Please help me as soon as possible I need it for my master thesis.
(I want to click the next page arrow button in the give website:
http://www.gelbeseiten.de/yp/11//subscriberlist_pageAction.yp?sessionDataString=H4sIAAAAAAAAAI2PQU8CMRCFfw0XSEmns9128k5KongwGjFeSZftIqILbhcVf70NSgg3X-pbyXjLfvCFpqsbbIMpwbVRRuaBELKm6iew5T4gLFUpdmKpewJAGD8xV7JaxalfpdZX6mP31bH4WQfZblJehXcd2tGvr0WwbunVIKbYIZjjKmoa3atct4RSh-pA/S912oY4qhWzyjJkLvPZV4P4JetNFHYWOG2OoCH4pZlyU-pjWdhjS/LY2sp7-p1lLCLOGXwTLqpT1XSqOiXcpE3Xzw-pncUtGSDNp0ZZwR0we92TxSHjIX0x-pIQM-p0AZuciLl7M/kGE-pmcGjIOsvEpTB-pADJS0suGAQAA&page=0&filterTrade=-&filterFunction=-&sortBy=sort_trade&availableLetters=ABCDEFGHIJKLMNOPQRSTUVW )
I've written many web-scrapers in the past using embedded WebBrowsers, so you've come to the right place.
When the element does not have a name you need to find it by either content, or another associated element that is named.
In the first instance we wrote helper methods to iterate the hierachy looking for a specific piece of content within an element.
For the second option you get the named element and use a specific index for the desired child.
A combination of both (find a specific parent then look for a child with the right content)
In your specific example webpage, the next page anchor has a class type of "arrow next" you can search for.
You could do
HtmlElement next_arrow = document.GetElementsByTagName("a")
.Cast<HtmlElement>()
.Where(e => e.GetAttribute("class") == "arrow next")
.FirstOrDefault();
if (next_arrow != null)
{
next_arrow.InvokeMember("click");
}
Here's a trick, not by InvokeMember("click") rather just "simulating the click" -
this is the link for the first page:
gelbeseiten.de/yp/11//subscriberlist_pageAction.yp?sessionDataString=H4sIAAAAAAAAAI2PQU8CMRCFfw0XSEmns9128k5KongwGjFeSZftIqILbhcVf70NSgg3X-pbyXjLfvCFpqsbbIMpwbVRRuaBELKm6iew5T4gLFUpdmKpewJAGD8xV7JaxalfpdZX6mP31bH4WQfZblJehXcd2tGvr0WwbunVIKbYIZjjKmoa3atct4RSh-pA/S912oY4qhWzyjJkLvPZV4P4JetNFHYWOG2OoCH4pZlyU-pjWdhjS/LY2sp7-p1lLCLOGXwTLqpT1XSqOiXcpE3Xzw-pncUtGSDNp0ZZwR0we92TxSHjIX0x-pIQM-p0AZuciLl7M/kGE-pmcGjIOsvEpTB-pADJS0suGAQAA&page=0&filterTrade=-&filterFunction=-&sortBy=sort_trade&availableLetters=ABCDEFGHIJKLMNOPQRSTUVW
as you see page=0; clicking next, gives the link -
gelbeseiten.de/yp/11//subscriberlist_pageAction.yp?sessionDataString=H4sIAAAAAAAAAI2PQU/DMAyFf00vmzLFdprE8gkmwTggEENcp3RNxxh0o-pmA8euJBlO1G0-p-pvCf58zNwUzW-pDKyQalSmckExl6DqJpKnPCEuVbDaYFUvBcEIFXgVu1Ws2nV6Xac-pZn89X5xFwoed2MvQbmI73rf1eL4L3SakFFsJOBpnzcJbte9W4hSI-pQ/S912oY4qhWz5LDSC992Dl/QR60ahPki2OZKeNfCgiba18oicmLV8lTcoS8t6BJ8zsHMo3yEU1VE1D1ZmWm7Tt-psXxtNwCMmjS4BhJ7oDAy72WR5CH/MT0l1HQEVa46QDK2Z/JsTyhcdIAWrZeGy8/k7LJ5YQBAAA-e&page=1&filterTrade=-&filterFunction=-&sortBy=sort_trade&availableLetters=ABCDEFGHIJKLMNOPQRSTUVW
now page=1
and so on... in general clicking next means page=(x+1) clicking prev means page=(x-1). so build a string according the requirements. this addresses ur problem, however there are some other data also sent with querystring, that u have to append to the string as well.