Capybara and div contentEditable
At Glassbreakers, we use Rspec/Capybara for our testing framework.
One recent front-end issue that we just encountered was figuring out how to deal with filling in forms that aren’t input fields. The code change required changing it over from an input field, either an <input type="text”>
or a textarea
element into contentEditable divs (ie: <div contentEditable="true">
). This was done in order to create text fields that are more dynamic.
Design context
Our existing textfields use textarea
elements. By default, a textarea element’s height is set (automatically by the browser if not given parameters) and does not size up and down (unless manipulated by CSS). So any text that goes beyond the set height will become hidden, and a scrollbar is added to scroll through the textarea content.
This change was about changing the textarea
box into a dynamic auto-height text field that sizes up with the amount of content inside the field. We want to minimize empty space being taken up from textfields that are not in use yet. This unfortunately isn’t how the HTML textarea
element works.
This is a mockup of the design we want, where we have a single line text area that will size up once we have content that fills in.
Our solution is to convert the fields into <div contentEditable="true">
fields as div
elements size up based on the content in the element.
We had a textarea element already on the feature and our existing tests were using the fill_in
Capybara method.
fill_in(:comment_body, with: “aaa”)
However with a change to a contentEditable div, this test method no longer works as it is not supported and this is where we started running into problems.
It took a while trying to look up how to deal with this change.
Using set to fill in the field
find(“.comments__textarea”).set(“aaa”)
The first option was to try using the set
method. Although it achieves the purpose of filling in the content of the div, it does not trigger JavaScript, and bypasses any validation and dynamic behavior — which in our case is to show and hide the Send button only when it is necessary.
Simulating keystrokes
find(“.comments__textarea”).base.send_keys(“aaa”)
Eventually, we found the send_keys method. It can be used to simulate keystrokes, and perfect in our case, because we can’t use fill_in
and set
does not trigger JavaScript. It requires usage of the native
or in our case, thebase
method at first.
This was able to achieve the functionality that fill_in
was able to do but for non-text class="input"
and non-textarea
fields.
There aren’t that many references I could find dealing with this issue, but much thanks to the few Stackoverflow posts out there who pointed us in the right direction.