post command not rendering data in Rspec - ruby-on-rails

I have defined a controller Add. In controller i have defined a function (add_params)
def add_values
ans = params[:first_element] + params[:second_element]
render :json => {:result => ans}.to_json
end
in routes file i have declared post :add_params
if i call curl -X POST -H "Content-Type:application/json" -d '{"first_element" : 3, "second_element" :2}' http://localhost:8000/add/add_values it return {"result":5}
but when i tried to test in Rspec as
describe AddController, :type => :request do
it "must return 5" do
post "http://localhost:8000/add/add_values", {"first_element" : 3, "second_element" :2}.to_json
expect(JSON.parse(response.body)["result"]).to eq "5"
end
end
it gives error as
Failure/Error: expect(response["result_is"]).to eq 5
expected: 5
got: nil
(compared using ==)
# ./spec/controller/add_controller_spec.rb:67:in `block (2 levels) in <top (required)>'
i am using rails 3.2.16 , ruby 2.1.5 , rspec 3.0.0

Is pretty weird that you receive
Failure/Error: expect(response["result_is"]).to eq 5
if your expectation is
expect(JSON.parse(response.body)["result"]).to eq "5"
the parameters of expect function are different one each other.
You should receive an error like this
Failure/Error: expect(JSON.parse(response.body)["result_is"]).to eq "5"
Are you sure your expectation is not
expect(response["result_is"]).to eq 5
?

Related

Date.today.to_s(:long) not converting to string

I am working on an assignment and I have written the following method based on our instructions:
def create_todolist(params)
due_date = Date.today.to_s(:long)
TodoList.create(list_name: params[:name],list_due_date: params[:due_date])
end
But when I run the rspec test, I get the following error:
1) Assignment rq03 rq03.2 assignment code has create_todolist method should create_todolist with provided parameters
Failure/Error: expect(testList.list_due_date).to eq due_date
expected: Thu, 07 May 2020
got: "2020-05-07"
(compared using ==)
Diff:
## -1,2 +1,2 ##
-Thu, 07 May 2020
+"2020-05-07"
# ./spec/assignment_spec.rb:177:in `block (4 levels) in <top (required)>'
# ./spec/assignment_spec.rb:14:in `block (2 levels) in <top (required)>'
Here is the rspec test:
context "rq03.2 assignment code has create_todolist method" do
it { is_expected.to respond_to(:create_todolist) }
it "should create_todolist with provided parameters" do
expect(TodoList.find_by list_name: "mylist").to be_nil
due_date=Date.today
assignment.create_todolist(:name=> 'mylist', :due_date=>due_date)
testList = TodoList.find_by list_name: 'mylist'
expect(testList.id).not_to be_nil
expect(testList.list_name).to eq "mylist"
expect(testList.list_due_date).to eq due_date
expect(testList.created_at).not_to be_nil
expect(testList.updated_at).not_to be_nil
end
end
At first I had just due_date = Date.today and was getting the same error and I'm not sure how to fix it. I'm wondering if it is because I am using a different version of ruby/rails than what was used when the course was created ( 5 years ago -_-).
Any help would be greatly appreciated!
Thank you :)
You are trying to compare a Date object:
due_date = Date.today
With a string object you generated while you created your record:
Date.today.to_s(:long)
As you can see, these are different types of objects:
Date.today.to_s(:long)
=> "May 07, 2020"
Date.today.to_s(:long).class
=> String
Date.today
=> 2020-05-07
Date.today.class
=> Date
Date.today.to_s(:long) == Date.today
=> false
I figured it out. When I was creating the TodoLists table, I didn't specify the migration type as :date. so by default, due_date was set to be a string. So I set to type :date and changed due_date to equal:
due_date = Date.today
Thank you for taking the time to help me out :)

RSpec API controllers testing

At first, sorry for my English :)
I need to realize API controller's tests in Ruby on Rails application (v 4.2.0).
When I do request to GET Advertising Sources I have a json response like this:
{"advertising_sources":[{"id":59,"title":"accusantium"},{"id":60,"title":"assumenda"}]}
JSON response template was defined by front-end developer.
Now I trying to create tests for:
1. JSON size (2 advert sources)
2. included attributes (id, title)
My tests:
it 'returns list of advertising sources' do
expect(response.body).to have_json_size(2)
end
%w(id title).each do |attr|
it "returns json with #{attr} included" do
hash_body = JSON.parse(response.body)
expect(hash_body).to include(attr)
end
end
Failures:
1. Failure/Error: expect(response.body).to have_json_size(2)
expected {"advertising_sources":[{"id":59,"title":"accusantium"},{"id":60,"title":"assumenda"}]} to respond to `has_json_size?`
2. Failure/Error: expect(hash_body).to include(attr)
expected {"advertising_sources" => [{"id" => 71, "title" => "necessitatibus"}, {"id" => 72, "title" => "impedit"}]} to include "id"
Diff:
## -1,2 +1,2 ##
-["id"]
+"advertising_sources" => [{"id"=>71, "title"=>"necessitatibus"}, {"id"=>72, "title"=>"impedit"}],
Can anyone help me to correctify my tests code?
Thanks!
Given the shape of your response and the characteristics you are interested in testing, you can write your tests as follows:
describe 'advertising_sources' do
let(:parsed_response_body) { JSON.parse(response.body) }
let(:advertising_sources) { parsed_response_body['advertising_sources'] }
it 'returns list of advertising sources' do
expect(advertising_sources.size).to eq(2)
end
%w(id title).each do |attr|
it "returns json with #{attr} included" do
advertising_sources.each { |source| expect(source.keys).to include(attr) }
end
end
end
I would personally simplify this even further to:
describe 'advertising_sources' do
let(:parsed_response_body) { JSON.parse(response.body) }
let(:advertising_sources) { parsed_response_body['advertising_sources'] }
it 'returns list of advertising sources' do
expect(advertising_sources.size).to eq(2)
end
it 'includes an id and title for each source' do
advertising_sources.each { |source| expect(source.keys).to match_array(%w(id title)) }
end
end

RSpec routing spec: sequence of fields in hash

I'm having a problem with the actual vs expected failing due to sequence on the hash. I don't recall seeing this before ... and in any case I thought a hash was unordered?
How can I have this test pass?
RSpec.describe ArticleSectionsController, type: :routing do
describe "routing" do
it "routes to #index" do
expect(:get => "/articles/5/article_sections").to route_to("article_sections#index", article_id: 5)
end
end
end
1) ArticleSectionsController routing routes to #index
Failure/Error: expect(:get => "/articles/5/article_sections").to route_to("article_sections#index", article_id: 5)
The recognized options <{"controller"=>"article_sections", "action"=>"index", "article_id"=>"5"}> did not match <{"article_id"=>5, "controller"=>"article_sections", "action"=>"index"}>, difference:.
--- expected
+++ actual
## -1 +1 ##
-{"article_id"=>5, "controller"=>"article_sections", "action"=>"index"}
+{"controller"=>"article_sections", "action"=>"index", "article_id"=>"5"}
The problem is not the order of the hash, the problem is the content.
"article_id"=>"5"
is not the same as
"article_id"=> 5
Us the string version in your route_to parameters and that'll fix the issue.

Expect that a JSON has just a particular set of keys in rspec?

I am testing a JSON API, and right now I do this:
expect(json).to have_key('name')
expect(json).to have_key('age')
How can I make sure that the JSON has just the keys name and age, and no other keys?
Use the #contain_exactly matcher:
expect(json.keys).to contain_exactly('name', 'age')
Examples
Number #1
Spec:
describe "Hash" do
subject { {a: 2, b: 3} }
it "passes" do
expect(subject.keys).to contain_exactly(:a, :b)
end
end
Let's run it :
arup#linux-wzza:~/Ruby> rspec spec/test_spec.rb
.
Finished in 0.00227 seconds (files took 0.13131 seconds to load)
1 example, 0 failures
Number #2
Spec:
describe "Hash" do
subject { {a: 2, b: 3} }
it "fails" do
expect(subject.keys).to contain_exactly(:a)
end
end
Let's run it:
arup#linux-wzza:~/Ruby> rspec spec/test_spec.rb
F
Failures:
1) Hash fails
Failure/Error: expect(subject.keys).to contain_exactly(:a)
expected collection contained: [:a]
actual collection contained: [:a, :b]
the extra elements were: [:b]
# ./spec/test_spec.rb:7:in `block (2 levels) in <top (required)>'
Finished in 0.00243 seconds (files took 0.13206 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/test_spec.rb:6 # Hash fails
Number #3
Spec:
describe "Hash" do
subject { {a: 2, b: 3, c: 4} }
it "fails" do
expect(subject.keys).to contain_exactly(:a, :b)
end
end
Let's run it:
arup#linux-wzza:~/Ruby> rspec spec/test_spec.rb
F
Failures:
1) Hash fails
Failure/Error: expect(subject.keys).to contain_exactly(:a, :b)
expected collection contained: [:a, :b]
actual collection contained: [:a, :b, :c]
the extra elements were: [:c]
# ./spec/test_spec.rb:7:in `block (2 levels) in <top (required)>'
Finished in 0.00243 seconds (files took 0.13301 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/test_spec.rb:6 # Hash fails
arup#linux-wzza:~/Ruby>
Number #4
When dealing with JSON keys, the splat operator (*) comes in handy to manage a list of arguments.
Spec:
describe "Hash" do
subject { {a: 2, b: 3} }
let(:json_keys) { %w{a b} }
it "passes" do
expect(subject.keys).to contain_exactly(*json_keys)
end
end
Let's run it :
arup#linux-wzza:~/Ruby> rspec spec/test_spec.rb
.
Finished in 0.00227 seconds (files took 0.13131 seconds to load)
1 example, 0 failures
Have you tried this:
expect(json.keys.sort).to eq(["age","name"])
Or
expect(json.keys).to match_array(["name","age"])
I am assuming the json object is pre-parsed such as let(:json){JSON.parse(something)}. If so this is now a Hash and #keys will return an Array of the keys so compare that to the expected Array.
If not pre-parsed then
expect(JSON.parse(json).keys).to match_array(["name","age"])

Tests are not passing

I'm using RSpec for tests and I don't know how to get this to green.
In this case, I have a model called "PartType" that holds an attribute called "quotation".
The value for quotation comes from a form, so it will be a string.
To demonstrate you can go to console and type:
(1..1000).includes?("50") # false
but..
(1..1000).includes?(50) # true
And this value can have decimals. So I needed to do a "type_cast".
I have this on my PartTypemodel:
before_validation :fix_quotation, :if => :quotation_changed?
protected
def fix_quotation
self[:quotation] = quotation_before_type_cast.tr(' $, ' , '.' )
end
This are working as expected BUT when go to tests, it fails.
Here is my part_type_spec.rb:
require 'spec_helper'
describe PartType do
before(:each) do
#attr = { :title => "Silver", :quotation => 100 }
end
it "should create a instance given a valid attributes" do
PartType.create!(#attr)
end
it "should accept null value for quotation" do
PartType.new(#attr.merge(:quotation => nil)).should be_valid
end
it "should accept 0 value for quotation" do
PartType.new(#attr.merge(:quotation => 0)).should be_valid
end
end
And finally the failing tests:
Failures:
1) PartType should create a instance given a valid attributes
Failure/Error: PartType.create!(#attr)
NoMethodError:
undefined method tr' for 100:Fixnum
# ./app/models/part_type.rb:7:infix_quotation'
# ./spec/models/part_type_spec.rb:10:in `block (2 levels) in '
2) PartType should accept 0 value for quotation
Failure/Error: PartType.new(#attr.merge(:quotation => 0)).should be_valid
NoMethodError:
undefined method tr' for 0:Fixnum
# ./app/models/part_type.rb:7:infix_quotation'
# ./spec/models/part_type_spec.rb:18:in `block (2 levels) in '
Finished in 0.06089 seconds
3 examples, 2 failures
Your include? snippets are wrong, I got false in the first, true in the second.
before_validation is executed and quotation_before_type_cast is expected to be a String but it is a Fixnum. Change 100 to '100' and 0 to '0'.

Resources