Skip to content

Instantly share code, notes, and snippets.

@kluzny
Last active July 31, 2024 17:35
Show Gist options
  • Save kluzny/65cf70e65352ab1c18f212c7d3e626d1 to your computer and use it in GitHub Desktop.
Save kluzny/65cf70e65352ab1c18f212c7d3e626d1 to your computer and use it in GitHub Desktop.
Some custom rspec matchers for inspecting json responses
require 'rspec/expectations'
# expect(response).to be_json_success
RSpec::Matchers.define :be_json_success do |_expected|
match do |actual|
actual.status == 200 && actual.content_type.match("application/json")
end
failure_message do |actual|
"expected status: 200, content_type: 'application/json', got status: #{actual.status}, content_type: '#{actual.content_type}'"
end
end
# expect(response).to have_json_status(:created)
RSpec::Matchers.define :have_json_status do |expected|
def numeric_status(status)
case status
when Symbol
Rack::Utils::SYMBOL_TO_STATUS_CODE[status]
else
status
end
end
match do |actual|
actual.status == numeric_status(expected) && actual.content_type.match("application/json")
end
failure_message do |actual|
"expected status: #{numeric_status(expected)}, content_type: 'application/json', got status: #{actual.status}, content_type: '#{actual.content_type}'"
end
end
# expect(response).to have_json_keys(%w[id created_at updated_at])
RSpec::Matchers.define :have_json_keys do |expected|
def parse(response)
JSON.parse(response.body)
end
def formatter(array)
"[ #{array.sort.join(', ')} ]"
end
# if key order is important I recommend an explicit test
match do |actual|
parse(actual).keys.sort == expected.sort
end
failure_message do |actual|
actual_keys = parse(actual).keys
difference = actual_keys.union(expected) - actual_keys.intersection(expected)
<<~MESSAGE
expected the following JSON keys:
#{formatter(expected)}
got:
#{formatter(actual_keys)}"
symmetric difference:
#{formatter(difference)}
MESSAGE
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment