Acceptance Testing: Asserting Sort Order
At LaunchWare, we’ve been looking for the best way to locate an element on a page in an Rspec request spec. Sometimes there’s just no getting around asserting that one piece of content appears before another, like when testing sort options. We’ve tried a few things:
Imagine there are two comments on a post. We want to assert that the most recent comment appears first.
We have the following markup:
1 2 3 4 5 6 7 8
The most obvious way
The most obvious way to assert that the newer commment appears first is:
1 2 3 4 5 6 7 8 9 10
Or some variant of this.
page.find("div.comment:nth-child(1)") works too.
But this approach is brittle. What if we go all HTML5 on this template and change the comment divs to article tags like so:
1 2 3 4 5 6 7 8
Then our test is broken.
Or worse, if we add another comment into the mix as part of another test:
1 2 3
Our markup becomes:
1 2 3 4 5 6 7 8 9 10 11
Not nth-child 1 and 2 anymore…
But hey, we don’t really care which children they are, or what tags they are. We just want to know if the text of the new comment is on the page and placed somewhere before the old comment! Let’s test that. So, here you have it:
The less brittle (and therefore better) way
We know thse things:
- With capybara, you can grab the contents of the whole page as a string by calling
- And with a Ruby string, you can grab the position (index) of a certain substring by calling
- And with Rspec you can assert that one index/position is less than/before another using
index1.should_be < index2.
So put that all together, and we replace the brittle approach above with this:
1 2 3 4
But there’s one more thing:
The one more thing (best) way
It would be annoying to type that over and over. What if you or the guys at LaunchWare figure out a better way to do this in the future? You wouldn’t want to have to find-and-replace your whole code base. And we wouldn’t either.
Try this Rspec custom matcher definition on for show:
1 2 3 4 5
Once this is in play, you can now make this magical assertion:
1 2 3 4
Definitely try this at home:
How to add this to your project
I’ve released this as a gem! so all you have to do is add
to your gemfile. Then you can assert
And you’re in business. #win
Follow me on Twitter at jmondo for <= 140 char gems