1

I have been trying to automate a few manual checks using cucumber and selenium and trying to make a click event on a menu item inside a iframe. Below is the skeleton of the source.

<html>
<head>...</head>
<frameset rows="100%,*" border="0">
    <frame src="/XXXX/index.dsp" cd_frame_id_="03af6e390xxxxxxxxx0b209e24f67b9fab">
        <html>
            <body>  
                <iframe class="menuframe" name="menu" src="menu.dsp" scrolling="yes" seamless="seamless">
                    <html>
                    <head>..</head>
                    <body class="menu"...........>
                        <table class="menuTable".............>
                            <tbody>                                         
                                <tr>......</tr>
                                <tr>......</tr>
                                <tr>......</tr>

                                <tr manualhide="true" onclick="toggle(this, 'XXX_subMenu', 'XXXX_twistie');" onmouseover="this.className='cursor';" class="cursor">
                                    <td class="menusection menusection-collapsed" id="elmt_XXXX_subMenu">
                                        <img id="XXXX_twistie" src="/XXXX/images/collapsed_blue.png">
                                          &nbsp;XXXX  
                                    </td>
                                </tr>
                                <tr>......</tr>
                                <tr>......</tr>
                            </tbody>
                    </body>
                </iframe>

                <iframe class="contentframe" name="body" id="body" src="stats-general.dsp">
                .............
                </iframe>

            </body>
        </html>
    </frame>
</frameset>

I am trying to click on the above with id elmt_XXXX_subMenu.

As i read in a few blogs it is required to switch to frame. I have tried the following.

driver.switchTo().defaultContent();
// switch to frame
driver.switchTo().frame(0); 

// switch to menu iframe, It throws an exception
driver.switchTo().frame("menu"); 

// When replaced by following line also it throws same exception
// driver.switchTo().frame(driver.findElement(By.name("menu")));

Below is the stacktrace.

 org.openqa.selenium.JavascriptException: javascript error: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
  (Session info: chrome=83.0.4103.97)
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'
System info: host: 'XXXX', ip: 'XX.XX.XXX.XXX', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_221'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 83.0.4103.97, chrome: {chromedriverVersion: 83.0.4103.39 (ccbf011cb2d2b..., userDataDir: C:\Users\XXXXXX~1\AppData\L...}, goog:chromeOptions: {debuggerAddress: localhost:58320}, javascriptEnabled: true, networkConnectionEnabled: false, pageLoadStrategy: normal, platform: WINDOWS, platformName: WINDOWS, proxy: Proxy(), setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:virtualAuthenticators: true}
Session ID: f2e850e3e43d7782902297879bc70bc4
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
    at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
    at org.openqa.selenium.remote.RemoteWebDriver$RemoteTargetLocator.frame(RemoteWebDriver.java:892)
    at XXX.XXXX.XXXX.pages.TestPage.test(TestPage.java:40)
    at XXX.XXXX.XXXX.stepdefinitions.TestSteps.test_method(TestSteps.java:137)
    at ?.Then Check menu(basicChecks.feature:12)

Kindly suggest if it is not the right way to do it? Many thanks in advance.

Update: As Per @DebanjanB answer, Tried using suggested snippet(both css selector and xpath),

new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.cssSelector("frame[src*='index']")));
new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.cssSelector("iframe.menuframe[name='menu']")));
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(By.cssSelector("td.menusection.menusection-collapsed#elmt_XXXX_subMenu"))).click();

Throws same exception at line 2

org.openqa.selenium.JavascriptException: javascript error: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
  (Session info: chrome=83.0.4103.97)
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'
System info: host: 'XXXX', ip: 'XX.XX.XXX.XXX', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_221'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 83.0.4103.97, chrome: {chromedriverVersion: 83.0.4103.39 (ccbf011cb2d2b..., userDataDir: C:\Users\XXXXXX~1\AppData\L...}, goog:chromeOptions: {debuggerAddress: localhost:58320}, javascriptEnabled: true, networkConnectionEnabled: false, pageLoadStrategy: normal, platform: WINDOWS, platformName: WINDOWS, proxy: Proxy(), setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:virtualAuthenticators: true}
Session ID: 79f14698ee49ff2f4308b7f7930ee8b1
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
    at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
    at org.openqa.selenium.remote.RemoteWebDriver$RemoteTargetLocator.frame(RemoteWebDriver.java:892)
    at org.openqa.selenium.support.ui.ExpectedConditions$17.apply(ExpectedConditions.java:501)
    at org.openqa.selenium.support.ui.ExpectedConditions$17.apply(ExpectedConditions.java:497)
    at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:249)
    at XXX.XXXX.XXXX.pages.TestPage.test(TestPage.java:26)
    at XXX.XXXX.XXXX.stepdefinitions.TestSteps.test_method(TestSteps.java:137)
    at ?.Then Check menu(basicChecks.feature:12)
Nagaraja JB
  • 729
  • 8
  • 18

3 Answers3

1

To click() on the element within the <iframe> which is within a <frame> so you have to:

  • Induce WebDriverWait for the first frameToBeAvailableAndSwitchToIt.
  • Induce WebDriverWait for the second frameToBeAvailableAndSwitchToIt.
  • Induce WebDriverWait for the desired elementToBeClickable.
  • You can use either of the following Locator Strategies:

    • Using cssSelector:

      new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.cssSelector("frame[src*='index']")));
      new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.cssSelector("iframe.menuframe[name='menu']")));
      new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(By.cssSelector("td.menusection.menusection-collapsed#elmt_XXXX_subMenu"))).click();
      
    • Using xpath:

      new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("//frame[contains(@src, 'index')]")));
      new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("//iframe[@class='menuframe' and @name='menu']")));
      new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(By.xpath("//td[@class='menusection menusection-collapsed' and @id='elmt_XXXX_subMenu']"))).click();
      

Note: As per the current HTML you have provided the following <iframe> looks to be closed which may not be true:

<iframe class="menuframe" name="menu" src="menu.dsp" scrolling="yes" seamless="seamless"></iframe>

Reference

You can find a couple of relevant discussions in:

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • Many thanks for the detailed answer. Sorry that there was a mistake while writing html skeleton in the question. I just updated it. Using css selector and xpath, I get same exception in the second line (stacktrace in the question). new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.cssSelector("iframe.menuframe[name='menu']"))); Log: org.openqa.selenium.JavascriptException: javascript error: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'. – Nagaraja JB Jun 18 '20 at 03:23
  • @NagarajaJB Instead of the hand crafted HTML can you update the question with the text based actual HTML please? – undetected Selenium Jun 18 '20 at 06:51
  • 1
    I was able to get it working using index again to switch to iframe. Many thanks for your answer. – Nagaraja JB Jun 19 '20 at 08:08
1

I was able to get get it working by switching content by index. Using System.out.println(driver.getPageSource()); to log page source to console and make sure i am working at the right spot. I tried to find iframes by tag and print their name as following.

List<WebElement> elements = DriverContext.driver.findElements(By.tagName("iframe"));
elements.forEach(element -> System.out.println(element.getAttribute("name"))); // printed 'menu' and 'body', perfect

But, while switching content to iframe using name, tried also using WebDriverWait,

driver.switchTo().frame(driver.findElement(By.name("menu")));

for whatever reason, it didn't work and kept throwing the exception as in the question.

Using index to switch to iframe followed by click on the element worked.

driver.switchTo().frame(0); // switch to frame
driver.switchTo().frame(0); // switch to first iframe

driver.findElement(By.id("elmt_XXXX_subMenu")).click();

Also, i had used WebDriverWait to wait for page load.

WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(webDriver -> ((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equals("complete"));
Nagaraja JB
  • 729
  • 8
  • 18
0

.frame() is used to switch the element to an iframe and it takes an element as its parameter, so you need to pass the element there. Also, element with "0" is not a type of iframe, so you don't need the driver.switchTo().frame(0) line of code.

You just need switch the driver to the menu iframe and then click on the element.

For switching to the menu iframe you need to use:

driver.switchTo().frame(driver.findElement(By.name("menu"))); 
Sameer Arora
  • 4,439
  • 3
  • 10
  • 20
  • Many thanks for your answer. I get below org.openqa.selenium.NoSuchElementException if i try to switch to the iframe directly. I tried adding WebDriverWait also. Caused by: org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"*[name='menu']"} If i switch to frame and try, then exception as in the question. – Nagaraja JB Jun 18 '20 at 04:12