Commit 4204ccdd by Hoang Phuc Do

RSpec for controller

parent e9c28cd3
......@@ -75,6 +75,10 @@ group :development, :test do
gem 'factory_girl_rails', '~> 4.8'
# Making tests easy on the fingers and eyes
gem 'shoulda', '~> 3.5'
# An IRB alternative and runtime developer console
gem 'pry', '~> 0.10.4'
# Extracting `assigns` and `assert_template` from ActionDispatch.
gem 'rails-controller-testing', '~> 1.0', '>= 1.0.2'
# Adds support for Capybara system testing and selenium driver
gem 'capybara', '~> 2.13'
gem 'selenium-webdriver'
......
......@@ -68,6 +68,7 @@ GEM
mime-types (>= 1.16)
childprocess (0.7.0)
ffi (~> 1.0, >= 1.0.11)
coderay (1.1.1)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
......@@ -154,6 +155,10 @@ GEM
parser (2.4.0.0)
ast (~> 2.2)
powerpack (0.1.1)
pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
public_suffix (2.0.5)
puma (3.9.1)
rack (2.0.3)
......@@ -179,6 +184,10 @@ GEM
rails-assets-bootstrap (>= 3.0.0)
rails-assets-jquery (>= 1.9.0)
rails-assets-jquery (3.2.1)
rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1)
actionview (~> 5.x, >= 5.0.1)
activesupport (~> 5.x)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
......@@ -252,6 +261,7 @@ GEM
connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0)
redis (~> 3.3, >= 3.3.3)
slop (3.6.0)
spring (2.0.2)
activesupport (>= 4.2)
spring-watcher-listen (2.0.1)
......@@ -313,9 +323,11 @@ DEPENDENCIES
listen (>= 3.0.5, < 3.2)
mini_magick
mysql2 (>= 0.3.18, < 0.5)
pry (~> 0.10.4)
puma (~> 3.7)
rails (~> 5.1.1)
rails-assets-bootstrap-touchspin!
rails-controller-testing (~> 1.0, >= 1.0.2)
rsolr (~> 2.0, >= 2.0.2)
rspec-rails (~> 3.6)
rubocop (~> 0.49.1)
......
......@@ -16,6 +16,13 @@ class ApplicationController < ActionController::Base
end
end
def user_is_admin?
return false unless user_signed_in?
unless current_user.admin?
redirect_to root_url, notice: "You don't have access to this page"
end
end
protected
def configure_permitted_parameters
......
class OrdersController < ApplicationController
include CartsHelper
before_action :authenticate_user!, only: :new
before_action :set_order, only: [:edit, :update]
before_action :authenticate_user!, only: [:new, :create]
before_action :user_is_admin?, only: [:edit, :update]
before_action :set_order, only: [:show, :edit, :update]
before_action :order_owner?, only: :show
before_action :set_order_items, only: :new
# GET /orders/1
......@@ -18,11 +20,10 @@ class OrdersController < ApplicationController
# POST /orders
def create
@order = Order.create(user: current_user,
order_status: 0)
save_order_items(@order)
@order = Order.new(order_params.merge(user_id: current_user.id))
if @order.present?
if @order.save
save_order_items(@order)
destroy_cart_session
OrderMailer.send_order_detail_to_user(current_user, @order).deliver_later
redirect_to order_url(@order)
......@@ -51,7 +52,8 @@ class OrdersController < ApplicationController
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
params.require(:order).permit(:order_status)
default_params = { order_status: Order.default_order_status }
params.require(:order).permit(:order_status).reverse_merge(default_params)
end
def set_order
......@@ -61,4 +63,10 @@ class OrdersController < ApplicationController
def set_order_items
@order_items = @cart.product_items
end
def order_owner?
unless @order.user == current_user
redirect_to root_url, notice: "You don't have access to this order"
end
end
end
\ No newline at end of file
......@@ -2,7 +2,6 @@ class ProductsController < ApplicationController
before_action :authenticate_user!, only: [:new, :edit, :create, :update, :destroy]
before_action :set_product, only: :show
before_action :user_can_edit_product, only: [:edit, :update, :destroy]
before_action :set_solr, only: [:create, :update, :destroy]
# GET /products/new
def new
......@@ -13,7 +12,6 @@ class ProductsController < ApplicationController
def create
@product = Product.new(product_params.merge(user_id: current_user.id))
if @product.save
@solr.add_product(@product)
redirect_to root_url, flash: { success: "Product #{@product.title} is sucessfully created" }
else
render 'new'
......@@ -23,7 +21,6 @@ class ProductsController < ApplicationController
# PATCH/PUT /products/1
def update
if @product.update(product_params)
@solr.update_product(@product)
redirect_to root_url, flash: { success: "Product #{@product.title} is sucessfully updated" }
else
render 'edit'
......@@ -34,7 +31,6 @@ class ProductsController < ApplicationController
def destroy
if @product.destroy
flash[:success] = "Product #{@product.title} deleted"
@solr.delete_product(@product)
else
flash[:alert] = "Product #{@product.title} can't be deleted"
end
......@@ -60,8 +56,4 @@ class ProductsController < ApplicationController
@product = current_user.products.find_by(id: params[:id])
redirect_to root_url, flash: { alert: 'You do not have permission to edit this product' } if @product.blank?
end
def set_solr
@solr = Solr.new
end
end
\ No newline at end of file
require 'active_support/concern'
module SolrProduct
extend ActiveSupport::Concern
included do
attr_accessor :solr
before_commit { self.solr = Solr.new }
after_create_commit :add_product_to_solr
after_update_commit :update_product_in_solr
after_destroy_commit :delete_product_in_solr
end
def add_product_to_solr
solr.add_product(self)
end
def update_product_in_solr
solr.update_product(self)
end
def delete_product_in_solr
solr.delete_product(self)
end
end
\ No newline at end of file
......@@ -3,6 +3,17 @@ class Order < ApplicationRecord
belongs_to :user
enum order_status: { 'Pending' => 0, 'Done' => 1 }
validates :order_status, presence: true
validate :validate_pending_order, on: :create
def self.default_order_status
'Pending'
end
def validate_pending_order
errors.add(:base, 'Error') if order_status != 'Pending'
end
def total_price
product_items.to_a.sum { |item| item.product.price * item.quantity }
end
......
class Product < ApplicationRecord
include SolrProduct
belongs_to :category
belongs_to :user
......
......@@ -22,8 +22,8 @@ class Solr
end
def update_product(product)
add_product(product)
delete_product(product)
add_product(product)
end
def add_product(product)
......
......@@ -38,6 +38,7 @@
<div class="checkout-review-action">
<h5>Grand Total <span><%= number_to_currency(cart_total_price) %></span></h5>
<%= form_for @order do |f| %>
<%= hidden_field_tag 'order[create_order]' %>
<%= f.submit 'Place Order now', class: 'btn btn-primary' %>
<% end %>
</div>
......
# RSolr
rsolr:
address: http://localhost:8983/solr/dhp_venshop
\ No newline at end of file
require 'rails_helper'
RSpec.describe OrdersController, type: :controller do
let!(:user) { FactoryGirl.create(:user) }
describe '#show' do
before { sign_in user }
def do_request
get :show, params: { id: order.id }
end
context 'as an authorized user' do
let!(:order) { FactoryGirl.create(:order, user: user) }
it 'assigns the requested order to @order' do
do_request
expect(assigns(:order)).to eq order
end
it 'renders the :show template' do
do_request
expect(response).to render_template(:show)
end
end
context 'as an unauthorized user' do
let(:other_user) { FactoryGirl.create(:user) }
let(:order) { FactoryGirl.create(:order, user: other_user) }
it 'redirects to home page' do
do_request
expect(response).to redirect_to(root_url)
end
end
end
describe '#new' do
context 'as an authorized user' do
before { sign_in user }
it 'assigns a new Order to @order' do
get :new
expect(assigns(:order)).to be_a_new(Order)
end
it 'render the :new template' do
get :new
expect(response).to render_template(:new)
end
end
context 'as a guest' do
it 'redirects to the sign-in page' do
get :new
expect(response).to redirect_to(new_user_session_path)
end
end
end
describe '#edit' do
def do_request
get :edit, params: { id: order.id }
end
context 'as an authorized user' do
let(:admin_user) { FactoryGirl.create(:user, admin: true) }
let!(:order) { FactoryGirl.create(:order) }
before { sign_in admin_user }
it 'assigns the requested order to @order' do
do_request
expect(assigns(:order)).to eq order
end
it 'render the :edit template' do
do_request
expect(response).to render_template(:edit)
end
end
context 'as an unauthorized user' do
let(:order) { FactoryGirl.create(:order) }
before { sign_in user }
it 'redirects to home page' do
do_request
expect(response).to redirect_to(root_url)
end
end
end
describe '#create' do
def do_request
get :create, params: { order: order_params }
end
context 'as an authorized user' do
let!(:order) { FactoryGirl.create(:order, user: user) }
before { sign_in user }
context 'with valid attributes' do
let!(:order_params) { FactoryGirl.attributes_for(:order) }
it 'save the new order to database' do
expect { do_request }.to change(Order, :count).by(1)
end
it 'redirect to order details' do
do_request
expect(response).to redirect_to order_url(assigns(:order))
end
end
context 'with invalid attributes' do
let(:order_params) { FactoryGirl.attributes_for(:order, order_status: 'Not valid') }
it 'does not save changes to database' do
expect { do_request }.to raise_error(ArgumentError)
end
end
end
context 'as a guest' do
let(:order_params) { FactoryGirl.attributes_for(:order) }
it 'redirects to home page' do
do_request
expect(response).to redirect_to(new_user_session_path)
end
end
end
describe '#update' do
def do_request
patch :update, params: { id: order.id, order: order_params }
end
context 'as an authorized user' do
let(:admin_user) { FactoryGirl.create(:user, admin: true) }
let!(:order) { FactoryGirl.create(:order) }
before { sign_in admin_user }
context 'with valid attributes' do
let!(:order_params) { FactoryGirl.attributes_for(:order, order_status: 'Done') }
it 'save changes to database' do
do_request
expect(order.reload.order_status).to eq 'Done'
end
end
context 'with invalid attributes' do
let!(:order_params) { FactoryGirl.attributes_for(:order, user_id: nil) }
it 'does not save changes to database' do
do_request
expect(order.reload.order_status).to eq 'Pending'
end
end
end
context 'as an unauthorized user' do
let(:order) { FactoryGirl.create(:order) }
let(:order_params) { FactoryGirl.attributes_for(:order) }
before { sign_in user }
it 'redirects to home page' do
do_request
expect(response).to redirect_to(root_url)
end
end
end
end
require 'rails_helper'
RSpec.describe ProductsController, type: :controller do
let!(:user) { FactoryGirl.create(:user) }
describe '#show' do
let!(:product) { FactoryGirl.create(:product) }
def do_request
get :show, params: { id: product.id }
end
it 'assigns the requested product to @product' do
do_request
expect(assigns(:product)).to eq product
end
it 'renders the :show template' do
do_request
expect(response).to render_template(:show)
end
end
describe '#new' do
context 'as an authorized user' do
before { sign_in user }
it 'assigns a new Product to @product' do
get :new
expect(assigns(:product)).to be_a_new(Product)
end
it 'render the :new template' do
get :new
expect(response).to render_template(:new)
end
end
end
describe '#edit' do
let!(:product) { FactoryGirl.create(:product, user: user) }
def do_request
get :edit, params: { id: product.id }
end
context 'as an authorized user' do
before { sign_in user }
it 'assigns the requested product to @product' do
do_request
expect(assigns(:product)).to eq product
end
it 'render the :edit template' do
do_request
expect(response).to render_template(:edit)
end
end
context 'as a guest' do
it 'redirect to the sign-in page' do
do_request
expect(response).to redirect_to(new_user_session_path)
end
end
end
describe '#create' do
def do_request
post :create, params: { product: product_params }
end
context 'as an authorized user' do
let!(:product) { FactoryGirl.create(:product) }
before { sign_in user }
context 'with valid attributes' do
let(:category) { FactoryGirl.create(:category) }
let!(:product_params) do
FactoryGirl.attributes_for(:product,
user_id: user.id,
category_id: category)
end
it 'save the new product in the database' do
expect { do_request }.to change(Product, :count).by(1)
end
it 'redirects to home page' do
do_request
expect(response).to redirect_to root_url
end
end
context 'with invalid attributes' do
let(:product_params) { FactoryGirl.attributes_for(:product) }
it 'does not save the new product' do
expect { do_request }.to_not change(Product, :count)
end
it 're-renders the :new template' do
do_request
expect(response).to render_template :new
end
end
end
end
describe '#update' do
before do
sign_in user
end
def do_request
patch :update, params: { id: product.id, product: product_params }
end
context 'as an authorized user' do
let!(:product) { FactoryGirl.create(:product, user: user) }
context 'with valid attributes' do
let(:product_params) { FactoryGirl.attributes_for(:product, title: 'New Product Title') }
it 'update changes to database' do
do_request
expect(product.reload.title).to eq 'New Product Title'
end
end
context 'with invalid attributes' do
let(:product_params) { FactoryGirl.attributes_for(:product, category_id: nil) }
it 'does not update changes to database' do
do_request
expect(response).to render_template(:edit)
end
end
end
context 'as an unauthorized user' do
let(:other_user) { FactoryGirl.create(:user) }
let(:product) { FactoryGirl.create(:product, user: other_user) }
let(:product_params) { FactoryGirl.attributes_for(:product) }
it 'redirect to home page' do
do_request
expect(response).to redirect_to(root_url)
end
end
end
end
FactoryGirl.define do
factory :category do
title 'Test Category'
end
end
FactoryGirl.define do
factory :order do
user
order_status 'Pending'
end
end
FactoryGirl.define do
factory :product do
title Faker::Commerce.product_name
sequence(:title) { |n| "Product #{n}" }
description Faker::Lorem.paragraphs
sku "u-#{rand(1..999)}"
sequence(:sku) { |n| "u-#{n}" }
price Faker::Commerce.price
category
user
end
end
\ No newline at end of file
FactoryGirl.define do
factory :user do
sequence(:email) { |n| "user_test#{n}@test.com" }
password 'password'
password_confirmation 'password'
end
end
......@@ -7,6 +7,10 @@ RSpec.describe Order, type: :model do
end
end
context 'validations' do
it { is_expected.to validate_presence_of(:order_status) }
end
context 'associations' do
it { is_expected.to belong_to(:user) }
it { is_expected.to have_many(:product_items) }
......
......@@ -7,11 +7,11 @@ RSpec.describe ProductItem, type: :model do
end
end
describe 'validations' do
context 'validations' do
it { is_expected.to validate_numericality_of(:quantity).is_greater_than(0) }
end
describe 'associations' do
context 'associations' do
it { is_expected.to belong_to(:order) }
it { is_expected.to belong_to(:product) }
end
......
......@@ -6,6 +6,7 @@ require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
require 'devise'
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
......@@ -20,7 +21,7 @@ require 'rspec/rails'
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
# Checks for pending migration and applies them before tests are run.
# If you are not using ActiveRecord, you can remove this line.
......@@ -30,6 +31,9 @@ RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# Devise helpers
config.include Devise::Test::ControllerHelpers, type: :controller
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
......
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment