I have an RSS feed that I am writing an RSpec test for. I want to test that the XML document has the correct nodes and structure. Unfortunately, I can't find any good examples of how to do this in a clean way. I have only found some half-implemented solutions and outdated blog posts. How can I test the structure of an XML document using RSpec?
4 Answers
Hi I can recommend you to use custom matcher for this.
require 'nokogiri'
RSpec::Matchers.define :have_xml do |xpath, text|
match do |body|
doc = Nokogiri::XML::Document.parse(body)
nodes = doc.xpath(xpath)
nodes.empty?.should be_false
if text
nodes.each do |node|
node.content.should == text
end
end
true
end
failure_message_for_should do |body|
"expected to find xml tag #{xpath} in:\n#{body}"
end
failure_message_for_should_not do |response|
"expected not to find xml tag #{xpath} in:\n#{body}"
end
description do
"have xml tag #{xpath}"
end
end
Full example can be found here https://gist.github.com/Fivell/8025849

- 11,829
- 3
- 61
- 99
No longer necessary to roll your own. We deal this problem daily, using the equivalent-xml matcher at https://github.com/mbklein/equivalent-xml .
require 'rspec/matchers'
require 'equivalent-xml'
...
expect(node_1).to be_equivalent_to(node_2)
Has options for edge cases like whitespace-preservation.
Your other option is to use a formal XSD template for strict validation.

- 3,079
- 1
- 18
- 16
context 'POST #join' do
it 'does successfully hit join xml route' do
post :join,
format: :xml
response.content_type.should == "application/xml"
response.should be_ok
end
end
This worked for me. I didn't realize I had to pass format: :xml. My join route responds to /join.xml and I was testing that this was successful.

- 107
- 6
-
3This doesn't really solve the OP's question, but it was helpful for me to just assert you are getting xml without adding gems – tam5 May 31 '16 at 15:29
Give Approvals a try, it works with rspec, I have used for testing Json payload, and it is used with Minitest in exercism.io
EDIT
it "returns available traffic information around me" do
post '/search_traffic_around', {location: [-87.688219, 41.941149]}.to_json
output = last_response.body
options = {format: :json, name: 'traffic_around_location'}
Approvals.verify(output,options)
end
the JSON I am verifying against is located in spec/fixtures
folder named traffic_around_location.approved.json
Implementation where the above snippet is pulled from is available here
How it works is you supply it an expected Payload, JSON, XML, TXT and HTML this I am sure it supports in spec/fixtures
and when you run the test it checks to confirm that the payload received matches the expected(approved) payload the test would pass if it matches else the test fails

- 9,592
- 2
- 37
- 47
-
Can you provide an example of how this is meant to be used? I have read through the Approvals readme and it's not very clear. – Andrew Dec 16 '13 at 21:49
-
I'll give you an up-vote for updating your answer but I'd still like to see some alternatives (or at least some more up-votes indicating this is a popular solution). – Andrew Dec 16 '13 at 23:53