【问题标题】:How to set content into mui-rte with selenium webdriver in python?如何在 python 中使用 selenium webdriver 将内容设置为 mui-rte?
【发布时间】:2019-11-30 20:35:29
【问题描述】:

我在 react 项目中使用 mui-rte 富文本编辑器 (https://github.com/niuware/mui-rte)。在编写 selenium webdriver 集成测试时,我无法弄清楚如何将文本输入到 rte 输入区域。

据我了解,mui-rte 是 Draftjs 的 materia-ui 包装器。反应代码很简单:

<MUIRichTextEditor
        onChange={onChange}
        value={initial}
        {...rest}
/ >

这会生成以下 html 元素:

<div id="mui-rte-container" class="MUIRichTextEditor-container-73">
<div id="mui-rte-toolbar" class="MUIRichTextEditor-toolbar-84">
    ...
</div>
<div id="mui-rte-editor" class="MUIRichTextEditor-editor-75">
    <div id="mui-rte-editor-container" class="MUIRichTextEditor-hidePlaceholder-79 MUIRichTextEditor-editorContainer-76">
        <div class="DraftEditor-root">
            <div class="DraftEditor-editorContainer">
                <div aria-describedby="placeholder-9mnek" class="notranslate public-DraftEditor-content" role="textbox" spellcheck="false" style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word" contenteditable="true">
                    <div data-contents="true"><div class="" data-block="true" data-editor="7kjuh" data-offset-key="8a2rc-0-0">
                        <div data-offset-key="8a2rc-0-0" class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr">
                            <span data-offset-key="8a2rc-0-0">
                                <br data-text="true">
                            </span>
                        </div>
                    </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

我可以很容易地找到任何元素,但是当我尝试这个时:

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
from selenium.webdriver.support import expected_conditions as EC # available since 2.26.0
from selenium.webdriver.common.by import By

rte_editor = WebDriverWait(self.driver, 2).until(
        EC.presence_of_element_located((By.ID, id))
    )
rte_input = bio_rte.find_element_by_xpath("//div[@role='textbox']")
rte_input.send_keys("Hello")

我明白了:

E       selenium.common.exceptions.ElementNotInteractableException: Message: Element <div class="notranslate public-DraftEditor-content"> is not reachable by keyboard

我尝试过的所有元素。

在python中使用selenium-webdriver将文本输入draft.js rte的正确方法是什么?我对 selenium+webdriver 很陌生,任何帮助都将不胜感激,无论是 python、JavaScript 还是其他风格的 selenium-webdriver API。

我这里有一个示例项目:https://github.com/vessper/formik-mui-rte-example

更新:

包括来自错误的堆栈跟踪:

self = <test.TestBase testMethod=test_input_text_in_rte>

    def test_input_text_in_rte(self):
        rte_input = WebDriverWait(self.driver, 20).until(
            EC.element_to_be_clickable(
>               (By.XPATH, '//div[@class="notranslate public-DraftEditor-content" and @role="textbox"]'))
        )

test.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <selenium.webdriver.support.wait.WebDriverWait (session="38c21bf5-27ea-499d-9831-e8755a10f57a")>
method = <selenium.webdriver.support.expected_conditions.element_to_be_clickable object at 0x7f7115fe7198>, message = ''

    def until(self, method, message=''):
        """Calls the method provided with the driver as an argument until the \
        return value is not False."""
        screen = None
        stacktrace = None

        end_time = time.time() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, 'screen', None)
                stacktrace = getattr(exc, 'stacktrace', None)
            time.sleep(self._poll)
            if time.time() > end_time:
                break
>       raise TimeoutException(message, screen, stacktrace)
E       selenium.common.exceptions.TimeoutException: Message:

../../../.virtualenvs/ml2/lib/python3.7/site-packages/selenium/webdriver/support/wait.py:80: TimeoutException
================================================================= 1 failed in 24.70s ==================================================================

【问题讨论】:

    标签: reactjs selenium material-ui webdriverwait draftjs


    【解决方案1】:

    在我的例子中,它是一个带有 contenteditable div

    draft.js 富文本编辑器
    async sendKeysToContentEditableDiv(element, text) {
        const script = `var txtarea = arguments[0],txt = arguments[1];
        txtarea.dispatchEvent(new Event("focus"));
        var txtEvt = document.createEvent("TextEvent");
        txtEvt.initTextEvent("textInput", true, true, null, txt);
        txtarea.dispatchEvent(txtEvt);     
        txtarea.dispatchEvent(new Event("blur"));`;
        await this.driver.executeScript(script, element, text);
    }
    

    【讨论】:

      【解决方案2】:

      所需元素是启用了ReactJS 的元素,以便定位并发送字符序列 到您必须为element_to_be_clickable() 诱导WebDriverWait 的元素,然后您可以使用以下任一解决方案:

      • 使用CSS_SELECTOR

        WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.notranslate.public-DraftEditor-content[role='textbox']"))).send_keys("Vess_Perfanov")
        
      • 使用XPATH

        WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[@class='notranslate public-DraftEditor-content' and @role='textbox']"))).send_keys("Vess_Perfanov")
        
      • 注意:您必须添加以下导入:

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

      更新

      由于click() 仍未被WebDriverWait 调用,您可以按如下方式使用ActionChains

      • 使用CSS_SELECTOR:

        element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.notranslate.public-DraftEditor-content[role='textbox']"))).send_keys("Vess_Perfanov")
        ActionChains(driver).move_to_element(element).click(element).send_keys("Vess_Perfanov").perform()
        
      • 使用XPATH

        element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[@class='notranslate public-DraftEditor-content' and @role='textbox']"))).send_keys("Vess_Perfanov")
        ActionChains(driver).move_to_element(element).click(element).send_keys_to_element(element, "Vess_Perfanov").perform()
        

      【讨论】:

      • 你好。这似乎是在正确的方向,但它仍然不起作用。如果我什么都不做,代码会超时,但是如果我在等待发生时单击 webdriver 浏览器中的元素,则文本会被输入。我在这里实现了测试:[github.com/vessper/formik-mui-rte-example/blob/master/test.py].我还需要做什么? click() 也不起作用,但是关注这个元素的正确方法是什么?
      • @VessPerfanov 查看更新的答案并告诉我状态。
      • 再次感谢,在仔细查看序列后,我注意到我省略了 material-UI 放置在文本框上方的覆盖标签元素。必须使用您的建议之一来聚焦和单击此元素。这是我的疏忽,我很抱歉。我现在有一个工作测试。我想我应该发布正确的答案。感谢您的帮助。
      • @VessPerfanov 好消息!!!很高兴能帮到你!!!在 StackOverflow 上,我们通过acceptingThanks 最佳 answer 并通过 upvoting answers 帮助解决您的问题问题。
      【解决方案3】:

      Material-UI 中有一个内联标签元素,需要先单击它才能发现底层文本字段。所以以下对我有用。

      from selenium import webdriver
      from selenium.common.exceptions import TimeoutException
      from selenium.webdriver.support.ui import WebDriverWait
      from selenium.webdriver.support import expected_conditions as EC
      from selenium.webdriver.common.by import By
      from selenium.webdriver import ActionChains
      import unittest
      
      
      class TestBase(unittest.TestCase):
      
      def setUp(self):
          self.driver = webdriver.Firefox()
          self.driver.get(URL)
      
      def tearDown(self):
          self.driver.close()
      
      def get_by_id(self, id):
          return WebDriverWait(self.driver, 5).until(
              EC.presence_of_element_located((By.ID, id))
          )
      def test_input_text_in_rte(self):
          description_msg = "Hello There"
          rte_container = self.get_by_id('mui-rte-container')
          rte_label = rte_container.find_element_by_xpath("//*[contains(text(), 'Description:')]")
          actions = ActionChains(self.driver)
          actions.move_to_element(rte_label)
          actions.click(rte_label)
          actions.perform()
      
          rte_input = WebDriverWait(self.driver, 5).until(
              EC.presence_of_element_located((By.XPATH,
                  '//div[@class="notranslate public-DraftEditor-content" and @role="textbox"]'))
          )
      
          rte_input.send_keys(description_msg)
      

      感谢@DebanjanB 提供上述代码中的建议。

      【讨论】:

        猜你喜欢
        • 2021-07-19
        • 1970-01-01
        • 2014-09-15
        • 1970-01-01
        • 2019-04-04
        • 1970-01-01
        • 2017-09-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多