Skip to content

nomtek/rspec-json_api

Repository files navigation

RSpec::JsonApi

RSpec:JsonAPI is an extension for RSpec to easily allow testing JSON API responses.

Installation

Add this line to your application's Gemfile:

gem 'rspec-json_api'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install rspec-json_api

Generate directory tree:

rails generate rspec:json_api:install

Require gem assets in your rails_helper.rb

Dir[File.join(__dir__, 'rspec', 'json_api', 'types', '*.rb')].each { |file| require file }
Dir[File.join(__dir__, 'rspec', 'json_api', 'interfaces', '*.rb')].each { |file| require file }

Generators

Using build-in generators it's possible to create custom interface and type.

Generate new template:

rails generate rspec:json_api:interface interface-name

Generate new type:

rails generate rspec:json_api:type type-name

Example usage

# spec/controllers/users_controller_spec.rb

RSpec.describe UsersController, type: :controller do
  describe '#index' do
    let(:expected_schema) do
      Array[{
        id: RSpec::JsonApi::Types::UUID,
        name: String,
        age: Integer,
        favouriteColorHex: /^\#([a-fA-F]|[0-9]){3,6}$/,
        number: -> { { type: Integer, min: 10, max: 20, lambda: ->(actual) { actual.even? } } }
      }]
    end

    it 'matches API response' do
      get :index

      expect(response.body).to match_json_schema(expected_schema)
    end
  end
  
  describe '#update' do
    it 'matches API response' do
      put :update, params: { name: 'John', age: 35 }
      
      expect(response.body).to have_no_content
    end
  end
end

Built-in matchers

  • match_json_schema

  expect(response.body).to match_json_schema(expected_schema)
  • have_no_content

  expect(response.body).to have_no_content

Interfaces

The gem introduces interfaces to reuse them during test matches.

# spec/rspec/json_api/interfaces/example_interface.rb

module RSpec
  module JsonApi
    module Interfaces
      EXAMPLE_INTERFACE = {
        id: Types::UUID,
        name: String,
        number: Integer,
        color: -> { { inclusion: %w[black red white], allow_blank: true } }
      }.freeze
    end
  end
end

Note: You can either generate file on your own or use generator.

Types

The gem allow users either to user build-in types or define owns.

Build-in types

  • EMAIL

RSpec::JsonApi::Types::EMAIL
  • URI

RSpec::JsonApi::Types::URI
  • UUID

RSpec::JsonApi::Types::UUID

Custom type example:

# spec/rspec/json_api/types/color_hex.rb

module RSpec
  module JsonApi
    module Types
      COLOR_HEX = /^#(?:[0-9a-fA-F]{3}){1,2}$/
    end
  end
end

RSpec::JsonApi::Types::COLOR_HEX

Note: You can either generate file on your own or use generator.

Matching methods

The gem offers variety of possible matching methods.

Presumptions

  • match_json_schema always require full keys match.

    Failure Example:

    let(:expected) do
      {
        id: RSpec::JsonApi::Types::UUID,
        name: String,
        age: Integer
      }
    end
    
    let(:actual) do
      {
        id: "0a2f911f-3767-4cc7-9c19-049f4350e38c",
        name: "Mikel",
      }
    end

    Success Example:

    let(:expected) do
      {
        id: RSpec::JsonApi::Types::UUID,
        name: String,
        age: Integer
      }
    end
    
    let(:actual) do
      {
        id: "0a2f911f-3767-4cc7-9c19-049f4350e38c",
        name: "John",
        age: 24
      }
    end

Value match

let(:expected_schema) do
  {
    id: "e0067346-4d24-4aa6-b303-f927a410a001",
    name: "John",
    age: 24,
    favouriteColorHex: "#FF5733"
  }
end

Class match

let(:expected_schema) do
  {
    id: Integer,
    name: String,
    age: Integer,
    notes: Array[String]
  }
end

Type match

let(:expected_schema) do
  {
    id: RSpec::JsonApi::Types::UUID,
    email: RSpec::JsonApi::Types::EMAIL,
  }
end

Regexp match

let(:expected_schema) do
  {
    color: /^\#([a-fA-F]|[0-9]){3,6}$/
  }
end

Interface match

let(:expected_schema) do
    Array[RSpec::JsonApi::Interfaces::PERSON]
end

Proc match

Proc match allows to customize schema accoring needs using lambda shorthand notation ->

Supported options:

  • type

let(:expected_schema) do
  {
    name: -> { { type: String } }
  }
end
  • value

let(:expected_schema) do
  {
    name: -> { { value: "John" } }
  }
end
  • min

let(:expected_schema) do
  {
    age: -> { { min: 15 } }
  }
end
  • max

let(:expected_schema) do
  {
    age: -> { { max: 25 } }
  }
end
  • inclusion

let(:expected_schema) do
  {
    letter: -> { { inclusion: %w[A B C] } }
  }
end
  • regex

let(:expected_schema) do
  {
    hex: -> { { regex: /^\#([a-fA-F]|[0-9]){3,6}$/ } }
  }
end
  • lambda

let(:expected) do
  {
    number: -> { { lambda: ->(actual) { actual.even? } } }
  }
end
  • allow_blank

let(:expected_schema) do
  {
    name: -> { { type: String, allow_blank: true } }
  }
end

Note: Default value is false

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/nomtek/rspec-json_api. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the RSpec::JsonApi project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

About

No description, website, or topics provided.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages