I want to test a class function on RSpec on my Product class. To ease the reading I will keep it as this:
class Product < ApplicationRecord
private
def self.order_list(sort_by)
if sort_by == 'featured' || sort_by.blank?
self.order(sales: :desc)
elsif sort_by == 'name A-Z'
self.order(name: :asc)
elsif sort_by == 'name Z-A'
self.order(name: :desc)
elsif sort_by == 'rating 1-5'
self.order(:rating)
elsif sort_by == 'rating 5-1'
self.order(rating: :desc)
elsif sort_by == 'price low-high'
self.order(:price)
elsif sort_by == 'price high-low'
self.order(price: :desc)
elsif sort_by == 'date old-new'
self.order(:updated_at)
elsif sort_by == 'date new-old'
self.order(updated_at: :desc)
end
end
end
Once the function is called with a parameter, depending on the parameter that has been used, the list of products is ordered in a different way for the user to see.
I built a FactoryBot for the product model as well:
FactoryBot.define do
factory :product do
sequence(:name) { |n| "product_test#{n}" }
description { "Lorem ipsum dolor sit amet" }
price { rand(2000...10000) }
association :user, factory: :non_admin_user
rating { rand(1..5) }
trait :correct_availability do
availability { 1 }
end
trait :incorrect_availability do
availability { 3 }
end
#Adds a test image for product after being created
after(:create) do |product|
product.photos.attach(
io: File.open(Rails.root.join('test', 'fixtures', 'files', 'test.jpg')),
filename: 'test.jpg',
content_type: 'image/jpg'
)
end
factory :correct_product, traits: [:correct_availability]
factory :incorrect_product, traits: [:incorrect_availability]
end
end
Basically, we want to call the :correct_product to create a product thats accepted by the validations of the model.
For the specs:
describe ".order_list" do
let!(:first_product) { FactoryBot.create(:correct_product, name: "First Product" , rating: 1) }
let!(:second_product) { FactoryBot.create(:correct_product, name: "Second Product" , rating: 2) }
let!(:third_product) { FactoryBot.create(:correct_product, name: "Third Product" , rating: 3) }
it "orders products according to param" do
ordered_list = Product.order_list('rating 1-5')
expect(ordered_list.all).to eq[third_product, second_product, first_product]
end
end
So basically, my question is, how can I create an instance variable for each of the 3 mock products so I can name them here in the order I expect them to appear:
expect(ordered_list.all).to eq[third_product, second_product, first_product]
Or, even better, is there a way to create the instance variables with a loop and actually have the instance variable name to use them in the expect? This would free me from having to create 3 different variables on FactoryBot as I did.
I searched around the web and instance_variable_set is used in some cases:
Testing Rails with request specs, instance variables and custom primary keys
Simple instance_variable_set in RSpec does not work, but why not?
But it doesn´t seem to work for me. Any idea on how could I make it work? Thanks!
elsif's.expect(ordered_list.pluck(:name)).to_eq(["Third Product" , "Second Product", "First Product"]))).for starters you're calling and testing a private method.is there a problem with that? @max