In my application most of all the elements are inside iframe.
so my POM (Page Object Model) methods will start with switching to frame and then the code for performing actions..am able to perform action by switching to frame.
below is an example of my code:
public void method 1()
{
driver.switchTo().frame(0);
// code to perform actions....
method 2();
driver.switchTo().defaultcontent();
}
public void method 2()
{
driver.switchTo().frame(0);
// code to perform actions....
}
As per above example, the 2nd method is called from 1st method
The driver will get into frame from method 1, when the method 2 is called again it tried to switch to frame 0, as i hardcoded the frame index, i thought it will work fine (i.e even driver is on same frame), but its giving error as
"No such frame exception."
is it possible to know the current frame? like if we know the frame then i can add a condition and decide to switch or not to switch, please guide.
You could achieve this by creating a global variable for current switched frame like below approach :-
String currentFrame = null;
//make this currentFrame as global variable
public void switchToFrame(String frame) {
if ((null != frame) && (!"".equals(frame))) {
if (!frame.equals(currentFrame)) {
driver.switchTo().defaultContent();
driver.switchTo().frame(frame);
currentFrame = frame;
}
} else {
currentFrame = "";
driver.switchTo().defaultContent();
}
}
Now you can use it in your methods as below :-
public void method 1()
{
switchToFrame("your frame id or name"); //pass null if you want to switch to default
// code to perform actions....
method 2();
}
public void method 2()
{
switchToFrame("your frame id or name"); //pass null if you want to switch to default
// code to perform actions....
}
Note : - If you does not want yo create a global variable to know about current frame, you can also use JavascriptExecutor to know about current frame as below :-
JavascriptExecutor jsExecutor = (JavascriptExecutor)driver;
String currentFrame = jsExecutor.executeScript("return self.name");
Hope it will help you...:)
You could search for the frame again and if you find it, you know you aren't already in the frame.
I would try to simplify the methods so that they don't rely on each other as much as possible.
Related
guys. Today I have done my custom realization for WebDriverEventListener. I need only onException() method which will create screenshot. But I got problem because I am using fluent wait.
new FluentWait<>(webDriver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class)
.until(someCondition)
So, finally, I have got screen for each ignoring(NoSuchElementException.class) - 20 screenshots for 1 fail ))). Had somebody the such problem or had someone resolve it?
when you use .ignoring(NoSuchElementException.class) you don't avoid that the exception is raised, you are just ignoring that exception. What is happening is that the exception is being raised by your FluentWait, but it is ignored (when you declare .ignoring(NoSuchElementException.class)).
You have three options here:
Capture the screen at the end of your test if the test failed [preferred].
Have a Try-Catch wherever you are using your FluentWait or any other Selenium code.
Use reflection to avoid capture when the event is raised from the method that implements the FluentWait.
This is an idea after what we have discussed:
private void ExceptionThrown(object sender, WebDriverExceptionEventArgs e)
{
if (e.ThrownException is NoSuchElementException)
{
// Get the stack trace from the current exception
StackTrace stackTrace = new StackTrace(e.ThrownException, true);
// Get the method stack frame index.
int stackTraceIndex = stackTrace.FrameCount - 1;
// Get the method name that caused the exception
string methodName = stackTrace.GetFrame(stackTraceIndex).GetMethod().Name;
if(methodName != "MyFindElement")
{
TakeSceenshot();
}
}
else
{
TakeSceenshot();
}
}
// This is an extension method of the DriverHelper interface
public IWebElement MyFindElement(this IWebDriver driver, By by, int timeOut = 0)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeOut));
wait.IgnoreExceptionTypes(typeof(NoSuchElementException));
// I wait until the element exist
IWebElement result = wait.Until(drv => drv.FindElement(by) != null);
// it means that the element doesn't exist, so we throw the exception
if(result == null)
{
MyPersonalException(by);
}
}
// The parameter will help up to generate more accurate log
public void MyPersonalException(By by)
{
throw new NoSuchElementException(by.ToString());
}
This probably require changes in EventFiringWebDriver, because this class is without WebDriverWait instance and events for them. If you want avoid it, create bool variable in your EventFiringWebDriver extended class and check this value in your OnException like:
protected void OnException(WebDriverExceptionEventArgs e) {
if (IsWaitHandler)
return;
Your actions...
}
but this is not perfect solution.
I am having some issues using selenium, and specifically using actions, although this could just be a symptom for a bigger issue. To quickly explain what try to do:
I scroll down to the bottom of a page using SendKeys(Keys.ArrowDown)
I press a button, and I change the page to a different language.
I try to scroll down on the new page using SendKeys(Keys.ArrowDown). This is where i receive an error!
The strange thing here is that i have no issues with the scrolling in step 1 even though I am using the same function, but in step 3 i receive an error message:
OpenQA.Selenium.StaleElementReferenceException: 'The element reference of is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed'
I have tried to redeclare my footer variable, and also included it as a Footer class variable (originally it wasn't), but nothing i do change anything
The reason I am using SendKeys and not MoveToElement is due to MoveToElement doesn't work for off-screen elements in Firefox. I have included all relevant code below, including an image of the error and when it happens.
Could anyone please advice what I am doing wrong?
[TestMethod]
public void Reset_newsletter_subscription_form_BR_site()
{
Browser.Goto(siteUrl);
Webpage.Footer.GoTo_CountryPageViaFooter("br");
Webpage.Footer.ScrollToFooter(); // -> This is where it fails!
Other.Irrelevant.Stuff();
}
Below this is the Selenium parts:
public static class Browser
{
public static IWebDriver webDriver;
public static Actions actions;
public static void Goto(string url)
{
webDriver.Url = url;
}
}
public static class Webpage
{
public static Footer Footer
{
get
{
var footer = new Footer(Browser.webDriver, Browser.actions);
return footer;
}
}
}
public class Footer
{
private IWebDriver webDriver;
private Actions actions;
private IWebElement footer;
public Footer(IWebDriver webDriver, Actions actions)
{
this.webDriver = webDriver;
this.actions = actions;
}
public void GoTo_CountryPageViaFooter(string CountryTag)
{
footer = webDriver.FindElement(By.ClassName("c-footer"));
var changeCountryButton = footer.FindElement(By.ClassName("c-footer__toggle-country-selector"));
ScrollToFooter();
actions.MoveToElement(footer).Perform();
actions.MoveToElement(changeCountryButton).Perform();
changeCountryButton.Click();
var intPageLink = footer.FindElement(By.XPath("//*[#href='/" + CountryTag + "/']"));
intPageLink.Click();
}
public void ScrollToFooter()
{
footer = webDriver.FindElement(By.ClassName("c-footer"));
//MoveToElement does not work for Firefox, so a workaround is needed.
if (webDriver is FirefoxDriver)
{
int i = 0;
while (i < 5)
{
actions.SendKeys(Keys.ArrowDown).Perform(); //This is where it fails!
i++;
}
}
actions.MoveToElement(footer).Perform();
}
Image of the exception
Whenever Perform() method is invoked, it figures how to interact with the Page. So its job is to find out the active element present in the Page(if element not specified as in MoveToElement(element) or during clicking an element using Actions).
So in your case, as no Element is specified actions.SendKeys(Keys.ArrowDown).Perform(); so Actions will focus on any Active Element present in the Page and Perform the SendKeys Operation on that.
Details about Actions Interaction with Web Page..
So, as soon as the Language change link is getting clicked the Elements attached to the DOM are changing as a result Selenium Webdriver detects this as a change in the current Active Element as a result StaleElementReference Exception thrown.
In order to get rid of the Exception, you can add wait statement in between or there is a great way to handle StaleElementReference Exception given here
Thanks :)
I wouldn't use .SendKeys() to scroll the page. It won't be consistent. Imagine if the page is longer or shorter... how many times will you need to scroll? I think a better approach is to use JS to scroll the page to the desired element.
public void ScrollToFooter()
{
footer = webDriver.FindElement(By.ClassName("c-footer"));
// MoveToElement does not work for Firefox, so a workaround is needed
if (webDriver is FirefoxDriver)
{
IJavaScriptExecutor jse = (IJavaScriptExecutor)webDriver;
jse.ExecuteScript("arguments[0].scrollIntoView();", footer);
}
else
{
actions.MoveToElement(footer).Perform();
}
}
If you decide to stick with your method, you have a bug because of a missing else. If the driver is FF, after your scrolldown code is executed, it will execute .MoveToElement() and fail.
You could simplify this function to just use JS for all drivers.
public void ScrollToFooter()
{
footer = webDriver.FindElement(By.ClassName("c-footer"));
IJavaScriptExecutor jse = (IJavaScriptExecutor)webDriver;
jse.ExecuteScript("arguments[0].scrollIntoView();", footer);
}
Instead of
actions.SendKeys(Keys.ArrowDown).Perform();
I suggest:
webDriver.FindElement(By.cssSelector("body")).sendKeys(Keys.ArrowDown);
In webpage I test is a modal which appears after pressing a button for circa 5sec.
And now I'm trying to make this in selenium.
I have method like this:
public static void ClickHold(IWebElement by)
{
SpecialInteractions.ClickAndHold(by);
}
where
public static Actions SpecialInteractions { get; set; }
and there is no hold time to set.
It looks like just clicking and releasing. Is there a way to wait for particular amount of time and then release?
Without digging dipper I can tell you the program above probably returns NulReference exception. I suspect you need to instantiate the Actions by wrapping the current driver instance.
Possible solution could be:
public void ClickHold(IWebElement element)
{
Actions action = new Actions(driver);
action.clickAndHold(webelement).build().perform();
//you need to release the control from the test
//actions.MoveToElement(element).Release();
}
Keep in mind that this will not work if you are using Selenium Grid. There is a bug that makes moveToElement an unrecognized command.
public static Boolean moveToThenSlowClickElement(final WebDriver driver, final WebElement toElement, final int millisecondsOfWaitTime) {
final Actions clickOnElementAndHold = new Actions(driver);
final Actions release = new Actions(driver);
clickOnElementAndHold.moveToElement(toElement).clickAndHold(toElement).perform();
sleep(millisecondsOfWaitTime);
release.release(toElement).perform();
final Action hoverOverCheckBox = clickOnElementAndHold.build();
hoverOverCheckBox.perform();
return true;
}
I want to get the time between successive mouse clicks in ms. This is what I have tried:
void setup(){
size(512,512);
background(100,100,0);
}
void draw(){
}
void mousePressed(){
println(new Date() - oldtime);
var oldtime=new Date();
}
The problem appears to be that processing.js does not remember the value of oldtime between calls to mousePressed().
On the first call, there has been no previous mouse click, oldtime is undefined, and the time should be NaN. But after the first click, oldtime is set, and so the above should work. I tried doing
var oldtime=new Date();
outside mousePressed() so that the first call would not be NaN, but no luck.
Thanks very much for any help.
===========================
The problem had to do with variable "scope". This works now
var oldtime=new Date();
void setup(){
size(512,512);
background(100,100,0);
}
void draw(){
}
void mousePressed(){
println(new Date() - oldtime);
oldtime=new Date();
}
There is a built in method/function for this called millis(), no need to use the Date class. There is also no reason to call var. I would also initialize your classes and variables in the setup method. Here is how these changes would look in your code in processing syntax:
int oldtime;
void setup(){
size(512,512);
background(100,100,0);
oldtime = millis()
}
void draw(){
}
void mousePressed(){
println(millis() - oldtime);
oldtime = millis()
}
If you are familiar with JavaScript you might find it beneficial use processing directly in javascript. That way it is easy to mix and match what you need and to use standard javascript debugging tools. There is a great tutorial on how to do this here:
http://processingjs.org/articles/jsQuickStart.html#javascriptonlyprocessingcode
How are you finding out if jqGrid is loaded and ready to be used, via selenium.
Some details :
Im using C# driver
I have a method : new WebDriverWait(driver, new TimeSpan(0, 0, 0, 30)).Until(x => loadingdissapearedcondition) which im using to wait until Loading.. element is gone.
I also sometimes use this script :
private const string script = #"return ($('#{0}').jqGrid('getGridParam', 'reccount') !=x undefined) && ($('#{0}').jqGrid('getGridParam', 'reccount') != 0) && (!$('#load_{0}').is(':visible')) && (!$('#busyIcon').is(':visible'))";
private readonly string waitScript;
waitScript = string.Format(script, jqGridId);
public void WaitUntilLoadIconDissappears()
{
driver.WaitUntil(MAXWAIT, Wait);
}
public bool Wait()
{
var executeScript = ((IJavaScriptExecutor) driver).ExecuteScript(waitScript);
bool result;
bool tryParse = bool.TryParse(executeScript.SafeToString(), out result);
return tryParse && result;
}
to find if jqGrid has records and loading done.
I require something better - as even the above two does not make driver wait until load finishes, if we are using local data for jqGrid. Im also curious what is the best way, or at the minimum, how others are dealing with this problem.
I never used Selenium before, so I'm not sure that I understood your problem correctly. jqGrid will be first initialized and then (optionally) the data can be loaded from the server. During the initializing stage the original <table id="grid"></table> element will be converted to relatively complex HTML fragment which is the grid. At the end of the initialization the DOM element of the table (the $("#grid")[0]) will get the expando grid.
So you can use the test like
if ($("#grid")[0].grid) {
// grid is initialized
}
to determine that the grid is already initialized. jqGrid uses the same test internally (see here for example).
Here is solution for Java and jqgrid.
If grid data is not loaded yet then right pager has no value, so simply check its length. Methods such as isElementPresent, isDisplayed etc. seems not to work for grid right pager object. It's always present in page code while ajax, but text value is set when dynamic data is loaded.
public void waitForGridPagerRight(String gridName) throws Exception {
for (int second = 0;; second++) {
if (second >= 15) {
fail("Timeout.");
}
try {
if (driver
.findElement(By.id("pager_" + gridName + "_right"))
.getText().length() > 2)
break;
} catch (Exception e) {
}
Thread.sleep(1000);
}
}
Not sure why #Oleg's answer didn't work for me. It seemed like grid was being populated even before the ajax call was being made. It appears there's some change in newer versions maybe. It look like the last thing to happen in the ajax call is that the "loading" block is hidden, so instead I find that element and check it's display attribute a la:
def wait_for_jqgrid(self, t=20):
def check_jqgrid(driver):
#the last thing jqgrid does after the ajax call is to turn off the loading div
#so we find it and check to see if its display attribute is no longer set to 'none'
script = 'pid = $.jgrid.jqID($(".ui-jqgrid-btable").get(0).p.id); return $("#load_"+pid).get(0).style.display == "none";'
return driver.execute_script(script)
WebDriverWait(self.driver, t).until(check_jqgrid)
When the loading div is hidden, we are done. This is python but the same javascript bit should work in Java or whatever.