I am trying to click "Radio Button" which is inside iFrame. I tried to switch iFrame but facing issues.
I have tried to identify in which iFrame my Element lies but facing error as No such Frame.
Sharing my Script, which navigate to the page where I am facing issue clicking on any of the Radio Button.
WebDriver driver;
JavascriptExecutor jse;
public static void main(String[] args)
{
Sap_Demo demoObj = new Sap_Demo();
demoObj.invokeBrowser();
demoObj.initializeSAPFiory();
demoObj.forecastMD61();
}
public void invokeBrowser()
{
System.setProperty("webdriver.chrome.driver", "U:\\Research Paper\\Selenium\\Drivers\\Chrome\\chromedriver_win32\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().deleteAllCookies();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(40, TimeUnit.SECONDS);
driver.manage().timeouts().pageLoadTimeout(40, TimeUnit.SECONDS);
}
public void initializeSAPFiory()
{
try
{
Thread.sleep(1200);
driver.get("https://dijon.cob.csuchico.edu:8042/erp");
driver.findElement(By.id("USERNAME_FIELD-inner")).sendKeys("H4");
Thread.sleep(1200);
driver.findElement(By.id("PASSWORD_FIELD-inner")).sendKeys("Onsjhjsa1087");
Thread.sleep(1200);
driver.findElement(By.id("CLIENT_FIELD-inner")).clear();
Thread.sleep(1200);
driver.findElement(By.id("CLIENT_FIELD-inner")).sendKeys("485");
Thread.sleep(1200);
driver.findElement(By.xpath("//span[#class='sapMBtnContent sapMLabelBold sapUiSraDisplayBeforeLogin']")).click();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void forecastMD61()
{
try {
driver.findElement(By.id("erpsim-tcode-btn-img")).click();
Thread.sleep(1200);
driver.findElement(By.id("TCode-input-inner")).sendKeys("MD61");
Thread.sleep(1200);
driver.findElement(By.id("TCode-launchBtn-content")).click();
Thread.sleep(1200);
/*driver.switchTo().frame(driver.findElement(By.xpath("//span[#id='M0:46:::4:2-imgSymb']")));
driver.findElement(By.xpath("//span[#id='M0:46:::4:2-imgSymb']")).sendKeys("ABC");*/
//driver.manage().timeouts().implicitlyWait(40, TimeUnit.SECONDS);
//Thread.sleep(1600);
driver.switchTo().frame("ITSFRAME1");
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt("ITSFRAME1"));
//WebElement E1 = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("M0:46:::4:2-imgStd")));
WebElement E1 = driver.findElement(By.xpath("//span[#id='M0:46:::4:2-imgSymb']"));
E1.click();
//driver.findElement(By.id("M0:46:::4:2-imgStd")).click();
//driver.findElement(By.xpath("//span[#id='M0:46:::4:2-imgStd']")).click();
//Thread.sleep(1200);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
Receiving error as :
Exception in thread "main" org.openqa.selenium.NoSuchFrameException: no such frame
HTML Source:
for iframe:
<iframe id="ITSFRAME1" name="itsframe1_20190401041759.3908120" noresize="1" frameborder="0" framespacing="0" border="0" scrolling="no" onload="null" style="visibility: visible; z-index: 999; top: 0px; left: 0px;" src="javascript:(function(){document.open();document.domain='dijon.cob.csuchico.edu';self.frameElement.oWguHandlerItsMgrFrame.finalize(); })();"></iframe>
For Radio Buttons:
enter code here <span id="M0:46:::4:2-imgStd" class="lsRBImgStd lsCBImgStdDef lsCBImgStdDefHv"><span id="M0:46:::4:2-imgSymb" class="lsRBImgSymb lsRBImgSel"></span></span>
Here is my answer from a previous question on this. (Copy/Paste) It works 100% of the time (assuming you have JQuery available on the page; if not we can make an alternative):
So this is ultimately the perfect use case for an extension I made. Here is the most important part of it:
/// <summary>
/// Selenium sometimes has trouble finding elements on the page. Give it some help by using JQuery to grab the full qualified xpath to that element.
/// </summary>
/// <param name="cssSelector"></param>
/// <returns></returns>
public static string GetFullyQualifiedXPathToElement(string cssSelector, bool isFullJQuery = false, bool noWarn = false)
{
if (cssSelector.Contains("$(") && !isFullJQuery) {
isFullJQuery = true;
}
string finder_method = #"
function getPathTo(element) {
if(typeof element == 'undefined') return '';
if (element.tagName == 'HTML')
return '/HTML[1]';
if (element===document.body)
return '/HTML[1]/BODY[1]';
var ix= 0;
var siblings = element.parentNode.childNodes;
for (var i= 0; i< siblings.length; i++) {
var sibling= siblings[i];
if (sibling===element)
return getPathTo(element.parentNode)+'/'+element.tagName+'['+(ix+1)+']';
if (sibling.nodeType===1 && sibling.tagName===element.tagName)
ix++;
}
}
";
if(isFullJQuery) {
cssSelector = cssSelector.TrimEnd(';');
}
string executable = isFullJQuery ? string.Format("{0} return getPathTo({1}[0]);", finder_method, cssSelector) : string.Format("{0} return getPathTo($('{1}')[0]);", finder_method, cssSelector.Replace("'", "\""));
string xpath = string.Empty;
try {
xpath = BaseTest.Driver.ExecuteJavaScript<string>(executable);
} catch (Exception e) {
if (!noWarn) {
Check.Warn(string.Format("Exception occurred while building a dynamic Xpath. Css selector supplied to locate element is \"{0}\". Exception [{1}].", cssSelector, e.Message));
}
}
if (!noWarn && string.IsNullOrEmpty(xpath)) {
Check.Warn(string.Format("Supplied cssSelector did not point to an element. Selector is \"{0}\".", cssSelector));
}
return xpath;
}
With this logic, you can pass a Jquery selector into your browser via javascript executor. JQuery has no problems finding elements nested within iframes. Try something like this:
driver.FindElement(By.XPath(GetFullyQualifiedXPathToElement("#MyDeeplyNestedElement")).Click();
https://gist.github.com/tsibiski/04410e9646ee9ced9f3794266d6c5a82
Feel free to remove whatever is in that method/class that does not apply to your situation.
Why/How does this suddenly make an element findable to Selenium????
You may have noticed that if you tell selenium to find an iframe html element, and then explicitly search within the WebElement of the iframe, that you can find child elements under it. However, without first finding each child iframe, Selenium does not seem to look inside the iframes without you explicitly helping it through the DOM.
JQuery does not have this limitation. It sees every registered DOM element just fine, and will grab it normally. Once you have the element as a JQuery object, you can build out a path of tags, parent by parent, all the way up the DOM. When the logic is complete, you will have a fully-qualified XPath from the top of the DOM down to the nested child element. Then, once this explicit XPath is supplied to Selenium, you are holding its hand down the rabbit hole through one or more iframes until it runs into the object you want.
Try these...
driver.SwitchTo().DefaultContent();
IWebElement iframe = driver.FindElement(By.Id("ITSFRAME1"));
driver.SwitchTo().Frame(iframe);
Related
I am automating amazon.com, and I am currently trying to move to a specific element in a drop down menu. No matter how specific I make my xpath for this element, WebDriver will only move the mouse to the first item in the list.
Here is the HTML code:
<div class="nav-template nav-flyout-content nav-tpl-itemList">
<span class="nav-hasPanel nav-item" data-nav-panelkey="InstantVideoPanel" role="navigation" aria-label="Amazon Video">
<span class="nav-text">Amazon Video</span>
</span>
<span class="nav-hasPanel nav-item" data-nav-panelkey="DigitalMusicPanel" role="navigation" aria-label="Amazon Music">
<span class="nav-text">Amazon Music</span>
</span>
<span class="nav-hasPanel nav-item" data-nav-panelkey="AndroidPanel" role="navigation" aria-label="Appstore for Android">
<span class="nav-text">Appstore for Android</span>
</span>
Here is my automation code:
#Test
public void departmentsDropMusic1() throws Exception {
driver = new FirefoxDriver();
driver.get("https://www.amazon.com");
Thread.sleep(3000L);
WebElement element = driver.findElement(By.xpath("//a[#id='nav-link-shopall']"));
Actions action = new Actions(driver);
action.moveToElement(element).build().perform();
Thread.sleep(3000L);
WebElement dropDown = driver.findElement(By.cssSelector("#nav-flyout-shopAll > div:nth-child(2)"));
if (dropDown.isDisplayed()) {
System.out.println("pass");
} else {
Assert.fail();
}
WebElement musicSubMenu = driver.findElement(By.xpath(//span[contains(text(), 'Amazon Music')]"));
action.moveToElement(musicSubMenu).build().perform();
Thread.sleep(3000L);
I have tried other xpaths as well, using the various labels provided in the html code, to no avail. WebDriver will only move to the first element (aria-label "Amazon Video"), and not the other elements listed.
Interestingly enough, when I use a for-loop to move through all of the items in the menu, there are no issues.
It is moving to first element in the dropdown as all elements of sub categories are loading when we move to first element in the list.
To overcome this, we need to move to the first element before moving to any other elements in the list. I have created one method to solve your issue. If you pass the sub menu name than it will move over on the sub menu.
The code is given below.
#Test
public void departmentsDropMusic1() throws Exception {
System.setProperty("webdriver.gecko.driver", "C:\\Projects\\SeleniumDrivers\\geckodriver.exe");
driver = new FirefoxDriver();
driver.get("https://www.amazon.com");
Thread.sleep(5000L);
openSubMenu("Amazon Music");
openSubMenu("Fire TV");
}
The open sub menu method code is here,
public void openSubMenu(String menu) throws InterruptedException{
//mouse over on Main menu 'Departments'
WebElement element = driver.findElement(By.xpath("//a[#id='nav-link-shopall']"));
Actions action = new Actions(driver);
action.moveToElement(element).build().perform();
Thread.sleep(5000L);
//verify sub menus are listed or not
WebElement dropDown = driver.findElement(By.cssSelector("#nav-flyout-shopAll"));
if (dropDown.isDisplayed()) {
System.out.println("pass");
} else {
Assert.fail();
}
//
WebElement subMenu1 = driver.findElement(By.cssSelector("#nav-flyout-shopAll > div.nav-tpl-itemList>span:nth-child(1)"));
WebElement subMenuWantedToOpen = driver.findElement(By.cssSelector("#nav-flyout-shopAll > div.nav-tpl-itemList>span[aria-label='"+menu.trim()+"']"));
action.moveToElement(subMenu1).moveToElement(subMenuWantedToOpen).build().perform();
Thread.sleep(5000L);
WebElement subMenuCat = driver.findElement(By.cssSelector(".nav-subcats > div.nav-subcat[style='display: block;']"));
if(subMenuCat.isDisplayed()){
System.out.println(subMenuCat.getText());
}
}
It is working fine for me. Check and let me know if any difficulties.
When you are automating the large sites like amazon.com, please be sure that the element has no child node, when you try to inspect it through firebug, and some times it depends on the browser itself make sure you are using latest web browser version.
I have my simple selenium program that validate if the value search box in the google is equal to hello world but i got this error:
Exception in thread "main"
org.openqa.selenium.NoSuchElementException: no such element: Unable to
locate element: {"method":"name","selector":"q"}....
Here's my complete code
public class SimpleSelenium {
WebDriver driver = null;
public static void main(String args[]) {
SimpleSelenium ss = new SimpleSelenium();
ss.openBrowserInChrome();
ss.getPage();
ss.listenForHelloWorld();
ss.quitPage();
}
private void openBrowserInChrome(){
System.setProperty("webdriver.chrome.driver", "C:/chromedriver.exe");
driver = new ChromeDriver();
}
private void quitPage() {
driver.quit();
}
private void getPage() {
driver.get("http://www.google.com");
}
private void listenForHelloWorld() {
WebElement searchField = driver.findElement(By.name("q"));
int count = 1;
while (count++ < 20) {
if (searchField.getAttribute("value").equalsIgnoreCase("hello world")) {
break;
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Do you wait until the page is ready and element displayed?
I've often got this error when the page is still loading. You could add something like
(MochaJS example, pretty much the same API for JAVA tests)
test.it('should check the field existence', function (done) {
let field_by = By.id(ID_OF_THE_FIELD);
driver.wait(until.elementLocated(field_by,
driver.wait(until.elementIsVisible(driver.findElement(field_by)), TIME_TO_WAIT_MS);
done();
});
You wait until the element is visible. If it failed, the timeout of TIME_TO_WAIT_MS will be raised.
The google search bar will never have "hello world" in it because you haven't typed it in?
Also the search field value doesn't seem to update when you type in a search (if you inspect the element using the Console).
If your just learning I would just write a test like this and the click the search button, then confirm the "hello world" text in the search results:
WebElement searchField = driver.findElement(By.name("q"))
searchField.sendKeys("Hello World")
//Add code to click search button
//Add code to assert results on next page
Also I would completely change your listenForHelloWorld() method and use the built in WebDriver ExpectedConditions:
new WebDriverWait(driver, 10)
.until(ExpectedConditions.textToBePresentInElement(searchField, "Hello World"))
I want to click the 'Followed' button until it found in the web page.
I've below code:
#Test
public void testCar() throws Exception
{
driver.get("https://-----/login/");
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.findElement(By.id("username")).clear();
driver.findElement(By.id("username")).sendKeys("user");
driver.findElement(By.id("password")).clear();
driver.findElement(By.id("password")).sendKeys("password");
driver.findElement(By.xpath("//button[#type='submit']")).click();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.findElement(By.xpath("//span[text()='Followed']")).click();
}
How can I do this? if not found the element then click next page & find the button again.
here is the next button HTML:
<span>Next Page</span>
Please help.
Just put a loop around with try catch
try {
while (true)
{
driver.findElement(By.xpath("//span[text()='Followed']")).click();
}
} catch (ElementNotFoundException ex) {
driver.findElement(By.xpath("//span[text()='Next Page']")).click()
}
If the element is found it will be clicked, if not then a element not found exception will be thrown and that time you can click on the Next page button
Check the condition weather Followed button available or not for that you have to use List to get followed webelements Like :
Boolean buttonNotFound = true;
while(buttonNotFound)
{
List<WebElement> follow = driver.findElements(By.xpath("//span[text()='Followed']"));
if(follow.size()!=0)
{
follow.get(0).click();
buttonNotFound=false;
}
else
{
driver.findElement(By.xpath("//span[text()='Next Page']")).click();
}
}
NOTE : Don't write ImplicitWait again and again, If you have mentioned at one place right below the get() then it is applicable for whole script. If some element require some more time to interact then use ExplicitWait.
I'm currently using PhantomJS + Selenium to populate some form fields but having weird results. 50% of the time, the test runs fine. The other 50% it errors out and gives me the following
{"errorMessage":"Element is not currently interactable and may not be
manipulated"
I'm doing the following to make sure the page is loaded.
private static boolean waitForJQueryProcessing(WebDriver driver,
int timeOutInSeconds) {
boolean jQcondition = false;
try {
new WebDriverWait(driver, timeOutInSeconds) {
}.until(new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver driverObject) {
return (Boolean) ((JavascriptExecutor) driverObject)
.executeScript("return jQuery.active == 0");
}
});
jQcondition = (Boolean) ((JavascriptExecutor) driver)
.executeScript("return window.jQuery != undefined && jQuery.active === 0");
return jQcondition;
} catch (Exception e) {
logger.debug(e.getMessage());
}
return jQcondition;
}
And then to interact with the element(s):
pageWait.until(ExpectedConditions.presenceOfElementLocated(By
.cssSelector("#myForm-searchDate")));
driver.findElement(
By.cssSelector("#myForm-searchDate"))
.sendKeys(Keys.CONTROL + "a");
driver.findElement(
By.cssSelector("#myForm-searchDate"))
.sendKeys(Keys.DELETE);
driver.findElement(
By.cssSelector("#myForm-searchDate"))
.sendKeys(MY_TEST_DATE);
I could see if it failed all the time, but it doesn't fail all the time so it's hard to repeat the results when debugging.
Edit 1. I've tried swapping following the comment below; however, it doesn't work. I've since come to realize this seems to only happen when I fire up several (5+) instances of PhantomJS at once.
I posed with a difficult task. I am fairly new to selenium and still working through the functionalities of waiting for elements and alike.
I have to manipulate some data on a website and then proceed to another. Problem: the manipulation invokes a script that makes a little "Saving..." label appear while the manipulated data is being processed in the background. I have to wait until I can proceed to the next website.
So here it is:
How do i wait for and element to DISAPPEAR? Thing is: It is always present in the DOM but only made visible by some script (I suppose, see image below).
This is what I tried but it just doesn't work - there is no waiting, selenium just proceeds to the next step (and gets stuck with an alert asking me if I want to leave or stay on the page because of the "saving...").
private By savingLableLocator = By.id("lblOrderHeaderSaving");
public boolean waitForSavingDone(By webelementLocator, Integer seconds){
WebDriverWait wait = new WebDriverWait(driver, seconds);
Boolean element = wait.until(ExpectedConditions.invisibilityOfElementLocated(webelementLocator));
return element;
}
UPDATE / SOLUTION:
I came up ith the following solution: I built my own method. Basically it checks in a loop for the CssValue to change.
the loops checks for a certain amount of time for the CSSVALUE "display" to go from "block" to another state.
public void waitForSavingOrderHeaderDone(Integer _seconds){
WebElement savingLbl = driver.findElement(By.id("lblOrderHeaderSaving"));
for (int second = 0;; second++) {
if (second >= _seconds)
System.out.println("Waiting for changes to be saved...");
try {
if (!("block".equals(savingLbl.getCssValue("display"))))
break;
} catch (Exception e) {
}
}
You can wait for a WebElement to throw a StaleElementReferenceException like this:
public void waitForInvisibility(WebElement webElement, int maxSeconds) {
Long startTime = System.currentTimeMillis();
try {
while (System.currentTimeMillis() - startTime < maxSeconds * 1000 && webElement.isDisplayed()) {}
} catch (StaleElementReferenceException e) {
return;
}
}
So you would pass in the WebElement you want to wait for, and the max amount of seconds you want to wait.
Webdriver has built in waiting functionality you just need to build in the condition to wait for.
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, SECONDS)
.pollingEvery(5, SECONDS)
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return (driver.findElements(By.id("lblOrderHeaderSaving")).size() == 0);
}
});
I'm not sure, but you can try something like this :)
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //time in second
WebElement we = driver.findElement(By.id("lblOrderHeaderSaving"));
assertEquals("none", we.getCssValue("display"));
This works with selenium 2.4.0. you have to use the invisibility mehtod to find it.
final public static boolean waitForElToBeRemove(WebDriver driver, final By by) {
try {
driver.manage().timeouts()
.implicitlyWait(0, TimeUnit.SECONDS);
WebDriverWait wait = new WebDriverWait(UITestBase.driver,
DEFAULT_TIMEOUT);
boolean present = wait
.ignoring(StaleElementReferenceException.class)
.ignoring(NoSuchElementException.class)
.until(ExpectedConditions.invisibilityOfElementLocated(by));
return present;
} catch (Exception e) {
return false;
} finally {
driver.manage().timeouts()
.implicitlyWait(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
}
}
I used following C# code to handle this, you may convert it to Java
public bool WaitForElementDisapper(By element)
{
try
{
while (true)
{
try
{
if (driver.FindElement(element).Displayed)
Thread.Sleep(2000);
}
catch (NoSuchElementException)
{
break;
}
}
return true;
}
catch (Exception e)
{
logger.Error(e.Message);
return false;
}
}
You can also try waiting for the ajax calls to complete. I've used this to check when the page load is complete and all the elements are visible.
Here's the code - https://stackoverflow.com/a/46640938/4418897
You could use XPath and WebDriverWait to check whether display: none is present in the style attribute of an element. Here is an example:
// Specify the time in seconds the driver should wait while searching for an element which is not present yet.
int WAITING_TIME = 10;
// Use the driver for the browser you want to use.
ChromeDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, WAITING_TIME);
// Replace ELEMENT_ID with the ID of the element which should disappear.
// Waits unit style="display: none;" is present in the element, which means the element is not visible anymore.
driver.wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[#id='ELEMENT_ID'][contains(#style, 'display: block')]")));
Try using invisibilityOfElementLocated method.
You can reference example here How to wait until an element no longer exists in Selenium?
enter image description hereI created my own method for element disappearing from dom....
In Conditions class (In .m2\repository\org\seleniumhq\selenium\selenium-support\3.141.59\selenium-support-3.141.59.jar!\org\openqa\selenium\support\ui\ExpectedConditions.class)
we can see that 'isInvisible' method with 'isDisplayed' method,,, i wrote the same with 'isEnabled'
public static ExpectedCondition<Boolean> invisibilityOf(final WebElement element) {
return new ExpectedCondition<Boolean>() {
#Override
public Boolean apply(WebDriver webDriver) {
return isRemovedFromDom(element);
}
#Override
public String toString() {
return "invisibility of " + element;
}
};
}
private static boolean isRemovedFromDom(final WebElement element) {
try {
return !element.isEnabled();
} catch (StaleElementReferenceException ignored) {
return true;
}
}