CSV file appearing backwards and RSpec failing - ruby-on-rails

I am new to Ruby in general and cannot find a solution as to why my entries_2.csv is imported backwards. My other .csv import appears to be the same syntax and is working fine.
Here is the portion of my RSpec for .csv method:
require_relative "../models/address_book"
RSpec.describe AddressBook do
let(:book) {AddressBook.new}
def check_entry(entry, expected_name, expected_phone_number, expected_email)
expect(entry.name).to eq(expected_name)
expect(entry.phone_number).to eq(expected_phone_number)
expect(entry.email).to eq(expected_email)
end
describe "#import from csv" do
it "imports the correct number of entries" do
book.import_from_csv("entries.csv")
book_size = book.entries.size
expect(book_size).to eq 5
end
it "imports the 1rst entry" do
book.import_from_csv("entries.csv")
entry_one = book.entries[0]
check_entry(entry_one, "Bill", "555-555-4854", "bill#blocmail.com")
end
it "imports the 2nd entry" do
book.import_from_csv("entries.csv")
entry_two = book.entries[1]
check_entry(entry_two, "Bob", "555-555-5415", "bob#blocmail.com")
end
it "imports the 3rd entry" do
book.import_from_csv("entries.csv")
entry_three = book.entries[2]
check_entry(entry_three, "Joe", "555-555-3660", "joe#blocmail.com")
end
it "imports the 4th entry" do
book.import_from_csv("entries.csv")
entry_four = book.entries[3]
check_entry(entry_four, "Sally", "555-555-4646", "sally#blocmail.com")
end
it "imports the 5th entry" do
book.import_from_csv("entries.csv")
entry_five = book.entries[4]
check_entry(entry_five, "Sussie", "555-555-2036", "sussie#blocmail.com")
end
it "imports an additional 3 entries" do
book.import_from_csv("entries_2.csv")
book_size = book.entries.size
expect(book_size).to eq 3
end
it "imports 1rst entry into additional csv" do
book.import_from_csv("entries_2.csv")
entry_one = book.entries[0]
check_entry(entry_one, "Ralph", "222-222-2222", "ralph#comcast.net")
end
it "imports 2nd entry into additional csv" do
book.import_from_csv("entries_2.csv")
entry_two = book.entries[1]
check_entry(entry_two, "Will", "333-333-3333","Will#comcast.net")
end
it "imports 3rd entry into additional csv" do
book.import_from_csv("entries_2.csv")
entry_three = book.entries[2]
check_entry(entry_three, "Foobarr", "444-444-4444", "Foobarr#comcast.net")
end
end
Here is my two .csv files:
entries.csv
name,phone_number,email
Bill,555-555-4854,bill#blocmail.com
Bob,555-555-5415,bob#blocmail.com
Joe,555-555-3660,joe#blocmail.com
Sally,555-555-4646,sally#blocmail.com
Sussie,555-555-2036,sussie#blocmail.com
entries_2.csv
name,phone_number,email
Ralph,222-222-2222,ralph#comcast.net
Will,333-333-3333,Will#comcast.net
Foobarr,444-444-4444,Foobarr#comcast.net
Here is the error I am receiving when checking my RSpec:
Failures:
1) AddressBook#import from csv imports 1rst entry into additional csv
Failure/Error: expect(entry.name).to eq(expected_name)
expected: "Ralph"
got: "Foobarr"
(compared using ==)
# ./spec/address_book_spec.rb:8:in `check_entry'
# ./spec/address_book_spec.rb:142:in `block (3 levels) in <top (required)>'
2) AddressBook#import from csv imports 2nd entry into additional csv
Failure/Error: expect(entry.name).to eq(expected_name)
expected: "Will"
got: "Ralph"
(compared using ==)
# ./spec/address_book_spec.rb:8:in `check_entry'
# ./spec/address_book_spec.rb:150:in `block (3 levels) in <top (required)>'
3) AddressBook#import from csv imports 3rd entry into additional csv
Failure/Error: expect(entry.name).to eq(expected_name)
expected: "Foobarr"
got: "Will"
(compared using ==)
# ./spec/address_book_spec.rb:8:in `check_entry'
# ./spec/address_book_spec.rb:158:in `block (3 levels) in <top (required)>'
Finished in 0.05492 seconds (files took 0.2885 seconds to load)
17 examples, 3 failures
Why is my entries.csv RSpec correct, but my entries_2.csv is not? What am I missing.
Thanks

Assuming AddressBook is an ActiveRecord model with has_many :entries defined on it, the core issue you're running into is that relations are not guaranteed to be returned in any specific order, unless you explicitly request it. So this:
book.entries[0]
Is actually running:
SELECT * FROM entries WHERE address_book_id = ?
And then fetching the first element of that array. Since the above query is not ordered, the order you get back is arbitrary (as you're seeing; sometimes it reflects creation order, and sometimes it does not).
What you actually want is something which actually requests the records ordered in the sequence they were created in, like:
book.entries.order('entries.id ASC')[0]
Which you can also accomplish by adding order: 'id ASC' as a parameter to your has_many :entries definition.

I finally figured out the solution to my problem. CSV.parse sorts .csv files alphabetically, I did not know this. At this point I am unsure how I could manipulate that particular method, however, rearranging my names in my .csv file solved my problem.

Related

RSpec - A JSON text must at least contain two octets

Two failing specs after upgrading rspec-rails (2.5.2 -> 3.8.1) and capybara (2.18.0 -> 3.10.1):
Not really sure what's going on here. Looks like text in the expectation is being truncated?!?
let(:story_attributes) do
{
title: 'Edited title',
description: 'Edited location',
start_year: '2001',
start_month: 'December',
start_day: '5',
end_year: '2001',
end_month: 'October',
end_day: '10',
is_range: true,
cover_image: {
url: 'http://placehold.it/edited.png'
}
}
end
...
within 'section.story-cover' do
expect(page).to have_text 'Edited title'
expect(page).to have_text 'Edited location'
expect(page).to have_text 'December 5th - October 10th, 2001'
end
In first failed example (below) "Edited location" is being truncated.
In second example expect(page).to have_text 'Edited title Edited location' where only "Edited title\nEdited locat" is found.
Then there's this "JSON text must at least contain two octets" issue which may or may not be related but this used to pass before upgrading rspec-rails & capybara.ds
Thoughts?
RSpec Failures:
1) Story editing published edit story
Failure/Error: JSON.parse(response.body)
JSON::ParserError:
A JSON text must at least contain two octets!
# ./app/services/converter/image_service.rb:36:in `post_to_filepicker'
# ./app/services/converter/image_service.rb:18:in `convert_format'
# ./app/services/converter/image_service.rb:11:in `block in convert'
# ./app/services/converter/image_service.rb:10:in `each'
# ./app/services/converter/image_service.rb:10:in `convert'
# ./app/models/images/image.rb:5:in `convert'
# ./app/models/images/image.rb:20:in `enqueue_conversion'
# ./app/services/story/updating_service.rb:14:in `update'
# ./app/controllers/stories_controller.rb:58:in `update'
# ------------------
# --- Caused by: ---
# Capybara::ExpectationNotMet:
# expected to find text "Edited location" in "Edited title\nLyla HoegerEditedDecember 5th - October 10th, 2001Download"
# ./spec/features/stories/editing_spec.rb:86:in `block (4 levels) in <top (required)>'
2) Story editing private private story should be read after editing
Failure/Error: JSON.parse(response.body)
JSON::ParserError:
A JSON text must at least contain two octets!
# ./app/services/converter/image_service.rb:36:in `post_to_filepicker'
# ./app/services/converter/image_service.rb:18:in `convert_format'
# ./app/services/converter/image_service.rb:11:in `block in convert'
# ./app/services/converter/image_service.rb:10:in `each'
# ./app/services/converter/image_service.rb:10:in `convert'
# ./app/models/images/image.rb:5:in `convert'
# ./app/models/images/image.rb:20:in `enqueue_conversion'
# ./app/services/story/updating_service.rb:14:in `update'
# ./app/controllers/stories_controller.rb:58:in `update'
# ------------------
# --- Caused by: ---
# Capybara::ExpectationNotMet:
# expected to find text "Edited title Edited location" in "Edited title\nEdited locat"
# ./spec/features/stories/editing_spec.rb:115:in `block (4 levels) in <top (required)>'
One of the big changes between Capybara 2.x and 3.x was that in Capybara 3.x text is returned as closely to what is displayed as possible. This means that line feeds are now included in the returned text when they would display to the user - https://github.com/teamcapybara/capybara/blob/master/UPGRADING.md. You either need to change your expected text to "Edited title\nEdited location" at spec/features/stories/editing_spec.rb:115 or if you don't care about the linefeeds you can use the :normalize_ws option => expect(page).to have_text("Edited title Edited location", normalize_ws: true)

Rspec controller test assign two dimensional Hash fails

i'm trying to run a controller test:
the controller code is
def aix_service_accounts
#no_dn_users= Hash.new
record = 0
#no_dn_users[record]= Hash.new
#no_dn_users[record]['aix_username'] ="abc"
end
The rspec code is
it "should show aix_service_accounts" do
get :aix_service_accounts
expect(assigns(:no_dn_users[0]['aix_username'])).to eq 'abc'
end
The result is
Failures:
1) AixController should show aix_service_accounts
Failure/Error: expect(assigns(:no_dn_users[0]['aix_username'])).to eq 'abc'
expected: "abc"
got: {"marked_for_same_origin_verification"=>true, "no_dn_users"=>{0=>{"aix_username"=>"abc"}}}
(compared using ==)
Diff:
## -1,2 +1,3 ##
-"abc"
+"marked_for_same_origin_verification" => true,
+"no_dn_users" => {0=>{"aix_username"=>"abc"}},
# ./spec/controllers/aix_controller_spec.rb:29:in `block (2 levels) in <top (required)>'
Could anyone help and explain the reason to me? Thanks!
Sure - you're trying to ask for a single key called :no_dn_users[0]['aix_username'] from the assigns. You need to change that to:
assigns(:no_dn_users)[0]['aix_username']
instead.
Ie, get out the first part by the key :no_dn_users, this will be the hash-inside-an-array that you're then referencing using indexing

rspec testing strong params and building a model

I am attempting to write a model test, like so:
require 'spec_helper'
describe Five9List do
before :each do
#five9_list = Five9List.new(name: 'test_list', size: '100')
end
describe "#new" do
it "takes two parameters and returns a Five9List object" do
#five9_list.should be_an_instance_of Five9List
end
end
describe "#name" do
it "returns the correct name" do
#five9_list.name.should eql "test_list"
end
end
describe "#size" do
it "returns the correct size" do
#five9_list.size.should eql 100
end
end
end
Currently, this succeeds and works fine. That's because my model is using attr_accessible, like so:
class Five9List < ActiveRecord::Base
attr_accessible :name, :size
end
If I want to get rid of attr_accessible and follow the rails 4 convention of using strong_params, how would I write that to where my rspec test would still succeed?
Adding this in my controller:
private
def five9_list_params
params.require(:five9_list).permit(:name, :size)
end
And removing attr_accessible does not work.
EDIT
Here is the error I receive from rspec .:
Failures:
1) Five9List#name returns the correct name
Failure/Error: #five9_list.name.should eql "test_list"
expected: "test_list"
got: nil
(compared using eql?)
# ./spec/models/five9_list_spec.rb:16:in `block (3 levels) in <top (required)>'
2) Five9List#size returns the correct size
Failure/Error: #five9_list.size.should eql 100
expected: 100
got: nil
(compared using eql?)
# ./spec/models/five9_list_spec.rb:22:in `block (3 levels) in <top (required)>'
Finished in 0.03303 seconds
4 examples, 2 failures, 1 pending
Failed examples:
rspec ./spec/models/five9_list_spec.rb:15 # Five9List#name returns the correct name
rspec ./spec/models/five9_list_spec.rb:21 # Five9List#size returns the correct size
Randomized with seed 20608
There's nothing wrong with your spec. I can only guess that you're not running Rails 4 or you've installed the ProtectedAttributes gem.

FactoryGirls randomly fails with 'Factory not registered', why?

I've some tests that randomly fail, approx. 20% of times. It means that WITHOUT changing the code, each time that I run the tests 1 time out of 5 will fail with "Factory not registered" error. It's very weird.. :(
This is the consone output:
Failures:
1) Unit#new_from_string returns factor for metric conversions
Failure/Error: FactoryGirl.create :taza
ArgumentError:
Factory not registered: taza
# ./spec/models/unit_spec.rb:29:in `block (2 levels) in <top (required)>'
Finished in 0.29619 seconds
4 examples, 1 failure
Failed examples:
rspec ./spec/models/unit_spec.rb:22 # Unit#new_from_string returns factor for metric conversions
Randomized with seed 61727
And this is the code:
file: "unit_spec.rb"
require 'spec_helper'
describe Unit, "#new_from_string" do
it "parses the string and returns a Unit object" do
[some tests...]
FactoryGirl.find_definitions
u = FactoryGirl.create :taza
FactoryGirl.create :tbsp
[tests...]
end
it "returns factor for metric conversions" do
[tests not involving factory girl...]
# the following is line 29, that fails
FactoryGirl.create :taza
[tests...]
end
end
file "spec/factories/units.rb":
FactoryGirl.define do
factory :taza , :class => CustomUnit do
singular 'taza'
plural 'tazas'
physical_type Unit::VOLUME
equivalence_factor 200
equivalence_unit 'ml'
end
[other factories...]
end
I think the problem is on this line
FactoryGirl.find_definitions
Actually there is no need for this line when your factories are in correct directories(I see it is), and you put gem factory_girl_rails in Gemfile.
I think, 20% of time, the second test get run at first. At this time, there is no definition of Factory and the test failed. The other test has such definition and get passed. In other time, the first test run first so definition exists.
My suggestion:
Make sure you have factory_girl_rails, not factory_girl in Gemfile.
Remove that line of definition.
[optional but recommended] Put all definition in a single file spec/factories and remove all other factory files, if you don't have too much factories. This would be easier to manage.

How to write spec for ActiveRecord

My spec/models code as require 'spec_helper'
describe Student do
it "should be work" do
student = Student.find 1
puts student.version
end
end
When running the code it shows the following error..,
Failures:
1) Student should be work
Failure/Error: student = Student.find 2
ActiveRecord::StatementInvalid:
Could not find table 'students'
# ./spec/models/student_spec.rb:6:in `block (2 levels) in <top (require
Finished in 0.00109 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/models/student_spec.rb:4 # Student should be work
I'm having students table.Also, I'm using paper_trail gem.
After running rake db:test:prepare then it shows an error as.,
Failures:
1) Student should be work
Failure/Error: s = Student.find 1
ActiveRecord::RecordNotFound:
Couldn't find Student with id=1
# ./models/student_spec.rb:5:in `block (2 levels) in <top (required)>'
Finished in 0.02182 seconds
1 example, 1 failure
Failed examples:
rspec ./models/student_spec.rb:4 # Student should be work
It seems there is no table students in test environment, try to run
$ bundle exec rake db:test:prepare
Do you have propagated some data in your test database (using fixtures or something like FactoryGirl gem)?
Otherwise you wouldn't find any "students" in your DB.
Test-DB and Development DB have nothing in common. In fact the Test-DB will be cleared for each test.
The problem is there is no studend with id=1 in the students table of the test DB (the test DB is cleared before start new tests).
What do you want to test?
Maybe you want to use the before to insert a student at the start of the spec:
describe Student do
before do
#student = Student.new(:version => 15)
#student.save
end
it "should be work" do
student = Student.first
# Test something ...
end
end
The before block is run before every test, in this case you can get the first student in the (test) DB because you inserted it in the before block (but I don't know what you're trying to test and if save a student is really needed).

Resources