Wednesday, June 26, 2013

Making Capybara integration testing play nicely with jQuery Elastic

One of the coolest ways to test the hell out of your Rails app, or any Rack-based app, is Capybara - it opens an actual browser window, in your test environment, and automatically executes all the instructions you give it - going to whatever page you like, logging into your app, interacting with form elements, the lot, saving you the hassle of doing it manually every time you make the tiniest little change you think might cripple your app.

Elastic is a jQuery plugin. It dynamically expands textareas to hold their content. You know what it's like. You're typing in a textarea, and bam, you run out of space, scrollbars appear, and you have to scroll like mad to access the novel you're writing. Elastic changes all that. A hell of a useful plugin.

As I discovered over several agonizing hours recently, though, Capybara and Elastic sometimes do not play nicely together. See, when you type into an Elastic-ified textarea, it's not actually a textarea at all. It's a custom div made by the plugin. If you right-click it in Chrome and choose "Inspect Element", you might see something like this:


1
2
3
4
5
6
<div style="border: 1px solid rgb(161, 161, 161); display: none;
font-family: sans-serif; font-size: 13px; font-weight: 400; line-height: normal;
padding: 5px; position: absolute; white-space: pre-wrap; width: 470px;
word-wrap: break-word;">
Your Content Here
</div>


Okay, so what? you may ask. So you're typing into an autogenerated div instead of a textarea. Does this break the form the textarea's in? No. When you hit Submit, the plugin copies your expand-o-div's contents back into the original textarea, ensuring all is fine and dandy?

So what's the problem?

The problem comes to light when you're running Capybara tests to ensure that the textarea contains the content you think it does. Say you're putting together a comment submission form in Rails. The textarea HTML will look something like this:

1
2
3
<textarea id="comment_content" name="comment[content]">
Your Content Here
</textarea>


Somewhere in your Javascript, you'll have a line saying

$('#comment_content').elastic()


And in your integration tests, you might have something saying

page.find('textarea[name="comment[content]"]')['value'].should eq "Hey look, I've typed this after calling elastic()"


And bam. It fails.

Failure/Error
 page.find('textarea[name="comment[content]"]')['value'].should eq
"Hey look, I've typed this after calling elastic()"

expected to find text "Hey look, I've typed this after calling elastic()"
actually found "Your Content Here.". The content <i>before</i> you 
called elastic(). I know why, and I could tell you why, but you're just a
silly human, you wouldn't understand.


If you're anything like me, you can spend several agonizing hours staring, frazzled and homicidal, at this infuriating message. Or you can be slightly smarter than I was, put two and two together, and realise that, hey, you need to trigger the form's submit() method to copy your expand-o-div's content back into the original textarea. Then you're golden.

No comments:

Post a Comment