Andrew
Andrew

Reputation: 238667

How to test XML file using RSpec?

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

Answers (4)

Angie
Angie

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

Joe Atzberger
Joe Atzberger

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

Fivell
Fivell

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

bjhaid
bjhaid

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

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

Upvotes: 1

Related Questions