Reputation:
I need to input text into a field in a table that doesn't have the input tag. This XPath points out the field uniquely
//div[@id="contentBody"]//div[@row="0"]/div[contains(@class, "l4") and contains(@class, "r4")]
(one can add a trailing /div
to this XPath, it makes no difference)
I can use this XPath to read this field but when I try to insert some text in the same field I get an error message:
InvalidElementStateException: Message: invalid element state: Element must be user-editable in order to clear it.
This is the HTML for the cell
<div class="slick-cell l4 r4 alignRight uppercase highint editable-cell active selected" aria-describedby="inforDataGrid731693C5" tabindex="-1" role="gridcell">
<div class="edit-cell">2,0</div></div>
I found this question (which, BTW, does seem to be erroneously marked as a duplicate)
Element must be user-editable in order to clear it exception in selenium
The comments there seem to make sense for my situation: my XPath points to a div, not an input field (but as you can see, the div's class is "edit-cell" so...) but I don't think I have the option to point an input field. How do I work around this - how to find which element to target, so I can set its text successfully, without taht exception?
Upvotes: 3
Views: 2284
Reputation: 20067
The conclusion you came to is the corrected one - you cannot send input to a <div>
tag, that's not how browsers usually work (an exception to the rule is given in "edit 2"). The code exception states it clearly - "Element must be user-editable in order to clear it". Regardless that the div has a class value of "edit-cell" - that just a name chosen by a developer, for illustrative proposed; it does not imply the div will be able to take input.
Most probably the UI used by the application uses this <div>
for stylized presentation of the values set by the user; there is a hidden <input>
element that takes the actual keyboard entries, and a javascript code updates the <div>
with them.
You'll have to find that input tag, and target it for your changes.
Here's how to find the input tag - in the browser, (by hand) set the value to a string that would be unique for the page - for instance, "myMegaSpecialString". Then run the following js in the console:
[...document.getElementsByTagName("input")].forEach(function(el){ if (el.value == "myMegaSpecialString"){console.log(el);} })
It will print the <input>
element(s) that has that "special" value.
According to the discussion in the comments, no <input>
element was found to have this value. As I was rightfully corrected by @Andersson, under special circumstances other elements but input can receive, khm, input - they should have the contenteditable
attribute, and it's inherited from parent elements - e.g. if set on the <body>
tag, you can type over any element in the page.
So - a modified version of the javascript to locate "who holds our value"; thankfully, getElementsByTagName()
supports wildcard for argument - that'll match any element:
[...document.getElementsByTagName("*")].forEach(function(el){ if (el.value == "myMegaSpecialString"){console.log(el);} })
It might be a bit slower - but it must print the element(s) with value
property equal to "myMegaSpecialString".
The quest continues - the text you are entering does not turn up in any element's value
property? No problem, let's look for it in the elements textual content.
This might be the case when you are actually editing the content of a <span>
, <div>
or similar tags (fingers crossed... :)).
This is a variation of the previous version - manually set the text to a value that is unique across the page (to limit the output), and run this in the console:
[...document.getElementsByTagName("*")].forEach(function(el){ if (el.textContent.indexOf("myMegaSpecialString") !== -1){console.log(el);} })
, which will (should? might? I'm not certain in anything anymore :D) print in the console all DOM elements which have that string as part of their text.
Breakdown what is what in the javascript, for future changes:
document.getElementsByTagName("*")]
returns a all elements with that tag name as an array; the argument asterisk (*
) - any tag name.forEach
- a loop over the collection elements, passing each one to the anonymous function in it.el.textContent
- returns the text content of the node (and its child nodes).indexOf()
- returns the position of the argument in the string, -1
if it is not present (used indexOf()
vs contains()
for compatibility, the later comes in ES6).console.log(el)
will print it in the console.Upvotes: 1
Reputation: 193108
This error message...
InvalidElementStateException: Message: invalid element state: Element must be user-editable in order to clear it.
...implies that a WebElement is in a state in which actions cannot be performed on it. Examples would include an element being obscured by another when clicking, or perhaps not being visible on the DOM.
As the element is a JavaScript enabled element you need to induce WebDriverWait to be element to be clickable and you can use either of the following solutions:
Wait Until Element Is Visible
:
Wait Until Element Is Visible xpath=//div[contains(@class, 'slick-cell') and starts-with(@aria-describedby,'inforDataGrid')]/div[@class='edit-cell'] 20 seconds
Set Focus To Element xpath=//div[contains(@class, 'slick-cell') and starts-with(@aria-describedby,'inforDataGrid')]/div[@class='edit-cell']
# invoke click
Wait Until Element Is Enabled
:
Wait Until Element Is Enabled xpath=//div[contains(@class, 'slick-cell') and starts-with(@aria-describedby,'inforDataGrid')]/div[@class='edit-cell'] 20 seconds
Set Focus To Element xpath=//div[contains(@class, 'slick-cell') and starts-with(@aria-describedby,'inforDataGrid')]/div[@class='edit-cell']
# invoke click
Upvotes: -1