Mark Datoni
Mark Datoni

Reputation: 524

How to test with Rspec that a key exists inside a hash that contains an array of hashes

I have a Model method that returns the following when executed.

 {"data" => [
 {"product" => "PRODUCTA", "orders" => 3, "ordered" => 6, "revenue" => 600.0},
 {"product" => "PRODUCTB", "orders" => 1, "ordered" => 5, "revenue" => 100.0}]}

I would like to test to make sure that "revenue" in the first hash is there and then test that the value is equal to 600.

subject { described_class.order_items_by_revenue }

it "includes revenue key" do
  expect(subject).to include(:revenue)
end

I am completely lost on how to test this with Rspec.

Upvotes: 48

Views: 62794

Answers (4)

Chris Heald
Chris Heald

Reputation: 62698

RSpec allows you to use the have_key predicate matcher to validate the presence of a key via has_key?, like so:

subject { described_class.order_items_by_revenue }

it "includes revenue key" do
  expect(subject.first).to have_key(:revenue)
end

Upvotes: 62

Sohair Ahmad
Sohair Ahmad

Reputation: 457

this works for me in 'rspec-rails', '~> 3.6'

array_of_hashes = [
  {
    id: "1356786826",
    contact_name: 'John Doe'
  }
]

expect(array_of_hashes).to include(have_key(:id))

Upvotes: 2

Purkhalo Alex
Purkhalo Alex

Reputation: 3627

This issue can be solved via testing of each hash by key existing with appropriate type of value. For example:

describe 'GetCatsService' do
  subject { [{ name: 'Felix', age: 25 }, { name: 'Garfield', age: 40 }] }

  it { is_expected.to include(include(name: a_kind_of(String), age: a_kind_of(Integer)))}
end

# GetCatsService
#  should include (include {:name => (a kind of String), :age => (a kind of Integer)})

Upvotes: 9

wspurgin
wspurgin

Reputation: 2733

If you explicitly want to test only the first hash in your array mapped to :data, here are your expects given what you wrote above:

data = subject[:data].first
expect(data).not_to be_nil
expect(data.has_key?(:revenue)).to be_truthy
expect(data[:revenue]).to eq 600

Alternatively, for the second expectation, you could use expect(data).to have_key(:revenue) as Chris Heald pointed out in his answer which has a much nicer failure message as seen in the comments.

  1. The first "expectation" test if the subject has the first hash. (You could alternately test if the array is empty?)
  2. The next expectation is testing if the first hash has the key :revenue
  3. The last expectation tests if the first hash :revenue value is equal to 600

You should read up on RSpec, it's a very powerful and usefull testing framework.

Upvotes: 7

Related Questions