【问题标题】:selenium button click not triggering inline javascript event handler硒按钮单击不触发内联javascript事件处理程序
【发布时间】:2020-04-29 05:47:58
【问题描述】:

我的 HTML 如下所示

<div class="container">
    <div class="jumbotron">
        <h1 id="survey-title" class="display-5 text-capitalize">Your favourite candidate</h1>
        <hr class="my-4">

        <div class="card-body">
            <h5 id="question-title" class="card-title">What is your name?</h5>

            <form id="question_form" action="/survey/takesurvey/1/2" method="post" class="form">
                <input type="hidden" name="csrfmiddlewaretoken" value="ELBWYGZRxRuI7CoZ2xkmgCJ3f9JweFMM4Ew1pQbgSE3BLb38VStPJEbHvsyiBEFg">
                <div class="form-group"><input type="text" name="response" value="asdfasdfas" maxlength="400" class="form-control" title="" id="id_response"></div>
            </form>
        </div>

        <a id="btn-previous" href="javascript:history.back()" class="btn btn-primary ">Previous</a>
        <a id="btn-next" href="/survey/takesurvey/finish/1" class="btn btn-primary">Next</a>
    </div>
</div>

注意上一个按钮上的href

&lt;a id="btn-previous" href="javascript:history.back()" class="btn btn-primary "&gt;Previous&lt;/a&gt;

点击下一步将提交表单并转到“下一页”页面,再次点击“上一页”应返回并保留上一页中的输入值。我正在使用以下代码来测试此行为,以下代码仅在我将sleep(1)line 放在查找元素和单击之间时才有效。否则页面不会返回(网址不变)

  • 为什么在点击按钮前等待网址更改不起作用
  • 我怀疑这与未加载 javascript 事件处理程序(在 html 中内联)有关。
  • 我有什么方法可以检查页面是否已为点击事件做好准备
cur_url = self.browser.current_url
self.browser.find_element_by_id('btn-next').click()

wait(lambda: self.assertNotEqual(self.browser.current_url, cur_url))
btn_previous = self.browser.find_element_by_id('btn-previous')

## This code is not working without the sleep below. Which I suspect 
## has to do with javascript event handler (which is inline in html) not being loaded.
## Is there better way to check that the button is ready to be clicked
sleep(1)

btn_previous.click()

【问题讨论】:

  • 如果你在做测试,应该在 onclick 而不是 href。如果您没有返回,还有更简单的方法。
  • 当我把它放在 onclick 时是一样的,当我把它放在 sleep(1) 时你可能会注意到它的工作原理

标签: python selenium selenium-chromedriver


【解决方案1】:

您可以将WebDriverWaitelement_to_be_clickable 条件一起使用。也检查here

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

WebDriverWait(self.browser, 5).until(EC.element_to_be_clickable((By.ID, "btn-previous"))).click()

您可以尝试等待 JavaScript:

WebDriverWait(self.browser, 20).until(lambda d: d.execute_script(
        'return (document.readyState == "complete" || document.readyState == "interactive")'))

# or without interactive 
WebDriverWait(self.browser, 20).until(lambda d: d.execute_script(
        'return document.readyState == "complete"'))

【讨论】:

  • 感谢您的解决方案,但结果与我之前的代码相同。代码越过了浏览器网址不变的行。它仅在行前使用 sleep(1) 时才有效
  • 等待 JS 完成检查答案更新
  • 谢谢,是的,点击按钮后检查 readyState 的解决方案有效
【解决方案2】:

这不是理想的解决方案,而是目前对我有用的解决方法。

我的等待功能

from time import sleep
from functools import wraps
from selenium.common.exceptions import NoSuchElementException

def wrap_in_wait(func, retires=5):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return wait(func, *args, retires=retires, **kwargs)
    return wrapper

def wait(func, *args, retires=10, exceptions=[AssertionError, NoSuchElementException], **kwargs):
    for i in range(retires):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            print('retry', i)
            if type(e) not in exceptions:
                raise e

            if i == retires-1:
                raise e

            sleep(0.5 + i*.2)


使用 Workaround 解决方案测试功能

def test_question_form_is_loaded_with_existing_answer(self):
        '''Test question form pre-loads'''
        self.browser.get(self.live_server_url + self.url)
        inp = self.browser.find_element_by_css_selector("input#id_response")
        inp.send_keys("This is my answer")

        self.browser.find_element_by_id('btn-next').click()

        @wrap_in_wait
        def click_previous_button():
            btn_previous = self.browser.find_element_by_id('btn-previous')
            btn_previous.click()
            inp = self.browser.find_element_by_css_selector("input#id_response")
            self.assertEqual(inp.get_attribute('value'), "This is my answer")

        click_previous_button()

如果引发AssertionError or NoSuchElementException 异常,此解决方案会重试click_previous_button 10 次。它正在第二次尝试。

但我仍然不确定为什么即使按钮可点击也不会触发 javascript 事件以及是否有直接的方法来测试 javascript 何时准备就绪

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    • 2012-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多