简体   繁体   English

selenium 按钮单击不会触发内联 javascript 事件处理程序

[英]selenium button click not triggering inline javascript event handler

My HTML looks like below我的 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>

Notice the href on previous button注意上一个按钮上的href

<a id="btn-previous" href="javascript:history.back()" class="btn btn-primary ">Previous</a>

Clicking next will submit form and go to "next" page, again clicking "previous" should come back and preserve the input value in previous page.单击下一步将提交表单并转到“下一页”,再次单击“上一页”应返回并保留上一页的输入值。 I am using following code to test this behavior, The following code is working only when I put sleep(1) line in between finding the element and clicking.我正在使用以下代码来测试此行为,以下代码仅在我将sleep(1)行置于查找元素和单击之间时才有效。 Else the page is not going back (url not changing)否则页面不会返回(网址不变)

  • Why just waiting for url change before clicking the button not working为什么在单击按钮之前等待 url 更改不起作用
  • I suspect it has to do with javascript event handler (which is inline in html) not being loaded.我怀疑这与未加载 javascript 事件处理程序(在 html 中内联)有关。
  • I is there any way to check if page is ready for the click event我有什么方法可以检查页面是否已准备好单击事件
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()

You can use WebDriverWait with element_to_be_clickable condition.您可以将WebDriverWaitelement_to_be_clickable条件一起使用。 Check here also.也请检查这里

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()

You can try wait for JavaScript:您可以尝试等待 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"'))

This is not the desired solution but a workaround the worked for me for now.这不是理想的解决方案,而是目前对我有用的解决方法。

My functions for wait我的等待功能

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)


Test function with Work around solution使用变通解决方案测试功能

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()

This solution retries click_previous_button for 10 times if it raises AssertionError or NoSuchElementException exception.如果它引发AssertionError or NoSuchElementException异常,此解决方案将重试click_previous_button 10 次。 It is working on 2nd try.它正在进行第二次尝试。

But I am still not sure why javascript event is not triggered even when the button is clickable and if there is direct way to test when javascript is ready但我仍然不确定为什么即使按钮可点击也不会触发 javascript 事件,以及是否有直接的方法来测试 javascript 何时准备就绪

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM