2

I have a Ruby (2.6.5) on Rails (5.2.3) application which is already successfully using Savon (2.12) to interact with FlightAware's FlightXML 2 API via SOAP/WSDL. However, I'm running into an issue while attempting to write Minitest tests for this functionality, using WebMock (3.7.6) to stub out the API requests.

My application (via Savon) makes a request including an XML body like the following example:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:FlightXML2="http://flightxml.flightaware.com/soap/FlightXML2" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
  <env:Body>
    <FlightXML2:AirportInfoRequest>
      <FlightXML2:airportCode>KDFW</FlightXML2:airportCode>
    </FlightXML2:AirportInfoRequest>
  </env:Body>
</env:Envelope>

I would like to use a with statement so that the stub only responds to a request having a specific airport code in the element. For example, if I'm looking for "KDFW", then a request containing <FlightXML2:airportCode>KDFW</FlightXML2:airportCode> should match, but a request containing <FlightXML2:airportCode>CYYZ</FlightXML2:airportCode> should not.

Right now, I have it working by including the XML tag in a regular expression:

icao_code = "KDFW"
response_body = "[the response I want]"

WebMock.stub_request(:post, "http://flightxml.flightaware.com/soap/FlightXML2/op").
  with(body: /<FlightXML2:airportCode>#{icao_code}<\/FlightXML2:airportCode>/).
  to_return(status: 200, body: response_body)

This feels like a kludge, especially when the documentation for WebMock mentions that I can use hash_including to match XML tags. No matter what I try, though, I get the typical WebMock unregistered request error, indicating that I don't match the request. Here are the with statements that I've tried so far:

with(body: hash_including({airport_code: icao_code})
with(body: hash_including({"airportCode": icao_code})
with(body: hash_including({"FlightXML2:airportCode": icao_code})

How can I match a specific XML element without having to resort to putting the XML tag in a regular expression?

bogardpd
  • 287
  • 1
  • 10

1 Answers1

1

Match the request against a block:

stub_request(:post, "http://flightxml.flightaware.com/soap/FlightXML2/op")
  .with do |request|
    # do something
  end.to_return(status: 200, body: response_body)

The block code could look something like:

request_xml = Nokogiri::XML(request.body)
request_xml.xpath("//FlightXML2:airportCode").any? do |node|
  node.content == icao_code
end

This approach has an additional advantage in that you can insert a debugger into the above code block and figure out why your test case isn't working. You can see Webmock docs here.

niborg
  • 390
  • 4
  • 16