# Soaspec This gem helps to represent multiple API tests against a backend briefly, concisely and clearly. It is essentially a wrapper around the Savon and RestClient gems, adding useful functionality including * Creating multiple API calls from the same base configuration through the use of an `ExchangeHandler` * Extracting values from response body's through either `XPath` or `JSONPath` * Building up a custom RSpec `success scenario` shared example to repeatedly writing the same tests * Methods making setting and extracting values from a `Request/Response` pair (`Exchange`) easy * Waiting for a particular response from an API by polling it * Way of abstracting paths to values from a response with business-meaningful method names * Generating initial code for an API with `soaspec new` * Way of accessing and using an `oauth2` access token * Hosting a `virtual_server` that simulates REST & SOAP responses from an API [![Build Status](https://gitlab.com/samuel-garratt/soaspec/badges/master/build.svg)](https://gitlab.com/samuel-garratt/soaspec/pipelines) [![Coverage](https://gitlab.com/samuel-garratt/soaspec/badges/master/coverage.svg)](https://samuel-garratt.gitlab.io/soaspec) ## Installation Add this line to your application's Gemfile: ```ruby gem 'soaspec' ``` And then execute: $ bundle Or install it yourself as: $ gem install soaspec [Things to be done](Todo.md) ## Getting Started To create a new test suite using this you can use the `soaspec` binary. Example: ``` mkdir 'api_test' cd 'api_test' soaspec new [rest/soap] bundle install ``` Then you can run the tests with: ``` rake spec ``` You can also use `soaspec generate` to generate a set of tests from a WSDL. This is still in trial period and will be finished probably after Savon 3 is more stable. ## Usage * SOAP - this uses Savon behind the scenes. Some defaults are overridden. Please see 'soap_handler.rb'-'default_options' method for such defaults. When describing an API override this in 'savon_options' method * REST - this uses the resource class from the Rest-Client gem behind the scenes. See [specs](specs) and [features](features) for example of usage. ### ExchangeHandler To start with a class inheriting from a ‘Handler’ class for each web service that’s tested needs to be created. In this class you define the common parameters used for testing this class. For example: ```ruby # Classes are set up through inheriting from either `Soaspec::RestHandler` or `Soaspec::SoapHandler` class PuppyService < Soaspec::RestHandler headers accept: 'application/json', content_type: 'application/json' # Set default headers for all `Exchanges` using this class base_url 'http://petstore.swagger.io/v2/pet' # URL for which all requests using this class will start with element :id, :id # Define a method 'id' that can be obtained with either XPATH '//id' or JSONPath '$..id' element :category_id, '$..category.id' # Define method to obtain a category id through JSON Path end ``` ### Exchange Then you reference this class in creating `Exchange`’s (representing a request / response pair). Upon initialization of the Exchange object or later on through setters, parameters specific to this request are set All getters of the Exchange are on the response & will implicitly trigger the API request to be made. Once this request has been made, all following accessors of the response will just use the previous request made. ```ruby exchange = PuppyService.post(body: { status: 'sold' }) # The 'body' key will convert it's value from a Hash to JSON # Create a new Exchange that will post to 'http://petstore.swagger.io/v2/pet' with JSON { "status": "sold" } exchange.category_id # This will trigger the request to be made & return a value at JSON path $..category.id, throwing an exception if not found ``` See [Request Body Parameters](wikis/RequestBodyParameters) for more details on setting a request body. See [Creating an Exchange](wikis/CreatingExchange) for details on how to create an Exchange. ### RSpec For example: ```ruby context PuppyService.new('Order Puppies') do describe post(:create_pet, body: { status: 'sold' }) do # Post with status as sold in request its(['status']) { is_expected.to eq 'sold' } # Check responses status is sold end end ``` #### Tips If you find having a large backtrace on errors or RSpec shared examples such as 'success scenarios' this can shorten the backtrace. RSpec.configure do |config| config.backtrace_exclusion_patterns = [ /rspec/ ] end ### Cucumber If you're using `Cucumber` then I would recommend the following In the `Given` (or background) specify the `Exchange` object. Either store this as an instance variable (e.g `@exchange`) or use the global `Soaspec.last_exchange` In the `When` use the `call` method to make the request `@exchange.call` In the `Then` make the assertions from the `@exchange` object. E.g ```ruby expect(@exchange['message']).to include 'success' expect(@exchange.status_code).to eq true ``` ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). ## Contributing Bug reports and pull requests are welcome on GitLab at https://gitlab.com/samuel-garratt/soaspec. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). ## Code of Conduct Everyone interacting in the Soaspec project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://gitlab.com/samuel-garratt/soaspec/blob/master/CODE_OF_CONDUCT.md).