Selenium-Java-geckodriver:测试执行因 JavaScript 错误而停止,因为“document.getElementById(...) is null”

Posted

技术标签:

【中文标题】Selenium-Java-geckodriver:测试执行因 JavaScript 错误而停止,因为“document.getElementById(...) is null”【英文标题】:Selenium-Java-geckodriver : Test Execution halts with JavaScript error as "document.getElementById(...) is null" 【发布时间】:2017-10-24 19:01:27 【问题描述】:

我遇到这个问题已经有一段时间了。在 SO 和其他论坛上浏览了很多主题,但仍然一无所知。

在 Eclipse Neon v2 IDE 中使用 Selenium 3.4.0、geckodriver v0.16.1 和 Mozilla Firefox 53.0 在 Web 应用程序上自动执行简单流程时,我在控制台上间歇性地遇到错误:

javascript error: https://www.url.com/my, line 1715: TypeError: document.getElementById(...) is null

虽然使用 chromedriver v2.29/Google Chrome 58.0 或使用 Python,但我没有遇到任何此类问题。

一旦出现此错误,测试执行将停止并最终显示TimeoutException,如下所示:

Exception in thread "main" org.openqa.selenium.TimeoutException: Timeout loading page after 300000ms

网站网址为:https://www.shareinvestor.com/my

html DOM 是:

<div id="sic_sitemap">
  <div id="sic_container">
    <div id="sic_header">
      <h1 id="sic_siteTitle">
        <div id="sic_headerMembershipLink">
          <a id="sic_mobileEdition" href="/mobile">
            <div id="sic_loginContainer" class="sic_logIn" style="">
              <div class="sic_login-wrap">
                <div class="sic_logIn-subscribe">
                  <div class="sic_logIn-bg">
                    <a href="/user/login.html">
                  </div>
                </div>
              </div>
            </div>
            <div id="sic_subHeader">
              <div id="sic_mainNav" class="sic_withRightCorner">
                <div id="sic_sideBar" class="sic_expanded  selected_market_suffix: 'MY'">
                  <div class="sic_superBanner sic_superBannerTop">
                    <div id="sic_content" class="sic_collapsed">
                      <div id="sic_footer" class="si_fixed">
                      </div>

到目前为止,我已经尝试了以下选项,但无济于事:

    Java 点击 JavascriptExecutor 点击 点击操作

这是我的代码:

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.DesiredCapabilities;

public class 78644072022 

public static void main(String[] args) 

    System.setProperty("webdriver.gecko.driver", "C:\\Utility\\BrowserDrivers\\geckodriver.exe");
    DesiredCapabilities dc = DesiredCapabilities.firefox();
    dc.setCapability("marionette", true);
    WebDriver driver =  new FirefoxDriver(dc);
    driver.manage().window().maximize();
    driver.get("https://www.shareinvestor.com/my");
    WebElement login_button = driver.findElement(By.xpath("//div[@id='sic_loginContainer']/div/div[@class='sic_logIn-bg']/a"));

    //Java Click
    login_button.click();

    //JavascriptExecutor Click
    /*JavascriptExecutor jse = (JavascriptExecutor)driver;
    jse.executeScript("arguments[0].click();", login_button);*/

    //Actions Click
    /*Actions act = new Actions(driver);
    act.moveToElement(login_button).click().build().perform();*/

    driver.findElement(By.xpath("//input[@id='sic_login_header_username']")).sendKeys("debanjan");
    driver.findElement(By.xpath("//input[@id='sic_login_header_password']")).sendKeys("5786");
    driver.findElement(By.xpath("//input[@id='sic_login_submit']")).click();


我正在寻找带有 geckodriver 的 Java 解决方案来克服错误 JavaScript error:TypeError: document.getElementById(...) is null

在SO threads 之一中,我看到了类似的解决方案:

您需要像这样在 updateHTML 中进行空检查:

function updateHTML(elmId, value) 
  var elem = document.getElementById(elmId);
  if(typeof elem !== 'undefined' && elem !== null) 
    document.getElementById(elmId).innerHTML = value;
  

我们可以实现吗? 任何建议和指示都会有所帮助。

【问题讨论】:

你完成了 console.log(document) 并检查了它不为空吗?也许您必须通过您使用的 webdriver 通过 window.document.getElementById() 访问(这只是一个想法) @dev 你在哪里使用 document.getElementById() 在你的代码中? @mtizziani 感谢您的快速浏览。你能指导我设置console.log(document) 来检查它不为空吗?谢谢 @kushal。我没有使用那个。那是控制台上的错误导致了麻烦。谢谢 @dev 你的意思是浏览器控制台? 【参考方案1】:

我正在寻找带有 geckodriver 的 Java 解决方案来克服错误 JavaScript error:TypeError: document.getElementById(...) is null

要回答您的问题,我认为您无法通过 Java/Selenium 来“修复”此问题。这是一个 JavaScript 错误,源自您尝试访问的网站。您可能需要考虑 contacting 他们的支持团队,也许他们的一位开发人员可以查看此问题。


与其点击登录按钮,不如考虑直接导航到登录页面?

driver.get("https://www.shareinvestor.com/user/login.html");

【讨论】:

【参考方案2】:

首先,这些 javascript 错误不会由于任何 selenium 代码而触发。当然,超时是由 selenium 触发的(稍后会讨论)。

无论您使用何种浏览器启动 URL,您都会收到该 javascript 错误。但是在壁虎的情况下,您会在 Eclipse 控制台中收到通知,但在 Chrome 的情况下不会。如果您需要在 chrome 中查看 java 脚本错误,只需在 chrome 中启动 url 并转到 devtools/console(F12)。您也可以在 Firefox 控制台中看到相同的内容。

Chrome 图片:

其次,我们收到超时异常,因为该网站确实花费了太多时间来加载。我已经等了 7 分钟,即使现在页面仍在加载。除非页面已完全启动,否则 Selenium 不会执行其脚本。结果我们得到了超时异常(不确定允许的默认页面启动时间)。我想过直接绕过登录页面(“https://www.shareinvestor.com/user/login.html”),这也不需要任何有限的时间来完全加载。

插入:那些 java 脚本错误对于自动化来说不是问题,但那些页面加载确实是。此站点似乎不是解决此问题的自动化的理想候选者。

更新1:否则我们也可以通过另一个线程停止页面加载,例如使用Action类发送“esc”键序列。

Update2:我今天尝试了相同的代码,它运行良好。下面是我尝试过的代码sn-p(完全没有变化)

 public static void main(String[] args) throws InterruptedException 

    System.setProperty("webdriver.gecko.driver", "F:\\Softwares\\Selenium\\Webdriver\\geckodriver.exe");
    WebDriver driver = new FirefoxDriver();
    driver.manage().window().maximize();
    driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
    driver.get("https://www.shareinvestor.com/my");
    WebElement login_button = driver.findElement(By.xpath("//div[@id='sic_loginContainer']/div/div[@class='sic_logIn-bg']/a"));

    //Java Click
    login_button.click();
    System.out.println("In Login PAge");

    driver.findElement(By.xpath("//input[@id='sic_login_header_username']")).sendKeys("debanjan");
    driver.findElement(By.xpath("//input[@id='sic_login_header_password']")).sendKeys("5786");
    System.out.println("Entered password");
    driver.findElement(By.xpath("//input[@id='sic_login_submit']")).click();

Selenium 版本 - 3.4.0

Gecko 驱动程序 - v0.16.1(我的是 32 位)

Mozilla - 51.0.1(更新=>它也在 53.02 上运行)

希望这对您有所帮助。谢谢。

【讨论】:

我理解了这个问题,那么有什么办法可以通过 Selenium/Java 绑定来克服/解决这个问题?谢谢 将其称为问题是不公平的。正如我在问题中提到的,通过 Chrome 浏览器或 Python/Ruby 绑定,我不会遇到这个障碍。甚至 Node.js 也有出路。但是,我正在从 Java/Mozilla 绑定的角度寻找解决方案。谢谢 我的意思是……它现在可以在 mazilla 中工作了。昨天我尝试它时甚至没有在 chrome 中工作。现在它可以在 Firefox 和 chrome 上运行 感谢您的支持和时间帮助我进行这项研究。【参考方案3】:

我想我已经设法在您的脚本中找到了造成这种骚动的原因。 我检查了您的 HTML,似乎 javascript 方法 function showRemaining() 导致了这个问题;因为showRemaining()包含了这个语句

    document.getElementById('countdown').innerHTML = '';

它尝试将id为countdown的元素的innerHTML属性设置为''。

但是您的网页上的任何地方都不存在倒计时,因此出现错误。

TypeError: document.getElementById(...) is null

不知何故 selenium 无法忽略这个错误。所以我认为从开发人员那里得到修复应该会对你有所帮助。

更新:

基本上,您需要使用隐式等待来等待所有元素加载,一旦加载了所有元素,您的 Javascript 错误就会得到解决,最终与网页的交互不会受到该 javascript 错误的阻碍:

        driver.get("https://www.shareinvestor.com/my");

        driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
        driver.manage().window().maximize();

        /*String script = "function updateHTML(countdown, value) " +
                "var elem = document.getElementById('countdown');"+
                "if(typeof elem !== 'undefined' && elem !== null) "+
                " document.getElementById('countdown').innerHTML = value;"+
                ""+
                "";

        ((JavascriptExecutor) driver).executeScript(script);*/

        WebElement login_button = driver.findElement(By.xpath("//div[@id='sic_loginContainer']/div/div[@class='sic_logIn-bg']/a"));

        login_button.click();

        driver.findElement(By.xpath("//input[@id='sic_login_header_username']")).sendKeys("debanjan");
        driver.findElement(By.xpath("//input[@id='sic_login_header_password']")).sendKeys("5786");
        driver.findElement(By.xpath("//input[@id='sic_login_submit']")).click();

【讨论】:

如果你直接进入登录页面;它会起作用;因为这个导致错误的脚本在您的着陆页上。 如果你只使用 chromedriver;那么它在任何情况下都能正常工作,我猜是不同浏览器引擎的原因。 你是对的。我在几个地方面临这个问题。所以想解决这个问题。谢谢 是的,我已经提到 Chrome 可以顺利通过,没有任何问题。谢谢 但它不应该提示您使用 Firefox 执行,因为您可以直接导航到登录页面并从那里开始您的工作。【参考方案4】:

看起来login_button 的 XPath 不正确:

By.xpath("//div[@id='sic_loginContainer']/div/div[@class='sic_logIn-bg']/a");

应该是:

By.xpath("//div[@id='sic_loginContainer']/div/div/div[@class='sic_logIn-bg']/a");

这可以解释TimeoutException,因为 Selenium 无法找到不存在的元素。 编辑:我的错误,如果无法找到该元素,您应该看到 NoSuchElementException

至于 JavaScript 错误,除非您尝试使用 Selenium 访问被 JavaScript 代码(id='countdown' 元素)操作的 Web 元素,否则 Selenium 应该忽略该错误。否则,可能会出现其他 Selenium 错误,例如 StaleElementReferenceException,但情况似乎并非如此。

【讨论】:

你能不能考虑帮我理解你为什么感觉XPath for the login_button is incorrect。我已经在问题区域中提到了实际 URL,用于直接访问 HTML DOM。如果我的xpath 不正确,那么我会遇到NoSuchElementException,但事实并非如此。谢谢 那么您的代码 sn-p 不正确,我基于此 XPath。另外,如果无法找到该元素,您应该得到一个NoSuchElementException 是正确的,我已经使用 Selenium 有一段时间了... 我已经更新了 HTML DOM 并使用了适当的格式条件供您参考。谢谢【参考方案5】:

这是由于您的应用程序 HTML 页面使用了异步 javascript,并且它使用了一些在执行时不可用的变量引用。我们遇到了同样的问题,并要求开发人员遵循 HTML 中 javascript 的一些最佳实践,例如将脚本标记放在页面末尾。我检查了该站点的 HTML 页面源代码,它在代码之间包含许多脚本标签。这将阻止 DOM 渲染。更好的是,要求开发人员遵循一些最佳实践,在 HTML 中包含 script 标签。您参考链接Where should I put <script> tags in HTML markup? 了解最佳做法。

【讨论】:

您能否考虑帮我理解async javascriptvariable reference that is not available at the time of execution 的确切含义?谢谢 Async JavaScript 只不过是带有 asyn 属性的脚本标签。它将在页面加载时从源代码下载 JavaScript 库,并在下载后执行它。引用变量是一个引用一些 HTML 元素,它是由来自另一个库的 JavaScript 生成的

以上是关于Selenium-Java-geckodriver:测试执行因 JavaScript 错误而停止,因为“document.getElementById(...) is null”的主要内容,如果未能解决你的问题,请参考以下文章