How to set content into mui-rte with selenium webdriver in python?

送分小仙女□ 提交于 2020-03-03 17:14:14

问题


I am using mui-rte rich text editor (https://github.com/niuware/mui-rte) in a react project. I am not able to figure out how to input text to the rte input area when writing a selenium webdriver integration test.

As I understand correctly, mui-rte is a materia-ui wrapper of draftjs. The react code is simply:

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

This generates the following html elements:

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

I can easily find any of the element but when I try this for example:

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

I get:

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

With all elements that I have tried.

What is the correct way to input text into draft.js rte with selenium-webdriver in python? I am quite new to selenium+webdriver and any help will be appreciated, be it in python, JavaScript or other flavor of selenium-webdriver API.

I have a sample project here: https://github.com/vessper/formik-mui-rte-example

update:

Including the stack trace from the error:

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 ==================================================================

回答1:


In my case it was a draft.js rich text editor with a contenteditable div

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:


The desired element is a ReactJS enabled element so to locate and send a character sequence to the element you have to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following solutions:

  • Using 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")
    
  • Using 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")
    
  • Note : You have to add the following imports :

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

Update

As the click() is still not invoked with WebDriverWait you can use ActionChains as follows:

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



回答3:


There is an inline label element from Material-UI that needs to be clicked first to uncover the underlying text field. So the following work for me.

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)

Thanks to @DebanjanB for the suggestions that are incorporated in the code above.



来源:https://stackoverflow.com/questions/59120039/how-to-set-content-into-mui-rte-with-selenium-webdriver-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!