Testing HTML5 Messages with RSpec/Selenium

Mike Schutte
2 min readApr 15, 2017

--

For context, we are in the land of Rails, RSpec, and Capybara with Selenium for testing JavaScript and async features. We have a simple create form, and we want to validate the presence and type of the input fields.

Instead of validating at the model or database level, why not skip the request/response altogether with a required attribute on your HTML5 forms? Given a required presence, we get a nice error like this:

Built in validations in HTML5 fields with the “required” property.

And given a URL type requirement with type="url" in the input field, an invalid entry like medium.com will produce an error like this:

because it doesn’t have an http:// or https:// prefix.

Lovely.

But in Rails and RSpec land, where we use feature and unit tests to beautifully document our applications, it becomes trickier to prove that

As a user,
when I forget to fill in an input field
I see an message that says "Please fill out this field."

Typically, when using flash messages in Rails, a simple RSpec expectation like:

expect(page).to have_content "Please fill out this field."

would do. However, using HTML5 validations introduces deeply embedded JS magic that is not readable by more familiar Capybara methods. The expectation snippet above does not evaluate to true even though I’d see the warning pop up on the Selenium browser.

When I ran into this problem, I searched the googles and the stack overflows without any real success. I also had a heck of a time reading through the docs to figure out how to prove that the validation message was indeed popping up.

Having recently done a basic calorie tracker project all in vanilla JS (no jQuery no nothin’), I was confident that the validation message had to be somewhere in the labyrinth of the DOM. So, I persisted in my quest to verify the message, and landed on this solution:

describe "if I leave the url blank" do
it "I get an error on the same page" do
fill_in "link_title", with: "New Title"
fill_in "link_url", with: ""
click_on "Update"

message =
page.find("#link_url").native.attribute("validationMessage")
expect(message).to eq "Please fill out this field."
expect(current_path).to eq edit_link_path(user.links.first)
end
end

And voila: a client-side validation that is well documented in the tests, and saves us a trip to the server. Looks pretty nice for the user too.

Test on!

--

--

Mike Schutte

Licensed Driver 🚗 TSA Pre ® AeroPress Barista ☕️ Conversational in Emoji 🤟 Anti-mouse (💻✚🏠) Pro-listening 👂he/him 👨‍💻 @TEDTalks