I've got a page with both text, text fields, normal form buttons and a file upload button (which opens a file upload dialog).
All the other elements can be accessed, except the file upload button. I've tried with both .Click() and JavaScriptExecutor, but as far as I can see (visually) the file dialog never opens. There are no error messages, though.
The page source:
<a class="bttngrey file-input-container bttn-small" data-bind="enable: !uploading() " style="margin-top: 10px; ... data-original-title="Add attachment">
<i class="fa fa-cloud-upload">...</i>
<input type="file" data-bind="upload: addAttachments, enable: !uploading()"> == $9
C#/Selenium code to click the button:
NB: I'm using a Button class and a JavaScriptActions class to handle the call to the ChromeDriver instance, instead of calling it directly. I hope the code snippets make sense.
Button.FindByXPath("/html/body/div[1]/div[2]/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/a").Click();
JavaScriptActions.ButtonClickXPath("/html/body/div[1]/div[2]/overlay--master/div/div/overlay-lightbox/div/div[3]/content-placeholder/a");
public class Button {
public static IWebElement FindByXPath (string bttnxpath) {
return GCDriver.Instance.FindElement(By.XPath(bttnxpath));
}
}
public class JavascriptActions {
public static void ButtonClickXPath (string xpath) {
GCDriver.JSClickXPath(xpath);
}
}
public class GCDriver {
....
....
....
public static void JSClickXPath (string xpath) {
IWebElement icon = Instance.FindElement(By.XPath(xpath));
Actions ob = new Actions(Instance);
ob.Click(icon);
IAction action = ob.Build();
action.Perform();
}
....
....
....
}
None of the methods for clicking the button seems to work. Even though they work for other "normal" buttons on the page. The reason I'm trying JavaScriptExecutor is that I've experience a case earlier where a button like this (that opens a file dialog) wasn't clickable by the normal Selenium method, but it was with JavaScriptExecutor.
The strange thing here is that both methods just finishes without any errors. However, when I'm watching the page, I see no clicking and opening of the dialog. The test just finishes immediately. Adding an explicit wait before and after clicking the button doesn't help either.
Any ideas? I'll elaborate more if necessary; It's not always clear how much code needs to be shown for the question/problem to be clear.
Please give below code try, using similar code in my project:
IWebElement element = new WebDriverWait(_browserWindow, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.CssSelector("[class='fa fa-cloud-upload']")));
//Send complete file path to attach it
element.SendKeys("File Path");
Also, as per posted HTML code, upload button contain composite class name. So refer this for composite class element locator:
Compound class names are not supported. Consider searching for one class name and filtering the results
Try this: (using a driver class instance)
Actions actions = new Actions(Driver.Instance);
actions.MoveToElement(Driver.Instance.FindElement(By.XPath(xpath)));
actions.Click();
actions.Build().Perform();
Just create a method in the driver class and call it from the relevant place in your code.
You can possible use SendKeys to send the file path, but the way I usually do it is to use the AutoIt library to handle the actions on the window, since it's not a browser/web element.
Related
I have the following problem:
When my menu sidebar changes from "open-state" to "closed-state", or other way around, the width of the components in the page are not refreshed and that result in something like this:
Now this can be solved with calling the "Refresh" function of the SfMaps component so the width is refreshed aswell, however I'm unable to do that because my Sidebar is in another Razor component.
Therefore I need a solution in my NavMenu.razor(sidebar component) that will call a method in another class that refreshes the SfMap component, this method will be called from the OnChange method of the sidebar.
This is What I've tried so far:
Declare the instance of the Test.page and call the "RefreshItem()" method when the state of the sidebar has changed:
NavMenu. razor:
<SfSidebar Width="250px"
EnableDock="true"
DockSize="65px"
Position="SidebarPosition.Left"
Type="SidebarType.Push"
#ref="Sidebar"
IsOpen="true"
Changed="ManageSideBar">
</SfSideBar>
#code{
[CascadingParameter]
ApplicationName.Pages.Test testLayout { get; set; }
void ManageSideBar()
{
if (testpage != null)
{
this.testLayout.RefreshItem();
}
}
}
Test.Razor:
<SfMaps ID="map" #ref="maps" Width="100%">
</SfMaps>
#code
{
SfMaps maps;
public void RefreshItem()
{
maps.Refresh();
}
}
However this code does not work somehow, its telling me that "Test.Razor" is null even after I loaded it.
Does someone know how this happends or does anyone have another solution how to tackle my problem?
Thanks in advance!
We have prepared a simple sample to achieve your expected requirement. In the below sample, we have used a time delay on the click method where the sidebar is expanded/collapsed. This is because the sidebar is collapsed before the page component is resized completely. The Refresh() method of Maps is called before that. So the maps component is refreshed after the component is resized completely using the time delay.
Sample link - https://www.syncfusion.com/downloads/support/directtrac/292460/ze/BlazorApp1906858485
Refer the below links for Maps and Sidebar component.
Maps:
UG documentation- https://blazor.syncfusion.com/documentation/maps/getting-started/
Demo link- https://blazor.syncfusion.com/demos/maps/default-functionalities
API reference- https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Maps.SfMaps.html
Sidebar:
UG documentation- https://blazor.syncfusion.com/documentation/sidebar/getting-started/
Demo link- https://blazor.syncfusion.com/demos/sidebar/default-functionalities?theme=bootstrap4
API reference- https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Navigations.SfSidebar.html
Please let us know, if you need any further assistance.
Regards,
Sowmiya.P
I am having a really hard time with the following issue. I am trying to navigate through some web pages that have various inputs (text boxes/dropdowns/buttons) followed by a continue button at the bottom to move onto the next screen. My tests frequently fall over because they can't always locate the first element in order to interact with it.
As far as I'm aware the page doesn't do any fancy AJAX post loading or anything, so once the page has loaded then Webdriver should be able to locate every element.
My code:
FRAMEWORK
public static void WaitOnPageForXPathClickable(string selector)
{
new WebDriverWait(Driver.Instance, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable((By.XPath(selector))));
}
TEST CASE
Utilities.WaitOnPageForXPathClickable("the xpath of the continue button and checks that it is clickable");
Driver.Instance.FindElement(By.XPath("the xpath of the first button that I want to click")).Click();
Do I need to try and include a function to ensure that the page is fully loaded before test execution? I am confused about this because I have read that Selenium already waits for the page to load by default. I would have thought that waiting for one element (the continue button) to be clickable should mean that all other elements are ready by then too? I really want to avoid having to wait for every single element before clicking it.
Can you please share html, have you tried with Visible instead of Clickable
public static void WaitOnPageForXPathClickable(string selector)
{
new WebDriverWait(Driver.Instance, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementIsVisible((By.XPath(selector))));
}
You can wait for the page to be fully loaded with something like:
public void WaitForPageToBeFullyLoaded(int timeSpan)
{
new WebDriverWait(Driver, TimeSpan.FromSeconds(timeSpan)).Until(
d => ((IJavaScriptExecutor) d).ExecuteScript("return document.readyState").Equals("complete"));
}
You can check for displayed or Enabled element too.
You have made things much more complicated by waiting for the Continue Button Utilities.WaitOnPageForXPathClickable("the xpath of the continue button and checks that it is clickable"); where as in the next step trying to click() on the First Button Driver.Instance.FindElement(By.XPath("the xpath of the first button that I want to click")).Click();
Test Scenario:
Ideally your Test Scenario should have been :
TEST CASE:
Utilities.WaitOnPageForXPathClickable("the xpath of the first button that I want to click");
Driver.Instance.FindElement(By.XPath("the xpath of the first button that I want to click")).Click();
FRAMEWORK:
public static void WaitOnPageForXPathClickable(string selector)
{
IWebElement element = new WebDriverWait(Driver.Instance, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable((By.XPath(//label[#class='replaced-input-label replaced-input-label--radio']))));
elementClick();
}
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.
Looking at the USCIS form N-400, you can see that in Part 9 has two buttons, Add Children and Go to continuation page Looking at the XML/JS backing those buttons you get this node for the corresponding field:
<event activity="click" name="event__click">
<script contentType="application/x-javascript">
_KidsContPage.addInstance(1);
xfa.form.recalculate(1);
xfa.host.pageDown( );
</script>
</event>
This is used to add the automatically hidden page to the form in case the user has more than 8 children. My question is using iTextSharp, or perhaps some other method, how do I create this new instance of the page? If you notice you can make multiple copies of this additional children page, if, somehow, you happen to have more than 25 kids, so not getting side-tracked by the unlikelihood of that possibility, I need to know how to create multiples of such a page...
This is what I have so far:
PdfAction cloneAction = PdfAction
.JavaScript(ClonePage("KidsContPage"), stamper.Writer);
stamper.Writer.AddJavaScript(cloneAction);
I've also tried with SetOpenAction
stamper.Writer.SetOpenAction(cloneAction);
private string ClonePage(string formName)
{
return #"
if (xfa.host.name != 'XFAPresentationAgent') {
$._" + formName + #".addInstance(1);
if (xfa.host.version < 8) {
xfa.form.recalculate(1);
}
}";
}
I know that my ClonePage() code is being run, because I see the alert when I tested it earlier, the problem is in the javascript or perhaps I somehow need to run it at server or who knows what I need to do. I opened the XFA PDF in LiveCycle and that's the JS that it's putting out for it, I must be missing something small somewhere...and it works fine in LiveCycle. Please help.
Im doing webtest using selenium Webdriver in C#. But I'm having a problem where when the browser window isn't in full size a popup will open half way outside the visible area.
The problem is that when i fire a .Click(); it doesn't do anything because the link i attempt to click is outside of the viewed area.
So how do i focus on the link to get click to work? Im currently using the following workaround but i don't think that's a nice way.
_blogPostPage.FindElement(By.XPath(_popupLogin)).SendKeys("");
_blogPostPage.FindElement(By.XPath(_popupLogin)).Click();
The sendkeys with space focuses on the link and makes Click work everytime, but isn't there a right way to do it?
We've been playing with Selenium and have run into this problem as well. I don't know if it's the WebDriver as a whole, the C# implementation, the version of Firefox etc, but we have found an ok workaround:
The trick is to force Selenium to evaluate the LocationOnScreenOnceScrolledIntoView property on the RemoteWebElement class (which is inherited by FirefoxWebElement and implements IWebElement). This forces the browser to scroll so that the element is in view.
The way we've done it is to use an extension method:
using OpenQA.Selenium;
using OpenQA.Selenium.Remote;
namespace Namespace
{
public static class ExtensionMethods
{
public static IWebElement FindElementOnPage(this IWebDriver webDriver, By by)
{
RemoteWebElement element = (RemoteWebElement)webDriver.FindElement(by);
var hack = element.LocationOnScreenOnceScrolledIntoView;
return element;
}
}
}
this way all we have to do is change the generated code from:
driver.FindElement(By.Id("elementId")).Click();
to:
driver.FindElementOnPage(By.Id("elementId")).Click();
Hope it works for you!?
Instead of doing send key for blank value, send it for space. Thats the keyboard shortcut to select a checkbox.
Just replace the code :
_blogPostPage.FindElement(By.XPath(_popupLogin)).SendKeys("");
_blogPostPage.FindElement(By.XPath(_popupLogin)).Click();
by
_blogPostPage.FindElement(By.XPath(_popupLogin)).SendKeys(Keys.Space);
driver.find_element(:id, "edit-section").send_keys " " with the space worked for me.
I am using webdriver rspec with selenium-server-2.24.1 and I was having trouble with IE8 - I kept getting Selenium::WebDriver::Error::ElementNotVisibleError. It was working in IE9 and FF but not IE8 until I added send_keys " ".