【问题标题】:Selenium - after bootstrap modal test, subsequent test fail with error ElementClickInterceptedErrorSelenium - 在引导模式测试之后,后续测试失败并出现错误 ElementClickInterceptedError
【发布时间】:2020-08-15 15:41:26
【问题描述】:

启动引导模式并关闭它后,selenium 无法在页面上找到任何其他元素。

三个按钮显示在下面的屏幕中。其中两个按钮的功能是启动引导模式并关闭它,第三个按钮(中间一个)的功能是简单地接收“点击”。

单独测试时,对所有 3 个按钮进行测试时效果很好,但在集体测试时会失败。

第一次启动并关闭模式的测试将通过,但随后的测试失败并出现 ElementClickInterceptedError。

中间有足够的隐式等待,以便模态可以正确加载,但问题仍然存在。

PS - 如果您最终需要尝试,请按照以下步骤操作 1) 复制以下 2 个文件 2) 使用 npm install selenium-webdriver 安装 selenium webdriver 3) 根据您的测试更改 fileName 变量自己的文件夹。

错误堆栈跟踪

DevTools 监听 ws://127.0.0.1:50210/devtools/browser/81f6bc5f-c6f5-4255-9134-5efa67a92bed [13108:12832:0501/100716.495:ERROR:browser_switcher_service.cc(238)] XXX Init() ElementClickInterceptedError:元素点击被拦截: 元素 ... 在点 (233, 67) 处不可点击。其他元素 会收到点击:... (会话信息:chrome=81.0.4044.129) 在 Object.throwDecodedError (D:\ip300-gk\node_modules\selenium-webdriver\lib\error.js:550:15) 在 parseHttpResponse (D:\ip300-gk\node_modules\selenium-webdriver\lib\http.js:565:13) 在 Executor.execute (D:\ip300-gk\node_modules\selenium-webdriver\lib\http.js:491:26) 在 processTicksAndRejections (internal/process/task_queues.js:93:5) 在异步 Driver.execute (D:\ip300-gk\node_modules\selenium-webdriver\lib\webdriver.js:700:17) 在异步 uitest (D:\ip300-gk\Samples\bootstrap\bs-modal-selenium\uitest.js:34:13) {
名称:'ElementClickInterceptedError',

测试脚本

const driver = require('selenium-webdriver')
const assert = require('assert').strict;
const {Builder, By, Key, until} = require('selenium-webdriver');

let fileName = "D:\\ip300-gk\\Samples\\bootstrap\\bs-modal-selenium\\index.html"


function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms))
}

(async function uitest() {
        let driver = await new Builder().forBrowser('chrome').build();
        let  element
        try {
            await driver.get(fileName)

            //Launch Modal 1 and close
            await driver.findElement(By.id('launchModalButton')).click()
            await driver.manage().setTimeouts( { implicit: 1000} )
            await driver.findElement(By.id('closeButton')).click()


            // middle button click 
             await driver.manage().setTimeouts( { implicit: 1000} )
             await driver.findElement(By.id('button')).click()

            //Launch Modal 2 and close
            await driver.manage().setTimeouts( { implicit: 1000} )
            await driver.findElement(By.id('launchModalButton_2')).click()
            await driver.manage().setTimeouts( { implicit: 1000} )
            element = await 
            driver.wait(until.elementLocated(By.id('closeButton_2')))
            await element.click()

        } catch (err) {
            console.log(err)
        } finally {
            await driver.quit();
        }
    }
)()

引导页面

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
          integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <title>Selenium </title>
</head>
<body>

<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
        integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
        crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
        integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
        crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
        integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
        crossorigin="anonymous"></script>

<div class="container">

    <button type="button" id="launchModalButton" class="btn btn-primary mt-5" data-toggle="modal"
            data-target="#exampleModal">
        Launch modal
    </button>

    <button type="button" id="button" class="ml-3 btn btn-primary mt-5">
        Button
    </button>

    <button type="button" id="launchModalButton_2" class="ml-3 btn btn-primary mt-5" data-toggle="modal"
            data-target="#exampleModal_2">
        Launch modal 2
    </button>

    <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
         aria-hidden="true">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="exampleModalLabel">Modal 1</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    Modal 1
                </div>
                <div class="modal-footer">
                    <button id="closeButton" type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                    <button id="saveChangesButton" type="button" class="btn btn-primary">Save changes</button>
                </div>
            </div>
        </div>
    </div>

    <div class="modal fade" id="exampleModal_2" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel_2"
         aria-hidden="true">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="exampleModalLabel_2">Modal 2</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    Modal 2
                </div>
                <div class="modal-footer">
                    <button id="closeButton_2" type="button" class="btn btn-secondary" data-dismiss="modal">Close
                    </button>
                    <button id="saveChangesButton_2" type="button" class="btn btn-primary">Save changes</button>
                </div>
            </div>
        </div>
    </div>
</div>

</body>
</html>

【问题讨论】:

    标签: javascript twitter-bootstrap selenium selenium-webdriver webdriver


    【解决方案1】:

    您不需要每次都使用隐式等待。在进行点击操作之前,您需要等待的是元素的可见性。

    在等待条件中有一个elementIsVisible 方法可用。我已修改代码以检查元素是否存在,然后在单击之前检查元素的可见性。

    (async function uitest() {
        let driver = await new Builder().forBrowser('chrome').build();
        let element
        try {
            await driver.get(fileName)
    
            //Launch Modal 1 and close
            await driver.findElement(By.id('launchModalButton')).click()
            let closeButton1 = await driver.wait(until.elementLocated(By.id('closeButton')))
            closeButton1 = await driver.wait(until.elementIsVisible(closeButton1))
            await closeButton1.click()
    
            // middle button click 
            await driver.findElement(By.id('button')).click()
    
            //Launch Modal 2 and close
            await driver.findElement(By.id('launchModalButton_2')).click()
            let closeButton2 = await driver.wait(until.elementLocated(By.id('closeButton_2')))
            closeButton2 = await driver.wait(until.elementIsVisible(closeButton2))
            await closeButton2.click()
    
        } catch (err) {
            console.log(err)
        } finally {
            await driver.quit();
        }
    }
    )()
    

    【讨论】:

      【解决方案2】:

      此错误消息...

      [13108:12832:0501/100716.495:ERROR:browser_switcher_service.cc(238)] XXX Init() ElementClickInterceptedError: element click intercepted: Element ... is not clickable at po int (233, 67). 
      Other element would receive the click: ... (Session info: chrome=81.0.4044.129)
      

      ...暗示当您在其上调用click() 时,所需的元素不可点击。


      正如您提到的 启动模式并关闭它的测试将通过,但随后的测试因 ElementClickInterceptedError 而失败本质上意味着当您在第二个元素上调用 click()Button kbd> 在那个时间点,包含文本为 Launch modal 的元素的Modal Dialog Box 仍在遮挡所需的元素。因此,在所需元素上的 click 失败。

      详情

      implicit wait 开始可能不适用于使用JavaScriptAngularReactJSjQueryAJAXVue.jsEmber.js 等构建的现代应用程序。

      实际上你需要replace implicit wait with explicit wait


      selenium-webdriver/lib/until

      • elementLocated:创建一个循环条件,直到找到具有给定定位器的元素。

        /**
         * Creates a condition that will loop until an element is
         * {@link ./webdriver.WebDriver#findElement found} with the given locator.
         *
         * @param {!(By|Function)} locator The locator to use.
         * @return {!WebElementCondition} The new condition.
         */
        exports.elementLocated = function elementLocated(locator) {
          locator = by.checkedLocator(locator);
          let locatorStr =
              typeof locator === 'function' ? 'by function()' : locator + '';
          return new WebElementCondition('for element to be located ' + locatorStr,
              function(driver) {
            return driver.findElements(locator).then(function(elements) {
              return elements[0];
            });
              });
        };
        
      • elementIsVisible:创建一个等待给定元素可见的条件。

        /**
         * Creates a condition that will wait for the given element to become visible.
         *
         * @param {!./webdriver.WebElement} element The element to test.
         * @return {!WebElementCondition} The new condition.
         * @see ./webdriver.WebDriver#isDisplayed
         */
        exports.elementIsVisible = function elementIsVisible(element) {
          return new WebElementCondition('until element is visible', function() {
            return element.isDisplayed().then(v => v ? element : null);
          });
        };
        

      解决方案

      因此,将 implicit wait 替换为 explicit wait 的有效代码块将是:

      (async function uitest() {
          let driver = await new Builder().forBrowser('chrome').build();
          let  element
          try {
              await driver.get(fileName)
      
              //Click Launch Modal
              let launchModal = await driver.wait(until.elementLocated(By.id('launchModalButton')))
              launchModal = await driver.wait(until.elementIsVisible(launchModal))
              await launchModal.click()
      
              //Close Launch Modal
              let closeModal = await driver.wait(until.elementLocated(By.id('closeButton')))
              closeModal = await driver.wait(until.elementIsVisible(closeModal))
              await closeModal.click()
      
              //Click Button
              let button = await driver.wait(until.elementLocated(By.id('button')))
              button = await driver.wait(until.elementIsVisible(button))
              await button.click()
      
              //Click Launch Modal 2 and close
              let launchModal2 = await driver.wait(until.elementLocated(By.id('launchModalButton_2')))
              launchModal2 = await driver.wait(until.elementIsVisible(launchModal2))
              await launchModal2.click()
      
              //Close Launch Modal 2
              let closeButton2 = await driver.wait(until.elementLocated(By.id('closeButton_2')))
              closeButton2 = await driver.wait(until.elementIsVisible(closeButton2))
              await closeButton2.click()          
      
          } catch (err) {
              console.log(err)
          } finally {
              await driver.quit();
          }
          }
      )()
      

      参考文献

      您可以在以下位置找到一些相关的讨论:

      【讨论】:

        【解决方案3】:

        要绕过 ElementNotClickable(这是 Web 驱动程序逻辑),您可以只使用 JavaScript 点击。

        var element = await driver.findElement(By.id('button'))
        driver.executeScript('arguments[0].click();', element)
        

        【讨论】:

          猜你喜欢
          • 2020-09-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-19
          • 1970-01-01
          • 1970-01-01
          • 2022-08-10
          • 2017-02-18
          相关资源
          最近更新 更多