One of my current Rails projects involves generating an RSS feed. While I was working on this the other night, it seemed to be working, so I deployed it to the staging server. Everything looked fine. If I fetched it with Firefox, the browser offered to let me subscribe to the feed with Google Reader, and if I used Safari I'd see a nice view of the feed just like I expected.
So I sent a note via our campfire to check it out, and a colleague replied that his Safari was saying that it was in an invalid format.
So I went to the W3 RSS Feed Validation Service and worked through the validation issues, after which his browser was as happy as mine.
Of course, having been through that, I wanted to make sure that RSS validation was covered in the specs for the project.
I went looking for an existing RSpec matcher, and found a matcher to validate XHTML but nothing for RSS.
I then found the feedvalidator gem which provides a Ruby interface to the SOAP interface to the W3 feed validator. You would think that W3 would be providing a REST interface! The gem already provides assertions for use with Test::Unit, so I just built an RSpec matcher.
class BeValidFeed require 'feed_validator' require 'tmpdir' require 'md5' def matches?(response) return true if validity_checks_disabled? v = W3C::FeedValidator.new() fragment = response.body filename = File.join Dir::tmpdir, 'feed.' + MD5.md5(fragment).to_s begin response = File.open filename do |f| Marshal.load(f) end v.parse(response) rescue unless v.validate_data(fragment) @failure = " could not access w3 validator to validate the feed." return false end File.open filename, 'w+' do |f| Marshal.dump v.response, f end end v.valid? end def description "be valid xhtml" end def failure_message @failure || " expected xhtml to be valid, but validation produced these errors:\n #{@message}" end def negative_failure_message " expected to not be valid, but was (missing validation?)" end private def validity_checks_disabled? ENV["NONET"] == 'true' end end def be_valid_feed BeValidFeed.new end
I saved this as spec/be_valid_feed.rb
And in a view or controller spec, I can include this file, and test a response with:
response.should be_valid_feed
If you use this in a controller spec, you will need to tell RSpec to integrate_views, or you won't have much of a feed to check. If you use nested example groups, integrate_views needs to be inside the inner group.
Trackbacks
Use the following link to trackback from your own site:
http://talklikeaduck.denhaven2.com/trackbacks?article_id=486





Next time, generate Atom 1.0 instead. The validator messages are way more helpful and you get to dodge a bunch of corner cases with enclosures and summaries and categories and so on.
Thanks Rick! This will be handy next time I do a feed.
Tim -
Yes generally I prefer Atom, however for this gig the rss feed is for consumption by iTunes, and as far as I know that requires RSS.
Great ! If I got time I’ll add the matcher to feedvalidator