public void Hover()
{
Actions action = new Actions(BrowserWindow.Instance.Driver);
action.MoveToElement(WebElement).Perform();
}
This is working in Chrome. Not Edge. I have confirmed with the developer that I am "hovering" over the correct element.
WebElement elem = yourWebDriverInstance.findElement(By.xpath("//*[#class='goog-menu goog-menu-vertical uploadmenu density-tiny']/input"));
String js = "arguments[0].style.height='auto'; arguments[0].style.visibility='visible';";
((JavascriptExecutor) yourWebDriverInstance).executeScript(js, elem);
Which also failed to work. Anyone have any idea what I am doing wrong?
More info.
This is also failing on Firefox. I saw an article about out of date selenium drivers. I have JUST installed both geckodriver and set the Edge driver to auto update according to the documentation. I do not believe I have out of date drivers.
More info take 2
Calling code is
public static void DoCloseActiveTabEntire()
{
Element tab = new Element(byTab);
tab.Hover();
// CLose button is not clickable. Cannot use standard BUTTON for find
Button close = new Button(byClosePanelButton);
close.Click();
}
If I set a break point at button close... after the hover attempt, I notice that moving my mouse over the "tab" also does not cause the button to be visible.
This is weird. But replace
action.MoveToElement(WebElement).Perform();
with
action.MoveToElement(WebElement).Build().Perform();
And it works. I read that the Build is built into Perform. But I was kinda just smacking at it hoping something fell out. And it worked.
perform()
perform() is the convenience method for performing the actions without calling build() first.
build()
build() generates a composite action containing all actions so far, ready to be performed and additionally also resets the internal builder state, so subsequent calls to build() will contain fresh sequences.
This usecase
In your usecase, you have invovoked perform() just after moveToElement(WebElement) without generating the composite action to be performed using build().
Solution
A straight forward solution would be to invoke build() before perform() as follows:
public void Hover()
{
Actions action = new Actions(BrowserWindow.Instance.Driver);
action.moveToElement(WebElement).build().perform();
}
So, I don't know why I thought the build().perform() did the job. I know it worked ONCE. What I wound up doing is keeping the hover code the same.
public void Hover()
{
Actions action = new Actions(BrowserWindow.Instance.Driver);
action.MoveToElement(WebElement).Build().Perform();
Thread.Sleep(1000);
}
I changed the calling code which attempts to close the panel/page whatever I want to call it to this:
public static void DoCloseActiveTabEntire()
{
// So there is a defect in EDGE whereby the behavior of the code containted in the hover on the tab executes without
// error but the action underneath does not occur. So in Edge, callng the hover method of the TAB as seen in the else condition
// below does nto display the CLOSE button which needs to be clicked.
// So for Edge, javascript is used to display the button directly.
IWebElement close;
if (BrowserWindow.Instance.Browser == BrowserWindow.Browsers.Edge)
{
close = BrowserWindow.Instance.Driver.FindElement(byClosePanelButton);
string js = "arguments[0].style.height='auto'; arguments[0].style.visibility='visible'; arguments[0].style.display='inline';";
IWebDriver driver = BrowserWindow.Instance.Driver;
IWebElement element = close;
((IJavaScriptExecutor)driver).ExecuteScript(js, element);
}
else
{
Element tab = new Element(byTab);
tab.Hover();
close = new Button(byClosePanelButton).WebElement;
}
close.Click();
}
For me, I am happy that the thing can be closed. I don't care that much whether the hover achieves it.
Related
The problem I have is that my Page Object class finds all of the objects on the screen and then sends it to a more generic method to do the actual data entry. During this data entry process, some objects become stale and I get the "StaleElementException".
My plan is to catch that exception and attempt to re-find the element again.
Is there a way of extract the selection strategy from the runtime WebElement object other than doing a "object.toString()" and then parsing it?
I use page objects by defining the locators at the top of the class, then the constructor that verifies that we're on the right page (etc), and then methods for each action available on the page. Here's a simple example for the Google search page.
GoogleSearchPage.java
public class GoogleSearchPage
{
private WebDriver driver;
private By waitForLocator = By.id("lst-ib"); // optional
private By searchBoxLocator = By.id("lst-ib");
private By searchButtonLocator = By.cssSelector("button[name='btnG']");
private By feelingLuckyButtonLocator = By.id("gbqfbb");
public GoogleSearchPage(WebDriver webDriver)
{
driver = webDriver;
// wait for page to finish loading
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(waitForLocator));
// see if we're on the right page
if (!driver.getCurrentUrl().contains("https://www.google.com"))
{
throw new IllegalStateException("This is not the Google search page. Current URL: " + driver.getCurrentUrl());
}
}
public void doSearch(String searchString)
{
driver.findElement(searchBoxLocator).sendKeys(searchString);
driver.findElement(searchButtonLocator).click();
}
}
GoogleSearchTest.java
public class GoogleSearchTest
{
public static void main(String[] args)
{
WebDriver driver = new FirefoxDriver();
driver.get("http://www.google.com");
GoogleSearchPage googleSearchPage = new GoogleSearchPage(driver);
googleSearchPage.doSearch("selenium");
System.out.println(driver.getCurrentUrl().contains("#q=selenium"));
}
}
This is obviously a super simple example but it shows one good way to create page objects that should significantly reduce the frequency of StaleElementExceptions and, in some cases, speed up your script execution because you only scrape what you need and move on.
Reduce the urge to provide a getX() and clickX() method for each and every element on the page. Instead favor task based methods. Ask yourself what tasks a user is going to want to accomplish on the page and provide methods to do those tasks. It will keep your page object API much cleaner and more clear in what it provides to the consumer (you and other script writers).
I am trying to automate search box of Amazon.in and when i try to enter some string over there, it rather points towards the address bar of browser. My code for the same.
Note- I have already tried with different xpaths using firebug and also through tag traversing.
Also please let me know why we have to use always build and perform methods with actions?
public static void main(String args[])
{
WebDriver driver= new FirefoxDriver();
driver.get("http://amazon.in");
Actions action=new Actions(driver);
WebElement element= driver.findElement(By.xpath(".//*[#id='nav-link-yourAccount']/span[2]"));
action.moveToElement(element).build().perform();
WebElement search= driver.findElement(By.xpath(".//*[#id='twotabsearchtextbox']"));
action.keyDown(Keys.SHIFT).moveToElement(search).sendKeys("teststring").build().perform();
action.contextClick(search).build().perform();
}
public static void main(String args[]) {
WebDriver driver = new FirefoxDriver();
driver.get("http://amazon.in");
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Actions action = new Actions(driver);
WebElement search = driver.findElement(By.xpath(".//*[#id='twotabsearchtextbox']"));
//Search using actions by combining entering search string and then hit enter
action.click(search).sendKeys("Test").sendKeys(Keys.RETURN).build().perform();
// This also works where it does the same without actions class
search.sendKeys("test");
search.sendKeys(Keys.RETURN);
}
In your code:
Below line enters teststring into the browser search instead of the amazon search bar because you are just moving to that element and not clicking on it. action.keyDown(Keys.SHIFT).moveToElement(search).sendKeys("teststring").build().perform();
This like right clicks / context click on the search bar
action.contextClick(search).build().perform();
From the API doc:
build() Generates a composite action containing all actions so far,
ready to be performed (and resets the internal builder state, so
subsequent calls to build() will contain fresh sequences).
perform() A convenience method for performing the actions without
calling build() first
Please read below links for a clear picture on them:
LinkOne
LinkTwo
I have an application which uses GXT and contains ±30 forms. I would like to make these forms so that when the user hits enter in a text field, the form gets submitted, like a regular browser form would.
I know I can add a key press listener to every text field, which would invoke the submit after enter is pressed, but since I want to apply this to every field in every form I am not sure if this is ideal.
Is there a simpler way to implement this in the entire application?
If not, which pattern should I use to add this functionality to every field? I can extend the TextField class, add the functionality in the child class and use the child class in the application. Or I can create a factory for the text field class which would also add the listener to the field. Or is there some other way, Decorator perhaps? I was wondering which of these approaches, if any, is generally preferred.
I would try something like this:
Event.addNativePreviewHandler(new NativePreviewHandler() {
#Override
public void onPreviewNativeEvent(NativePreviewEvent event) {
if (event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER) {
if (event.getNativeEvent().getEventTarget() != null) {
Element as = Element.as(event.getNativeEvent().getEventTarget());
if (as.getTagName().toLowerCase().equals("input") ||
as.getTagName().toLowerCase().equals("textarea")) {
// TODO submit data;
}
}
}
}
});
Every time someone hits the Enter Key and the cursor is placed on a input- or textarea-tag, you will get the control and can submit your data.
I don't think there is a way to do what you're asking directly in the GXT library. I do want to stress that extending the TextField class just to add an event handler to it is not the correct way to handle this. Event handlers are based on the composition of a class. It would be like extending a class with a List field just to add another element into the list.
A singleton factory class that created and initialises the Textfield for you would be the cleanest solution, in my opinion. It would allow you to effectively change defaults and add other handlers as required at a later time in a single place if requirements change.
You can try it with GWT JSNI also.
Steps to follow:
define a function in JavaScript that is called on Enter key press
call GWT JSNI from above JavaScript function that is exported at the time of onModuleLoad using GWT JSNI
get the Element from where this event is triggered and finally submit the form based on its tag name or Id
Sample code:
HTML/JSP:
<script>
window.onkeydown = keydown;
function keydown(event) {
if (event.which == 13) {
formSubmit(event.target);
}
}
</script>
JAVA(Entry Point):
import com.google.gwt.dom.client.Element;
public void onModuleLoad() {
exportFormSubmit();
...
}
public static void formSubmit(Element element) {
Window.alert("element tag name:" + element.getTagName() + "form ID:"
+ element.getParentElement().getId());
}
public static native void exportFormSubmit() /*-{
$wnd.formSubmit = $entry(#com.x.y.z.client.GWTTestProject::formSubmit(Lcom/google/gwt/dom/client/Element;));
}-*/;
I use selenium IDE to initially record the tests and save them as Java WebDriver tests.
When I go into an input field, delete all the text and enter a new value, it records that as 2 commands:
driver.findElement(By.id("username")).clear();
driver.findElement(By.id("username")).sendKeys("johnnyleitrim");
One problem with this for me is that the clear() event fires a Javascript change event for the "username" field. This does not happen when I use the browser itself - it waits until the field loses focus before firing the change javascript event, and that's what I want to emulate in Selenium.
The reason I need this is that I do validation on the change() event, and when change is called with an empty value, it displays an alert telling the user the information is invalid - and this alert stops Selenium
So how do I clear the field without using WebElement.clear()?
You can avoid using the clear() method and use the Actions class to clear and set text in one go, therefore firing the onchange() event only once the text is set.
Call the below method like:
ClearAndSetText(By.id("username"),"johnnyleitrim");
The method clicks the element, selects the existing text using shift+home keys,clears using backspace, and then types in the new text - just like how a user would do.
public void ClearAndSetText(By by, string text)
{
WebElement element = driver.findElement(by);
Actions navigator = new Actions(driver);
navigator.click(element)
.sendKeys(Keys.END)
.keyDown(Keys.SHIFT)
.sendKeys(Keys.HOME)
.keyUp(Keys.SHIFT)
.sendKeys(Keys.BACK_SPACE)
.sendKeys(text)
.perform();
}
You can try it using JavaScriptExecutor (although I haven't tested it).
JavaScriptExecutor js = (JavaScriptExecutor) driver;
js.executeScript("document.querySelector(\"input[id='username']\").value = ''");
Seems like it's a known Selenium bug. There were a few options as workarounds mentioned on the bug page, but they all meant having to "heavily" modify the code returned from Selenium IDE. Instead, I decided to create a Proxy which would do the work for me without too much modification to the IDE generated code:
protected WebElement findElement(By criteria) {
try {
WebElementHandler webElementHander = new WebElementHandler(seleniumWebDriver.findElement(criteria));
return (WebElement) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{WebElement.class}, webElementHander);
} catch (NoSuchElementException e) {
logger.error("Could not find " + criteria + " on page " + seleniumWebDriver.getCurrentUrl());
throw e;
}
}
private class WebElementHandler implements InvocationHandler {
private WebElement proxiedElement;
private WebElementHandler(WebElement proxiedElement) {
this.proxiedElement = proxiedElement;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("clear")) {
Keys[] keys = new Keys[proxiedElement.getAttribute("value").length()];
for (int i = 0; i < keys.length; i++)
keys[i] = Keys.BACK_SPACE;
proxiedElement.sendKeys(Keys.chord(keys));
return null;
}
return method.invoke(proxiedElement, args);
}
}
Can anyone tell me whether there is an equivalent method in GWT like change in jQuery for form elements like radio-buttons, checkboxes, etc, which is fired the moment any such button is checked or unchecked? If so, how do I use it? I found a method like addValueChangeHandler in the Google docs, but apart from providing the prototype, there is no working example.
Specifically, if I want a handler which will wait for a checkbox being checked or unchecked, and accordingly pop up an alert like A checkbox has been checked!!, along with that buttons accompanying text.
CheckBox newOption = new CheckBox();
newOption.setText("Check to see alert");
newOption.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
#Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
if (event.getValue()) {
Window.alert("Checkbox is checked!");
} else {
Window.alert("Checkbox is unchecked!");
}
}
});