---
title: Decoupling Data from Presentation
teaser:
tags: web,rails,testing
author: Josh Clayton
published_on: 2012-02-02
---

I'm really happy to see a resurgence in an understanding that writing
integration tests that use classes and DOM structure to perform assertions
within these tests is typically a bad idea. The DOM structure constantly changes
but the data displayed (the stuff we want to assert is present on a page)
typically doesn't.

Why write tests against some markup that a designer may change, sometimes often
if he's iterating over a design? It'll end up causing everyone headaches and
frustration.

How can we mark up our documents without performing assertions against a deep
nesting of classes and elements while ensuring our data is displayed properly?

Data attributes.

The browsers I care about support HTML5, so why not start using some of its
capabilities to clean up some integration tests?

Imagine this scenario:

    Scenario: See the site description on the homepage
      When I am on the homepage
      Then I should see the site description

Simple, straightforward, and each step is a similar level of abstraction.

Now imagine this markup:

    <section class="primary-content">
      <header>
        <h1>Welcome to the site!</h1>
        <h2>Insert a witty tagline here</h2>
      </header>
      <p class="description">This product will make your life 100 times
      better.</p>
    </section>

I could write a step like this:

```ruby
Then "I should see the site description" do
  page.should have_selector("section.primary-content p.description",
                            text: "This product will make your life 100 times better.")
end
```

This step is asserting that there's a section element with a class of
primary-content who has a child paragraph tag with a class of description that
contains the correct text.  Classes change. Structure changes. This is begging
to be rewritten.

```html
<section data-role="primary-content">
  <header>
    <h1>Welcome to the site!</h1>
    <h2>Insert a witty tagline here</h2>
  </header>
  <p data-role="description">This product will make your life 100 times better.</p>
</section>
```

```ruby
Then "I should see the site description" do
  page.should have_selector("[data-role='primary-content'] [data-role='description']",
                            text: "This product will make your life 100 times better.")
end
```

Now, the step is asserting that there's an element with a role of description
within an element with a role of primary-content that contains the correct text.

XHTML introduced a role attribute, but it's not present currently in HTML5.
Luckily, data attributes are even more flexible and we can use any conventions
we like. `data-role` and `data-state` are two of my favorites.

Interested in how to write awesome Cucumber steps? Head to my [Test-Driven Rails
workshop](https://thoughtbot.com/upcase/test-driven-rails) on March 26th and March 27th
where we'll cover this and other awesome topics on writing great tests!
