Search code examples
rspecruby-on-rails-5

What is the best way to match JSON arguments and multiple arguments usign RSpec


I am writing a spec for a Ruby class that converts a given ActiveRecord into JSON and passes the JSON to another class.

include KinesisHelper

class OrderProcesser

  class << self
    def post_order(order)
      json = extract_order_params(order)
      KinesisHelper.send_record_to_kinesis(json, order.stream)
    end

    private
    def extract_order_params(order)
      params = {}
      params[:id] = order.id
      params[:max_budget] = order.budget
      params[:startDate] = order.start_date.to_i * 1000
      params[:endDate] = order.end_date.to_i * 1000
      params.to_json
    end

In the RSpec I want to verify if the subject class creates the JSON in the right format and calls its component class with the right arguments. Here is my attempt.

require 'spec_helper'

describe OrderProcesser do
  describe "#perform" do
    before do
      @order = FactoryBot.create(:order)
    end
    it "should invoke OrderProcesser" do
      # working
      #KinesisHelper.should_receive(:send_record_to_kinesis).once.with(anything, @order.stream)
      #partially working - only first condition is verified
      expect(KinesisHelper).to receive(:send_record_to_kinesis) {
        |arg1, arg2|
        expect(arg2).to eq @order.stream
        expect(arg1[:id]).to eq @order.id
      }

      #when
      OrderProcesser.post_order(@order)
    end
  end
end

The generic verification is passing:

KinesisHelper.should_receive(:send_record_to_kinesis).once.with(anything, @order.stream)

However when I try to verify multiple conditions on the arguments, like the JSON contents and second argument's value, it just checks the first condition. The second condition is ignored.

expect(KinesisHelper).to receive(:send_record_to_kinesis) {
            |arg1, arg2|
            expect(arg2).to eq @order.stream
            expect(arg1[:id]).to eq @order.id #ignored
          }

Can you please me know how I can run multiple matchers on the arguments?


Solution

  • The issue is not related to the multiple matches. The error in my code was that I did not parse the JSON string argument to JSON. I also used the symbol values while accessing the JSON attributes. These symbols will eb converted to literal strings after the JSON conversion.

    This code snippet works:

    expect(KinesisHelper).to receive(:send_record_to_kinesis) {
                |arg1, arg2|
                expect(arg2).to eq @order.stream
                json = JSON.parse(arg1)
                expect(json['id']).to eq @order.id 
              }