Reputation: 238667
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?
Upvotes: 17
Views: 11142
Reputation: 107
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.
Upvotes: 2
Reputation: 3306
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.
Upvotes: 6
Reputation: 11929
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
Upvotes: 8
Reputation: 9752
Give Approvals a try, it works with rspec, I have used for testing Json payload, and it is used with Minitest in exercism.io
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
Upvotes: 1