diff --git a/.gitignore b/.gitignore index 48fb168f..5a111e4e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ # Ignore Byebug command history file. .byebug_history + +.env diff --git a/Gemfile b/Gemfile index c029c6da..ca01ddc7 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ git_source(:github) do |repo_name| end # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 5.0.2' +gem 'rails', '~> 5.1.6' # Use postgresql as the database for Active Record gem 'pg', '~> 0.18' # Use Puma as the app server @@ -40,6 +40,9 @@ gem 'jbuilder', '~> 2.5' gem 'foundation-rails' gem 'autoprefixer-rails' +gem 'omniauth' +gem 'omniauth-github' + group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platform: :mri @@ -49,6 +52,10 @@ group :development, :test do # Use pry for rails console gem 'pry-rails' + + gem 'dotenv-rails' + + gem 'binding_of_caller' end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index f03db854..8b6a73b2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,46 +1,46 @@ GEM remote: https://rubygems.org/ specs: - actioncable (5.0.7) - actionpack (= 5.0.7) - nio4r (>= 1.2, < 3.0) + actioncable (5.1.6) + actionpack (= 5.1.6) + nio4r (~> 2.0) websocket-driver (~> 0.6.1) - actionmailer (5.0.7) - actionpack (= 5.0.7) - actionview (= 5.0.7) - activejob (= 5.0.7) + actionmailer (5.1.6) + actionpack (= 5.1.6) + actionview (= 5.1.6) + activejob (= 5.1.6) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.0.7) - actionview (= 5.0.7) - activesupport (= 5.0.7) + actionpack (5.1.6) + actionview (= 5.1.6) + activesupport (= 5.1.6) rack (~> 2.0) - rack-test (~> 0.6.3) + rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.0.7) - activesupport (= 5.0.7) + actionview (5.1.6) + activesupport (= 5.1.6) builder (~> 3.1) - erubis (~> 2.7.0) + erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.0.7) - activesupport (= 5.0.7) + activejob (5.1.6) + activesupport (= 5.1.6) globalid (>= 0.3.6) - activemodel (5.0.7) - activesupport (= 5.0.7) - activerecord (5.0.7) - activemodel (= 5.0.7) - activesupport (= 5.0.7) - arel (~> 7.0) - activesupport (5.0.7) + activemodel (5.1.6) + activesupport (= 5.1.6) + activerecord (5.1.6) + activemodel (= 5.1.6) + activesupport (= 5.1.6) + arel (~> 8.0) + activesupport (5.1.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) ansi (1.5.0) - arel (7.1.4) - autoprefixer-rails (8.2.0) + arel (8.0.0) + autoprefixer-rails (8.4.1) execjs babel-source (5.8.35) babel-transpiler (0.7.0) @@ -51,6 +51,8 @@ GEM erubi (>= 1.0.0) rack (>= 0.9.0) bindex (0.5.0) + binding_of_caller (0.8.0) + debug_inspector (>= 0.0.1) builder (3.2.3) byebug (10.0.2) coderay (1.1.2) @@ -62,10 +64,16 @@ GEM execjs coffee-script-source (1.12.2) concurrent-ruby (1.0.5) - crass (1.0.3) + crass (1.0.4) + debug_inspector (0.0.3) + dotenv (2.4.0) + dotenv-rails (2.4.0) + dotenv (= 2.4.0) + railties (>= 3.2, < 6.0) erubi (1.7.1) - erubis (2.7.0) execjs (2.7.0) + faraday (0.12.2) + multipart-post (>= 1.2, < 3) ffi (1.9.23) foundation-rails (6.4.3.0) railties (>= 3.1.0) @@ -73,15 +81,17 @@ GEM sprockets-es6 (>= 0.9.0) globalid (0.4.1) activesupport (>= 4.2.0) - i18n (1.0.0) + hashie (3.5.7) + i18n (1.0.1) concurrent-ruby (~> 1.0) jbuilder (2.7.0) activesupport (>= 4.2.0) multi_json (>= 1.2) - jquery-rails (4.3.1) + jquery-rails (4.3.3) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) + jwt (1.5.6) listen (3.0.8) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) @@ -108,39 +118,56 @@ GEM minitest (~> 5.0) rails (>= 4.1) multi_json (1.13.1) + multi_xml (0.6.0) + multipart-post (2.0.0) nio4r (2.3.0) nokogiri (1.8.2) mini_portile2 (~> 2.3.0) + oauth2 (1.4.0) + faraday (>= 0.8, < 0.13) + jwt (~> 1.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (>= 1.2, < 3) + omniauth (1.8.1) + hashie (>= 3.4.6, < 3.6.0) + rack (>= 1.6.2, < 3) + omniauth-github (1.3.0) + omniauth (~> 1.5) + omniauth-oauth2 (>= 1.4.0, < 2.0) + omniauth-oauth2 (1.5.0) + oauth2 (~> 1.1) + omniauth (~> 1.2) pg (0.21.0) pry (0.11.3) coderay (~> 1.1.0) method_source (~> 0.9.0) pry-rails (0.3.6) pry (>= 0.10.4) - puma (3.11.3) - rack (2.0.4) - rack-test (0.6.3) - rack (>= 1.0) - rails (5.0.7) - actioncable (= 5.0.7) - actionmailer (= 5.0.7) - actionpack (= 5.0.7) - actionview (= 5.0.7) - activejob (= 5.0.7) - activemodel (= 5.0.7) - activerecord (= 5.0.7) - activesupport (= 5.0.7) + puma (3.11.4) + rack (2.0.5) + rack-test (1.0.0) + rack (>= 1.0, < 3) + rails (5.1.6) + actioncable (= 5.1.6) + actionmailer (= 5.1.6) + actionpack (= 5.1.6) + actionview (= 5.1.6) + activejob (= 5.1.6) + activemodel (= 5.1.6) + activerecord (= 5.1.6) + activesupport (= 5.1.6) bundler (>= 1.3.0) - railties (= 5.0.7) + railties (= 5.1.6) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.0.4) loofah (~> 2.2, >= 2.2.2) - railties (5.0.7) - actionpack (= 5.0.7) - activesupport (= 5.0.7) + railties (5.1.6) + actionpack (= 5.1.6) + activesupport (= 5.1.6) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) @@ -175,14 +202,14 @@ GEM thor (0.20.0) thread_safe (0.3.6) tilt (2.0.8) - turbolinks (5.1.0) + turbolinks (5.1.1) turbolinks-source (~> 5.1) turbolinks-source (5.1.0) tzinfo (1.2.5) thread_safe (~> 0.1) - uglifier (4.1.8) + uglifier (4.1.10) execjs (>= 0.3.0, < 3) - web-console (3.5.1) + web-console (3.6.2) actionview (>= 5.0) activemodel (>= 5.0) bindex (>= 0.4.0) @@ -197,8 +224,10 @@ PLATFORMS DEPENDENCIES autoprefixer-rails better_errors + binding_of_caller byebug coffee-rails (~> 4.2) + dotenv-rails foundation-rails jbuilder (~> 2.5) jquery-rails @@ -207,10 +236,12 @@ DEPENDENCIES minitest-reporters minitest-skip minitest-spec-rails + omniauth + omniauth-github pg (~> 0.18) pry-rails puma (~> 3.0) - rails (~> 5.0.2) + rails (~> 5.1.6) sass-rails (~> 5.0) spring spring-watcher-listen (~> 2.0.0) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c12c7c17..5fec5316 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,4 +14,12 @@ def find_user @login_user = User.find_by(id: session[:user_id]) end end + + def require_login + if @login_user.nil? + flash[:status] = :failure + flash[:result_text] = "You must be logged in to view this page" + redirect_to root_path + end + end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 5bce99e6..ebda057d 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,34 +1,56 @@ class SessionsController < ApplicationController - def login_form - end + + before_action :require_login, except: [:login] def login - username = params[:username] - if username and user = User.find_by(username: username) - session[:user_id] = user.id - flash[:status] = :success - flash[:result_text] = "Successfully logged in as existing user #{user.username}" - else - user = User.new(username: username) - if user.save - session[:user_id] = user.id - flash[:status] = :success - flash[:result_text] = "Successfully created new user #{user.username} with ID #{user.id}" + auth_hash = request.env['omniauth.auth'] + + if auth_hash[:uid] + @user = User.find_by(uid: auth_hash[:uid], provider: params[:provider]) + + if @user.nil? + + @user = User.get_from_github(auth_hash) + successfull_save = @user.save + + if successfull_save + flash[:status] = :success + flash[:result_text] = "Logged in new user successfully" + session[:user_id] = @user.id + + redirect_to root_path + else + flash.now[:status] = :failure + flash[:result_text] = "Could not log in" + flash.now[:messages] = user.errors.messages + redirect_back fallback_location: auth_callback_path + end + else - flash.now[:status] = :failure - flash.now[:result_text] = "Could not log in" - flash.now[:messages] = user.errors.messages - render "login_form", status: :bad_request - return + session[:user_id] = @user.id + flash[:status] = :success + flash[:result_text] = "Logged in existing user successfully" + redirect_to root_path end + else + flash.now[:status] = :failure + flash[:error] = "Logging in through GitHub not successful" + redirect_back fallback_location: root_path end - redirect_to root_path + end - def logout + def destroy session[:user_id] = nil flash[:status] = :success flash[:result_text] = "Successfully logged out" redirect_to root_path end + + + private + + def user_params + params.require(:user).permit(:name) + end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 73b42652..efdf82c8 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,4 +1,6 @@ class UsersController < ApplicationController + before_action :require_login + def index @users = User.all end diff --git a/app/controllers/works_controller.rb b/app/controllers/works_controller.rb index 2020bee4..aef9a04d 100644 --- a/app/controllers/works_controller.rb +++ b/app/controllers/works_controller.rb @@ -1,6 +1,7 @@ class WorksController < ApplicationController # We should always be able to tell what category # of work we're dealing with + before_action :require_login, except: [:root] before_action :category_from_work, except: [:root, :index, :new, :create] def root @@ -59,6 +60,7 @@ def destroy flash[:status] = :success flash[:result_text] = "Successfully destroyed #{@media_category.singularize} #{@work.id}" redirect_to root_path + end def upvote @@ -72,8 +74,8 @@ def upvote flash[:result_text] = "Could not upvote" flash[:messages] = vote.errors.messages end - else - flash[:result_text] = "You must log in to do that" + # else + # flash[:result_text] = "You must log in to do that" end # Refresh the page to show either the updated vote count @@ -81,7 +83,7 @@ def upvote redirect_back fallback_location: work_path(@work) end -private + private def media_params params.require(:work).permit(:title, :category, :creator, :description, :publication_year) end diff --git a/app/models/user.rb b/app/models/user.rb index 4cac8fe0..936792c6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,4 +3,13 @@ class User < ApplicationRecord has_many :ranked_works, through: :votes, source: :work validates :username, uniqueness: true, presence: true -end + + def self.get_from_github(auth_hash) + return User.new( + provider: auth_hash[:provider], + uid: auth_hash[:uid], + email: auth_hash[:info][:email], + username: auth_hash[:info][:nickname] + ) + end + end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 82ca0fdc..40b2bc8e 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -27,9 +27,9 @@
<% if @login_user %> <%= link_to "Logged in as #{@login_user.username}", user_path(@login_user), class: "button" %> - <%= link_to "Log Out", logout_path, method: :post, class: "button" %> + <%= link_to "Log Out", logout_path, method: :delete, class: "button" %> <% else %> - <%= link_to "Log In", login_path, class: "button" %> + <%= link_to "Log In with Github", '/auth/github', class: "button" %> <% end %>
diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb new file mode 100644 index 00000000..fd441612 --- /dev/null +++ b/config/initializers/omniauth.rb @@ -0,0 +1,3 @@ +Rails.application.config.middleware.use OmniAuth::Builder do + provider :github, ENV["GITHUB_CLIENT_ID"], ENV["GITHUB_CLIENT_SECRET"], scope: "user:email" +end diff --git a/config/routes.rb b/config/routes.rb index a7e8af1d..a282f18a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,12 +1,19 @@ Rails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html root 'works#root' - get '/login', to: 'sessions#login_form', as: 'login' - post '/login', to: 'sessions#login' - post '/logout', to: 'sessions#logout', as: 'logout' + # get '/login', to: 'sessions#login_form', as: 'login' + # # post '/login', to: 'sessions#login' + delete '/logout', to: 'sessions#destroy', as: 'logout' + + # get '/login', to: 'sessions#login_form', as: 'login' + # post '/login', to: 'sessions#login' resources :works post '/works/:id/upvote', to: 'works#upvote', as: 'upvote' resources :users, only: [:index, :show] + + get '/auth/github', as: 'github_login' + get '/auth/:provider/callback', to: 'sessions#login', as: 'auth_callback' + end diff --git a/db/migrate/20180417193808_add_email_provider_uid_to_users.rb b/db/migrate/20180417193808_add_email_provider_uid_to_users.rb new file mode 100644 index 00000000..59026941 --- /dev/null +++ b/db/migrate/20180417193808_add_email_provider_uid_to_users.rb @@ -0,0 +1,7 @@ +class AddEmailProviderUidToUsers < ActiveRecord::Migration[5.0] + def change + add_column :users, :email, :string + add_column :users, :uid, :integer, :null => false + add_column :users, :provider, :string, :null => false + end +end diff --git a/db/schema.rb b/db/schema.rb index 6bc8ba5c..e2bb5819 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170407164321) do +ActiveRecord::Schema.define(version: 20180417193808) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -19,6 +19,9 @@ t.string "username" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "email" + t.integer "uid", null: false + t.string "provider", null: false end create_table "votes", force: :cascade do |t| diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb index f641d15c..e52447f3 100644 --- a/test/controllers/sessions_controller_test.rb +++ b/test/controllers/sessions_controller_test.rb @@ -2,4 +2,72 @@ describe SessionsController do + before do + @existing_user = users(:dan) + + end + describe "login" do + + it 'login an existing user and redirect to root page' do + old_user_count = User.count + + login(@existing_user) + + must_redirect_to root_path + User.count.must_equal old_user_count + session[:user_id].must_equal @existing_user.id + end + + it 'creates a new user if given valid data and redirect to root page' do + new_user = User.new( + provider: "github", + uid: 900, + email: "test@adadevelopersacademy.org", + username: "test name" + ) + + new_user.must_be :valid? + old_user_count = User.count + + login(new_user) + + User.count.must_equal old_user_count + 1 + must_redirect_to root_path + session[:user_id].must_equal User.last.id + flash[:status].must_equal :success + flash[:result_text].must_equal "Logged in new user successfully" + end + + it 'does not create a new user if bogus data given and redirect to root page' do + new_user = User.new( + provider: "github", + email: "dada@test.org", + username: "coco" + ) + + old_user_count = User.count + + login(new_user) + flash[:error].must_equal "Logging in through GitHub not successful" + User.count.must_equal old_user_count + must_redirect_to root_path + end + + end + + describe "logout" do + + it 'should log out the user and redirect to root page' do + user = User.first + login(user) + + logout(user) + + session[:user_id].must_equal nil + flash[:result_text].must_equal "Successfully logged out" + must_respond_with :redirect + must_redirect_to root_path + end + + end end diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb index d2c5cfbb..1fe3b355 100644 --- a/test/controllers/users_controller_test.rb +++ b/test/controllers/users_controller_test.rb @@ -1,5 +1,63 @@ require 'test_helper' describe UsersController do + before do + @user = users(:dan) + end + describe 'index' do + it 'succeeds for logged in users' do + login(@user) + + get users_path + must_respond_with :success + end + + it 'cannot access index for guest users' do + get users_path + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + end + + describe 'show' do + + it 'succeeds for logged in user with an extant ID' do + login(@user) + + get user_path(users(:dan).id) + + must_respond_with :success + end + + it "renders 404 not_found for a bogus user ID" do + login(@user) + + get user_path("baa") + + must_respond_with :not_found + end + + it 'cannot access show page for a guest user with extant ID' do + get user_path(users(:dan).id) + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + + it 'cannot access show page for guest user with a bogus user ID' do + get user_path(users(:dan).id) + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + + + end end diff --git a/test/controllers/works_controller_test.rb b/test/controllers/works_controller_test.rb index 0945ca47..84f18e78 100644 --- a/test/controllers/works_controller_test.rb +++ b/test/controllers/works_controller_test.rb @@ -1,116 +1,564 @@ require 'test_helper' describe WorksController do - describe "root" do - it "succeeds with all media types" do - # Precondition: there is at least one media of each category + describe 'Logged in Users' do + + before do + @user = users(:kari) end - it "succeeds with one media type absent" do - # Precondition: there is at least one media in two of the categories + describe "root" do + it "succeeds with all media types" do + login(@user) + get root_path - end + must_respond_with :success + end - it "succeeds with no media" do + it "succeeds with one media type absent" do + # Precondition: there is at least one media in two of the categories + Work.where(category: "book").destroy_all - end - end + # Assumptions + Work.where(category: "album").count.must_be :>, 0 + Work.where(category: "movie").count.must_be :>, 0 + Work.where(category: "book").must_be_empty - CATEGORIES = %w(albums books movies) - INVALID_CATEGORIES = ["nope", "42", "", " ", "albumstrailingtext"] + login(@user) + get root_path - describe "index" do - it "succeeds when there are works" do + Work.all.where(category: "book").count.must_equal 0 + must_respond_with :success - end + end - it "succeeds when there are no works" do + it "succeeds with no media" do + Work.where(category: "book").destroy_all + Work.where(category: "album").destroy_all + Work.where(category: "movie").destroy_all - end - end + # Assumptions + Work.where(category: "album").must_be_empty + Work.where(category: "movie").must_be_empty + Work.where(category: "book").must_be_empty - describe "new" do - it "succeeds" do + login(@user) + get root_path + must_respond_with :success + + end end - end - describe "create" do - it "creates a work with valid data for a real category" do + CATEGORIES = %w(albums books movies) + INVALID_CATEGORIES = ["nope", "42", "", " ", "albumstrailingtext"] - end + describe "index" do + it "succeeds when there are works" do + login(@user) + get works_path + must_respond_with :success + end - it "renders bad_request and does not update the DB for bogus data" do + it "succeeds when there are no works" do + Work.destroy_all + Work.count.must_equal 0 + login(@user) + get works_path + must_respond_with :success + end end - it "renders 400 bad_request for bogus categories" do - + describe "new" do + it "succeeds" do + login(@user) + get new_work_path + must_respond_with :success + end end - end + describe "create" do + it "creates a work with valid data for a real category" do + login(@user) + work_data = { + category: CATEGORIES.sample, + title: "testing title " + } - describe "show" do - it "succeeds for an extant work ID" do + Work.new(work_data).must_be :valid? - end + old_count = Work.count - it "renders 404 not_found for a bogus work ID" do + post works_path, params: { work: work_data } - end - end + must_respond_with :redirect + Work.count.must_equal old_count + 1 + end - describe "edit" do - it "succeeds for an extant work ID" do + it "renders bad_request and does not update the DB for bogus data" do + login(@user) + work_data = { + category: CATEGORIES.sample, + title: "" + } - end - it "renders 404 not_found for a bogus work ID" do + Work.new(work_data).wont_be :valid? + old_count = Work.count - end - end + post works_path, params: { work: work_data } - describe "update" do - it "succeeds for valid data and an extant work ID" do + must_respond_with :bad_request + Work.count.must_equal old_count + end - end - it "renders bad_request for bogus data" do - end + it "renders 400 bad_request for bogus categories" do + login(@user) + work_data = { + category: INVALID_CATEGORIES.sample, + title: "testing title", + } + old_count = Work.count + + + Work.new(work_data).wont_be :valid? + + post works_path, params: { work: work_data } - it "renders 404 not_found for a bogus work ID" do + must_respond_with :bad_request + Work.count.must_equal old_count + end end - end - describe "destroy" do - it "succeeds for an extant work ID" do + describe "show" do + it "succeeds for an extant work ID" do + login(@user) + + work_id = Work.first.id + + get work_path(work_id) + + must_respond_with :success + end + it "renders 404 not_found for a bogus work ID" do + login(@user) + + work_id = Work.last.id + 1 + + get work_path(work_id) + + must_respond_with :not_found + end end - it "renders 404 not_found and does not update the DB for a bogus work ID" do + describe "edit" do + it "succeeds for an extant work ID" do + login(@user) + + work_id = Work.first.id + get edit_work_path(work_id) + + must_respond_with :success + + end + + it "renders 404 not_found for a bogus work ID" do + login(@user) + + work_id = Work.last.id + 1 + get edit_work_path(work_id) + + must_respond_with :not_found + + end end - end - describe "upvote" do + describe "update" do + it "succeeds for valid data and an extant work ID" do + login(@user) + + work = Work.first + work_data = { + category: CATEGORIES.sample, + title: "title edited", + } + + work.assign_attributes(work_data) + work.must_be :valid? + + # act + patch work_path(work), params: {work: work_data} + + # assert + must_respond_with :redirect + + work.reload + work.title.must_equal work_data[:title] + + end - it "redirects to the work page if no user is logged in" do + it "renders not_found for bogus data" do + login(@user) + work = Work.first + work_data = { + title: "", + category: CATEGORIES.sample + } + + # Assumptions + work.assign_attributes(work_data) + work.valid?.must_equal false + + patch work_path(work), params: { work: work_data } + + must_respond_with :not_found + work.reload + work.title.wont_equal work_data[:title] + end + + it "renders 404 not_found for a bogus work ID" do + login(@user) + + work_id = Work.last.id + 1 + + patch work_path(work_id) + + must_respond_with :not_found + end end - it "redirects to the work page after the user has logged out" do + describe "destroy" do + it "succeeds for an extant work ID" do + #arrange + login(@user) + work_id = Work.first.id + old_work_count = Work.count + + #act + delete work_path(work_id) + + #assert + must_respond_with :redirect + must_redirect_to root_path + + Work.count.must_equal old_work_count - 1 + Work.find_by(id: work_id).must_be_nil + end + + it "renders 404 not_found and does not update the DB for a bogus work ID" do + login(@user) + work_id = Work.last.id + 1 + old_work_count = Work.count + + delete work_path(work_id) + + must_respond_with :not_found + Work.count.must_equal old_work_count + end end - it "succeeds for a logged-in user and a fresh user-vote pair" do + describe "upvote" do + + it "redirects to the work page after the user has logged out" do + last_work = Work.last + post upvote_path(last_work) + + logout(@user) + must_respond_with :redirect + flash[:result_text] = "Successfully logged out" + + end + + it "succeeds for a logged-in user and a fresh user-vote pair" do + login(@user) + work = Work.first + old_count = work.votes.count + + post upvote_path(work) + must_respond_with :redirect + must_redirect_to work_path(work) + work.reload + work.votes.count.must_equal old_count + 1 + end + + it "redirects to the work page if the user has already voted for that work" do + login(@user) + user = User.find_by(username: "dan") + work = user.votes.first.work + vote_count = work.votes.count + + + post upvote_path(work) + + must_respond_with :redirect + must_redirect_to work_path(work) + work.reload + work.votes.count.must_equal vote_count + + end end - it "redirects to the work page if the user has already voted for that work" do + describe "Guest Users" do + + describe "root" do + it "succeeds with all media types" do + + get root_path + + must_respond_with :success + end + + + + it "succeeds with one media type absent" do + # Precondition: there is at least one media in two of the categories + Work.where(category: "book").destroy_all + + # Assumptions + Work.where(category: "album").count.must_be :>, 0 + Work.where(category: "movie").count.must_be :>, 0 + Work.where(category: "book").must_be_empty + + + get root_path + + Work.all.where(category: "book").count.must_equal 0 + must_respond_with :success + + end + + it "succeeds with no media" do + Work.where(category: "book").destroy_all + Work.where(category: "album").destroy_all + Work.where(category: "movie").destroy_all + + # Assumptions + Work.where(category: "album").must_be_empty + Work.where(category: "movie").must_be_empty + Work.where(category: "book").must_be_empty + + + get root_path + + must_respond_with :success + + end + end + + describe "index" do + it "cannot access index page" do + + get works_path + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + + end + + describe "new" do + it "cannot access to new" do + + get new_work_path + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + end + + describe "create" do + it "cannot access create" do + + work_data = { + category: CATEGORIES.sample, + title: "testing title " + } + + Work.new(work_data).must_be :valid? + + old_count = Work.count + + post works_path, params: { work: work_data } + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + + end + end + + describe "show" do + it "cannot access show for an extant work ID" do + get work_path(works(:album).id) + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + + it "cannot access show for a bogus work ID" do + get work_path("baa") + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + end + + describe "edit" do + it "cannot access edit for an extant work ID" do + get edit_work_path(works(:album).id) + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + + it "cannot access edit for a bogus work ID" do + get edit_work_path("baa") + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + end + + describe "update" do + it "cannot access update for valid data and extant work ID" do + + work = Work.first + work_data = { + category: CATEGORIES.sample, + title: "title edited", + } + + work.assign_attributes(work_data) + work.must_be :valid? + + # act + patch work_path(work), params: {work: work_data} + + # assert + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + + end + + it "cannot access update for bogus data" do + + work = Work.first + work_data = { + title: "", + category: CATEGORIES.sample + } + + # Assumptions + work.assign_attributes(work_data) + work.valid?.must_equal false + + patch work_path(work), params: { work: work_data } + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + + it "cannot access update for bogus work ID" do + + + work_id = Work.last.id + 1 + + patch work_path("work_id") + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + + end + + describe "destroy" do + it "cannot access destroy for an extant work ID" do + #arrange + + work_id = Work.first.id + old_work_count = Work.count + + #act + delete work_path(work_id) + + #assert + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + + it "cannot access destroy for a bogus work ID" do + + work_id = Work.last.id + 1 + old_work_count = Work.count + + delete work_path(work_id) + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + end + + describe "upvote" do + + it "redirects to the work page if no user is logged in" do + + work = Work.first + post upvote_path(work) + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + end + + it "redirects to the work page after the user has logged out" do + + work = Work.first + old_count = work.votes.count + + + post upvote_path(work) + + flash[:status].must_equal :failure + flash[:result_text].must_equal "You must be logged in to view this page" + must_respond_with :redirect + must_redirect_to root_path + + end + end end + end + end diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index e2968d78..49393467 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -1,7 +1,13 @@ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html dan: + provider: github + uid: 12345 + email: dan@adadevelopersacademy.org username: dan kari: + provider: github + uid: 6789 + email: kari@adadevelopersacademy.org username: kari diff --git a/test/test_helper.rb b/test/test_helper.rb index 5b4fb667..9f5b33b0 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,4 +1,5 @@ ENV["RAILS_ENV"] = "test" + require File.expand_path("../../config/environment", __FILE__) require "rails/test_help" require "minitest/rails" @@ -23,4 +24,33 @@ class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all # Add more helper methods to be used by all tests here... + def setup + # Once you have enabled test mode, all requests + # to OmniAuth will be short circuited to use the mock authentication hash. + # A request to /auth/provider will redirect immediately to /auth/provider/callback. + OmniAuth.config.test_mode = true + end + + def mock_auth_hash(user) + return { + provider: user.provider, + uid: user.uid, + info: { + email: user.email, + nickname: user.username + } + } + end + + def login(user) + OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new(mock_auth_hash(user)) + + get auth_callback_path(:github) + end + + def logout(user) + OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new(mock_auth_hash(user)) + delete logout_path + end + end