I'm using latest version of Solidus e-commerce (fork of Spree) and I'm having this issue. To describe it quickly:
- In Admin I create Spree::Membership record
- after_save callback in Spree::Membership creates Product and 2 variants
This code works when I run the server, but when I'm trying to use Rspec it gives me this error:
Failure/Error: reload.product.setup_membership_variants
NoMethodError:
undefined method `setup_membership_variants' for nil:NilClass
# ./app/models/spree/membership.rb:26:in `block in setup_product'
# ./app/models/spree/membership.rb:18:in `setup_product'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/configuration.rb:18:in `block in initialize'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/evaluation.rb:15:in `create'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy/create.rb:12:in `block in result'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy/create.rb:9:in `tap'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy/create.rb:9:in `result'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/factory.rb:42:in `run'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/factory_runner.rb:29:in `block in run'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/factory_runner.rb:28:in `run'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy_syntax_method_registrar.rb:20:in `block in define_singular_strategy_method'
# ./spec/controllers/spree/premium_controller_spec.rb:4:in `block (2 levels) in <top (required)>'
# ./spec/controllers/spree/premium_controller_spec.rb:33:in `block (6 levels) in <top (required)>'
# ./spec/controllers/spree/premium_controller_spec.rb:53:in `block (8 levels) in <top (required)>'
# ./spec/controllers/spree/premium_controller_spec.rb:53:in `block (7 levels) in <top (required)>'
Here is code I'm using:
membership.rb
class Spree::Membership < Spree::Base
has_many :active_memberships, class_name: 'Spree::ActiveMembership', dependent: :destroy
has_one :membership_product, class_name: "Spree::MembershipProduct", dependent: :destroy
has_one :product, through: :membership_product, source: :product
validates :name, presence: true
validates :monthly_quota, presence: true
validates :price, presence: true
after_save :setup_product
private
def setup_product
if product.nil?
ActiveRecord::Base.transaction do
create_membership_product(
product: Spree::Product.create(
name: name,
price: price,
shipping_category: Spree::ShippingCategory.find_by(name: "Default")
)
)
reload.product.setup_membership_variants
end
else
product.update(name: name, price: price)
end
end
end
product_decorator.rb
Spree::Product.class_eval do
def setup_membership_variants
ot = Spree::OptionType.find_or_create_by(name: "Membership")
option_types << ot
if ot.option_values.empty?
["Monthly", "Yearly"].each do |freq|
ot.option_values.create(name: freq, presentation: freq)
end
end
month = variants.create(is_master: false, price: price, track_inventory: false)
month.option_values << Spree::OptionValue.find_by(name: "Monthly")
year = variants.create(is_master: false, price: price * 12, track_inventory: false)
year.option_values << Spree::OptionValue.find_by(name: "Yearly")
end
end
membership.rb factory
FactoryGirl.define do
factory :membership, class: Spree::Membership do
name {FFaker::Lorem.word}
monthly_quota { rand(10..200) }
price { rand(10..200) }
trait :unnamed do
name nil
end
trait :without_quota do
monthly_quota nil
end
trait :priceless do
price nil
end
end
end
example of controller test
require 'rails_helper'
RSpec.describe Spree::PremiumController, type: :controller do
let(:valid_membership) { create(:membership) }
let(:variant) { create(:master_variant) }
context "#show" do
it "returns http success" do
get :show
expect(response).to have_http_status(:success)
end
it "returns all memberships" do
get :show
expect(assigns[:memberships]).to include(valid_membership)
end
end
context "#create" do
let!(:store) { create(:store) }
context "user not logged" do
context "valid attributes" do
context "user doesn't exist in database" do
subject do
post(:create, params: {
premium: {
first_name: "Ondrej",
last_name: "Kubala",
email: "ondrej@bala.com",
password: "test123",
password_confirmation: "test123",
membership_id: valid_membership.id,
payment_frequency: "1", #monthly yearly is 2
cc_number: "4111111111111111",
cc_exp_date: "10/22",
cvv: "123"
}
})
end
it "creates user with valid attributes" do
expect { subject }.to change { Spree::User.count }.from(0).to(1)
end
it "logs in user" do
expect(controller.warden).to receive(:set_user)
subject
end
context "create order with variant" do
it "should handle population" do
expect { subject }.to change { Spree::Order.count }.by(1)
user = Spree::User.find_by email: "ondrej@bala.com"
order = user.orders.last
expect(response).to redirect_to go_premium_path
expect(order.line_items.size).to eq(1)
# line_item = order.line_items.first
# expect(line_item.variant_id).to eq(valid_membership.reload.product.variants.)
end
it "charges credit card"
it "should redirect to account page"
end
end
context "user already exists"
end
context "wrong user attributes" do
end
context "wrong payment attributes" do
end
end
context "user is logged in" do
let(:user) { create(:user) }
before do
allow(controller).to receive_messages try_spree_current_user: user
allow(controller).to receive_messages spree_current_user: user
end
it "doesn't create user"
end
end
end
I don't have too much experience in Rspec, but it's weird that it works when server is running in development but in test it gives me that error.
Any idea what is wrong?