Skip to content

Instantly share code, notes, and snippets.

@zaeem
Created April 15, 2015 15:32
Show Gist options
  • Save zaeem/616174e5c461a208e001 to your computer and use it in GitHub Desktop.
Save zaeem/616174e5c461a208e001 to your computer and use it in GitHub Desktop.
require 'spec_helper'
describe CartsController do
include Fdoc::SpecWatcher
it_behaves_like "a base cart controller", "carts", "/:id"
let(:sku){mock_sku}
let(:sku_2){mock_sku(id:20, code:'FLB-R-M', current_retail_price:Money.new(1900), current_sale_price:Money.new(1800),
current_stylist_price:Money.new(900), pqv:2800, display_category_ids:[1,2,3])}
let(:sku_3){mock_sku(id:1, code:'FLB-R-M', current_retail_price:Money.new(1900), current_sale_price:Money.new(1800),
current_stylist_price:Money.new(900), pqv:2800, display_category_ids:[1,2,3], product_type:"StarterKitProduct",
best_valued: true)}
let(:bundle) { mock_bundle }
let(:bundle_error) { mock_bundle({errors: double(messages: {'base' => ["Sku not part of bundle"]})}, 2) }
before do
CatalogService.stub(:get_sku).with(sku.id).and_return(sku)
CatalogService.stub(:get_sku).with(sku_2.id).and_return(sku_2)
CatalogService.stub(:get_sku).with(sku_3.id).and_return(sku_3)
CatalogService.stub(:starter_kits).and_return([sku_3])
CatalogService.stub(:build_bundle).with(bundle.code, [bundle.skus.first.id]).and_return(bundle)
CatalogService.stub(:build_bundle).with(bundle_error.code, bundle_error.skus.map(&:id)).and_return(bundle_error)
@items = []
InventoryService.stub(:in_stock?).with(any_args).and_return(true)
PromotionService.stub(:evaluate).and_return(double(items: []))
UserService.stub(:get_user).and_return({"receive_marketing_emails_at" => "2014-07-17T14:20:11.000Z"})
end
describe "DSR endpoints" do
before do
request.stub(:headers).and_return({"X-Rosi-Platform" => platform_key, "X-Rosi-Auth" => "abc"})
@user = sign_in(User.new(id:1, role:"dsr", phone_number:"1234567890", email:"email@email.com", first_name:"Jane", last_name:"Doe"))
MyBusinessService.stub(:find_contact).and_return({})
end
describe "destroy", fdoc: "cart_service/carts/:id" do
before do
UserService.stub(:credits).and_return({"store_credits"=>500, "hostess_credits"=>0,
"hostess_discounts_hash"=>{"count"=>0, "percentage"=>50}})
@cart = FactoryGirl.create(:cart_with_items, store_credits_total:5)
end
it "should mark cart as 'pending_removal' but not delete it from database" do
delete :destroy, id: @cart.id, format: :json
expect(response).to be_success
@cart.reload
expect(@cart).to_not be_nil
expect(@cart.workflow_state).to eq("pending_removal")
end
end
describe "not_imported" do
before do
@cart = FactoryGirl.create(:cart_with_items, dsr_id: 1, workflow_state: "active")
end
context "valid", fdoc: 'cart_service/carts/not_imported' do
it "should return carts which are not imported yet" do
get :not_imported, format: :json
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart).to_not be_nil
end
end
end
describe "create" do
before do
@cart_create_params = {customer_first_name:"Jane", customer_last_name:"Doe", customer_email:"jane@doe.com",
customer_id:27, type_code:"dsr_customer", contact_id: 1,
billing_address_attributes: {
address1:"111 Sherbrook Drive", city:"Berkeley Heights",
state:"NJ", zip_code:"07922", first_name:"Jane", last_name:"Doe", phone:"123 4567 890"},
format: :json}
end
context "valid call", fdoc: "cart_service/carts" do
it "it require customer_id and type_code parameters" do
post :create, customer_first_name:"Jane", customer_last_name:"Doe", customer_email:"jane@doe.com", format: :json
expect(response.status).to eq(422)
errors = JSON.parse(response.body)
expect(errors['fields']).to include('type_code')
expect(errors['fields']).to include('customer_id')
end
it "should respond with cart json representation (details can be tested in view spec)" do
post :create, @cart_create_params
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart).to_not be_nil
end
it "should accept shipping address" do
shipping_address_params = {address1:"111 Sherbrook Drive", city:"Berkeley Heights",
state:"NJ", zip_code:"07922", first_name:"Jane", last_name:"Doe", phone:"123 4567 890"}
post :create, @cart_create_params.merge({shipping_address_attributes: shipping_address_params})
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(Cart.find(json_cart["id"]).shipping_address).not_to be_nil
expect(Cart.find(json_cart["id"]).shipping_address.address1).to eq("111 Sherbrook Drive")
end
it "should accept billing address" do
billing_address_params = {address1:"111 Sherbrook Drive", city:"Berkeley Heights",
state:"NJ", zip_code:"07922", first_name:"Jane", last_name:"Doe", phone:"123 4567 890"}
post :create, @cart_create_params.merge({billing_address_attributes: billing_address_params})
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(Cart.find(json_cart["id"]).billing_address).not_to be_nil
expect(Cart.find(json_cart["id"]).billing_address.address1).to eq("111 Sherbrook Drive")
end
it "should validate shipping attributes if shipping_address_attributes is included" do
post :create, @cart_create_params.merge({shipping_address_attributes: {}})
expect(response.status).to eq(422)
errors = JSON.parse(response.body)
expect(errors["fields"]).to match_array ["shipping_address.address1","shipping_address.city","shipping_address.state",
"shipping_address.zip_code", "shipping_address.first_name", "shipping_address.last_name", "shipping_address.phone"]
end
it "should validate billing attributes if billing_address_attributes is included" do
post :create, @cart_create_params.merge({billing_address_attributes: {}})
expect(response.status).to eq(422)
errors = JSON.parse(response.body)
expect(errors["fields"]).to match_array ["billing_address.address1","billing_address.city","billing_address.state",
"billing_address.zip_code", "billing_address.first_name", "billing_address.last_name"]
end
context "when cart type is DSR" do
before do
@cart_create_params[:type_code]= "dsr"
expect(@user).to receive(:reload_user).and_return(@user)
end
it "should discard customer_name field and use DSR data" do
post :create, @cart_create_params
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart["customer_first_name"]).to eq(@user.first_name)
end
end
context "when cart type is StarterKit", platform: "keep" do
before do
@cart_create_params[:type_code]= "starter_kit"
expect(@user).to receive(:reload_user).and_return(@user)
end
it "should discard customer_name field and use DSR data" do
post :create, @cart_create_params
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart["customer_first_name"]).to eq(@user.first_name)
expect(json_cart["type_code"]).to eq("starter_kit")
end
it "should automatically have the best valued startert_kit_product added" do
post :create, @cart_create_params
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart['items'].size).to eq(1)
expect(json_cart['items'].first['sku_id']).to eq(1)
end
end
end
it "should disregard public_order_id value" do
post :create, @cart_create_params.merge({public_order_id:888})
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart["public_order_id"]).to eq json_cart["id"]
end
end
context "when there exists a cart for the customer" do
before do
UserService.stub(:credits).and_return({"store_credits"=>500, "hostess_credits"=>0,
"hostess_discounts_hash"=>{"count"=>0, "percentage"=>50}})
@cart = FactoryGirl.create(:cart_with_items, store_credits_total:5)
end
describe "show", fdoc: "cart_service/carts/:id" do
it "should return not found if cart is not found" do
get :show, id: 99, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
it "should return not found if cart is status is not editable" do
@cart.workflow_state = "pending_removal"
@cart.save
get :show, id: @cart.id, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
end
describe "create", fdoc: "cart_service/carts" do
it "should return existing cart from customer" do
post :create, customer_first_name:@cart.customer_first_name, customer_last_name:@cart.customer_last_name,
customer_email:@cart.customer_email, customer_id:@cart.customer_id, type_code:@cart.type_code, format: :json
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart["id"]).to eq(@cart.id)
end
end
describe "remove_bundle", fdoc: 'cart_service/carts/:id/remove_bundle' do
before do
@cart = FactoryGirl.create(:cart_with_bundle, store_credits_total:5)
current_user.stub_chain(:carts, :editable, :includes, :find).and_return(@cart)
expect(@cart).to receive(:update_totals).and_call_original
end
it "should remove the bundle" do
delete :remove_bundle, bundle_id: @cart.cart_items.first.bundle_id, id: @cart.id, format: :json
json_cart = JSON.parse(response.body)
expect(@cart.cart_items.count).to eq(0)
expect(response).to be_success
end
end
describe "add_bundle", fdoc: 'cart_service/carts/:id/add_bundle' do
it "should show unprocessable_entity error if quantity is greater than or equal to 100" do
sku_ids = bundle.skus.map(&:id)
post :add_bundle, id: @cart.id, code: bundle.code, sku_ids: sku_ids, quantity: 100, format: :json
expect(response.status).to eq(422)
errors = JSON.parse(response.body)['errors']
expect(errors['base']).to include("quantity should be less than the product's maximum purchasable quantity: 100")
end
it "should show unprocessable_entity error if quantity is less or equal than 0" do
post :add_bundle, id: @cart.id, code: bundle.code, sku_ids: [1], quantity: 0, format: :json
expect(response.status).to eq(422)
errors = JSON.parse(response.body)['errors']
expect(errors['base']).to include('quantity should be greater than zero')
end
it "it should show unprocessable_entity error if bundle is not valid" do
post :add_bundle, id: @cart.id, code: bundle_error.code, sku_ids:bundle_error.skus.map(&:id), quantity: 1, format: :json
expect(response.status).to eq(422)
errors = JSON.parse(response.body)['errors']
expect(errors['base']).to include('Sku not part of bundle')
end
describe "successful calls" do
before do
current_user.stub_chain(:carts, :editable, :includes, :find).and_return(@cart)
expect(@cart).to receive(:update_totals).and_call_original
end
it "should add all sku_ids" do
quantity = 1
sku_ids = bundle.skus.map(&:id)
old_size = @cart.cart_items.size
post :add_bundle, id: @cart.id, code: bundle.code, sku_ids: sku_ids, quantity: quantity, format: :json
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart['items'].size).to eq(old_size+(quantity * sku_ids.size))
expect(json_cart['items'].count{|cart_item| cart_item['sku_id'] == sku_ids.first}).to eq(quantity)
end
end
end
describe "add_sku", fdoc: "cart_service/carts/:id/add_sku" do
it "should return not found if cart is not found" do
post :add_sku, id:99, sku_id: sku.id, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
it "should return not found if cart is status is not editable" do
@cart.workflow_state = "pending_removal"
@cart.save
post :add_sku, id:@cart.id, sku_id: sku.id, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
end
describe "remove_sku", fdoc: "cart_service/carts/:id/remove_sku" do
it "should return not found if cart is not found" do
delete :remove_sku, id:99, sku_id: sku.id, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
it "should return not found if cart is status is not editable" do
@cart.workflow_state = "pending_removal"
@cart.save
delete :remove_sku, id:@cart.id, sku_id: sku.id, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
end
describe "set_sku_quantity", fdoc: "cart_service/carts/:id/set_sku_quantity" do
describe "error handling" do
it "should return not found if cart is not found" do
patch :set_sku_quantity, id:99, sku_id: sku.id, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
it "should return not found if cart is status is not editable" do
@cart.workflow_state = "pending_removal"
@cart.save
patch :set_sku_quantity, id:@cart.id, sku_id: sku.id, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
end
end
describe "destroy", fdoc: "cart_service/carts/:id" do
it "should return not found if cart is not found" do
delete :destroy, id: 99, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
it "should return not found if cart is status is not editable" do
@cart.workflow_state = "pending_removal"
@cart.save
delete :destroy, id: @cart.id, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
end
describe "checkout_status", fdoc: "cart_service/carts/:id/checkout_status" do
it "should return not found if cart is not found" do
get :checkout_status, id: 99, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
context "when cart is removed" do
before do
@cart.update_attribute(:workflow_state, "pending_removal")
end
it "should return not found if cart is status is not editable" do
get :checkout_status, id: @cart.id, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
end
end
describe "hostess_credits", fdoc: 'cart_service/carts/:id/hostess_credits' do
before do
UserService.stub(:credits).and_return({"store_credits"=>1, "hostess_credits"=>1000,
"hostess_discounts_hash"=>{"count"=>1, "percentage"=>50}})
@cart = FactoryGirl.create(:dsr_hostess_cart)
FactoryGirl.create_list(:cart_item,2,cart:@cart, sku_id:sku.id,price_cents:1800)
@cart.update_totals
end
it "should return not found if cart is not found" do
post :hostess_credits, id: 99, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
it "should show correctly the new hostess_credits_total" do
post :hostess_credits, id:@cart.id, amount:1000, format: :json
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart["hostess_credits_total"]["cents"]).to eq 1000
end
context "when there is not enough balance" do
it "should render error response" do
post :hostess_credits, id:@cart.id, amount:1500, format: :json
expect(response.status).to eq(422)
error_hash = JSON.parse(response.body)["errors"]
expect(error_hash["hostess_credits_total_cents"]).to include("Available user credits are exceeded")
end
end
end
describe "product_credits", fdoc: 'cart_service/carts/:id/product_credits' do
before do
UserService.stub(:credits).and_return({"store_credits"=>1, "hostess_credits"=>1000, "product_credits" => 1000,
"hostess_discounts_hash"=>{"count"=>1, "percentage"=>50}})
@cart = FactoryGirl.create(:dsr_cart)
FactoryGirl.create_list(:cart_item,2,cart:@cart, sku_id:sku.id,price_cents:1800)
@cart.update_totals
end
it "should return not found if cart is not found" do
post :product_credits, id: 99, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
it "should show correctly the new product_credits_total" do
post :product_credits, id:@cart.id, amount:1000, format: :json
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart["product_credits_total"]["cents"]).to eq 1000
end
context "when there is not enough balance" do
it "should render error response" do
post :product_credits, id:@cart.id, amount:1500, format: :json
expect(response.status).to eq(422)
error_hash = JSON.parse(response.body)["errors"]
expect(error_hash["product_credits_total_cents"]).to include("Available user credits are exceeded")
end
end
end
describe "store_credits", fdoc: 'cart_service/carts/:id/store_credits' do
before do
UserService.stub(:credits).and_return({"store_credits"=>1000, "hostess_credits"=>1,
"hostess_discounts_hash"=>{"count"=>1, "percentage"=>50}})
end
it "should return not found if cart is not found" do
post :store_credits, id: 99, format: :json
expect(response.status).to eq(404)
errors = JSON.parse(response.body)['errors']
expect(errors).to eq("Cart not found")
end
it "should show correctly the new store_credits_total" do
post :store_credits, id:@cart.id, amount:1000, format: :json
expect(response).to be_success
json_cart = JSON.parse(response.body)
expect(json_cart["store_credits_total"]["cents"]).to eq 1000
end
context "when there is not enough balance" do
it "should render error response" do
post :store_credits, id:@cart.id, amount:1500, format: :json
expect(response.status).to eq(422)
error_hash = JSON.parse(response.body)["errors"]
expect(error_hash["store_credits_total_cents"]).to include("Available user balance is exceeded")
end
end
end
end
end
describe "Invalid platform headers" do
context "when no platform no auth" do
it "should return bad request on not_imported" do
get :not_imported, id: 99, format: :json
end
it "should return bad request on create" do
post :create, {customer_first_name:"Jane", customer_last_name:"Doe", customer_email:"jane@doe.com", format: :json}
end
after do
expect(response.status).to eq(400)
expect(response.body).to eq({ error: { message: "Invalid platform parameters" } }.to_json)
end
end
context "when platform but no auth" do
before{request.stub(:headers).and_return({"X-Rosi-Platform" => platform_key})}
it "should return bad request on create" do
post :create, {customer_first_name:"Jane", customer_last_name:"Doe", customer_email:"jane@doe.com", format: :json}
end
it "should return bad request on show" do
get :show, id: 99, format: :json
end
it "should return bad request on add_sku" do
post :add_sku, id:99, sku_id: sku.id, format: :json
end
it "should return bad request on remove_sku" do
post :remove_sku, id:99, sku_id:1, format: :json
end
it "should return bad request on update" do
put :update, id:99, format: :json
end
it "should return bad request on set_sku_quantity" do
patch :set_sku_quantity, id:99, sku_id: sku.id, format: :json
end
it "should return bad request on destroy" do
delete :destroy, id: 99, format: :json
end
it "should return bad request on checkout_status" do
get :checkout_status, id: 99, format: :json
end
it "should return bad request on not_imported" do
get :not_imported, id: 99, format: :json
end
after do
expect(response.status).to eq(401)
expect(response.body).to eq({ error: { message: "Incorrect credentials" } }.to_json)
end
end
end
describe 'private_authentication endpoints' do
before do
request.stub(:headers).and_return({"X-Rosi-Platform" => platform_key, "X-Rosi-Auth" => RosiCommon.config_store.rosi.rosi_user.private_token})
expect(controller).to receive(:private_authentication).and_call_original
expect(controller).to_not receive(:dsr_authentication)
end
describe 'update_tax', fdoc: 'cart_service/carts/:id/update_tax' do
subject { FactoryGirl.create(:cart_with_items) }
let(:cart_item_tax_cents){ 20 }
let(:cart_tax_cents){ cart_item_tax_cents * subject.cart_items.count }
let(:items){
subject.cart_items.map{|item|
{'item_id' => item.id, 'tax_cents' => cart_item_tax_cents}
}
}
context 'correct private authentication' do
before do
Cart.stub(:editable).and_return Cart
Cart.stub(:find).with(subject.id.to_s).and_return subject
expect(Cart).to receive(:find).with(subject.id.to_s)
sign_in(User.new(id:1, role:"dsr"))
end
it "succesfully should call model's update_tax method, passing the adequate params" do
patch :update_tax, {id: subject.id, tax_cents: cart_tax_cents, tax_version: subject.tax_version, items: items, format: :json}
expect(response.status).to eq(200)
expect(response).to be_success
expect(response.body).to eq('{}')
end
context 'when there are missing params' do
it 'responds with 422' do
patch :update_tax, {id: subject.id, format: :json}
expect(response.status).to eq(422)
expect(response).to_not be_success
expect(response.body.blank?).to be_false
end
end
context 'when mismatching old tax_version is passed' do
it 'responds with 202' do
tax_version = subject.tax_version - 1
patch :update_tax, {id: subject.id, tax_cents: cart_tax_cents, tax_version: tax_version, items: items, format: :json}
expect(response.status).to eq(202)
expect(response).to be_success
expect(response.body).to eq('{}')
end
end
end
context "when passed auth token doesn't match with this service's private_token" do
before do
request.stub(:headers).and_return({"X-Rosi-Platform" => platform_key, "X-Rosi-Auth" => "different #{RosiCommon.config_store.rosi.rosi_user.private_token}"})
end
it 'responds with 401' do
patch :update_tax, {id: subject.id, tax_cents: cart_item_tax_cents, tax_version: subject.tax_version, items: items, format: :json}
expect(response.status).to eq(401)
expect(response).to_not be_success
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment