- <%= quiz.check_box( checked: user.quizzes.include?(quiz.object)) %>
- <%= quiz.label %>
-
- <% end %>
+
Oops!
diff --git a/app/views/candidate/saved.html.erb b/app/views/candidate/saved.html.erb
index bd7dda0..e7f09eb 100644
--- a/app/views/candidate/saved.html.erb
+++ b/app/views/candidate/saved.html.erb
@@ -1,3 +1,4 @@
+<% content_for :title, "Saved! - Skills Assessment" %>
Your test results have been saved. You can visit again later with your Test ID to complete
diff --git a/app/views/candidate/thankyou.html.erb b/app/views/candidate/thankyou.html.erb
index b796e52..e2df7e2 100644
--- a/app/views/candidate/thankyou.html.erb
+++ b/app/views/candidate/thankyou.html.erb
@@ -1,3 +1,4 @@
+<% content_for :title, "Thank You - Skills Assessment" %>
Thank you!
diff --git a/app/views/quiz/_live_code.html.erb b/app/views/quiz/_live_code.html.erb
index 91814dd..cce5495 100644
--- a/app/views/quiz/_live_code.html.erb
+++ b/app/views/quiz/_live_code.html.erb
@@ -45,6 +45,17 @@
+
+
+
How to use the live coder
+
+ This is our own nifty creation, and it works similarly to CodePen. To use: type any HTML, CSS,
+ or JS inside their corresponding boxes, and watch the Results window below the boxes update
+ with your changes. Once you’re happy with your code and how it renders in the Results window,
+ move on to the next question!
+
+
+
Enter answer here
<%= text_area_tag 'answer[answer_hash][text]', value_text, { disabled: true, data: {last: answers['text']}} %>
@@ -64,6 +75,7 @@
<%= text_area_tag 'answer[answer_hash][js]', value_js, { disabled: true, data: {id: 'code-js', last: answers['js']}, class: 'code-answer code-js' } %>
+ Results
@@ -71,6 +83,7 @@
<% # removes the no-js message %>
document.getElementById("nojs<%= question.question_id %>").style.display = "none";
document.getElementById("answer<%= question.question_id %>").style.display = "";
+ document.getElementById("accordion<%= question.question_id %>").style.display = "";
<% # we want the coders disabled until JS is confirmed, so form post is easier to validate %>
var coders = document.querySelectorAll("[data-id=live-coder-answer] textarea");
diff --git a/app/views/quiz/summary.html.erb b/app/views/quiz/summary.html.erb
index cf0bab9..1491bd9 100644
--- a/app/views/quiz/summary.html.erb
+++ b/app/views/quiz/summary.html.erb
@@ -1,5 +1,5 @@
<%
- content_for :title, "Skills Assessment"
+ content_for :title, "Summary - Skills Assessment"
content_for :footer_title, "Skills Assessment"
content_for :progress, @status.progress.to_s
content_for_javascript_once 'summary-edit' do
diff --git a/config/routes.rb b/config/routes.rb
index c5356dd..691f4c5 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -50,6 +50,11 @@ Rails.application.routes.draw do
get "/admin/results", to: "admin/result#index", as: :admin_results
get "/admin/result/:test_hash", to: "admin/result#view", as: :admin_result
+ get "admin/vote/:test_hash/up", to: "admin/vote#up", as: :admin_up_vote
+ get "admin/vote/:test_hash/down", to: "admin/vote#down", as: :admin_down_vote
+ get "admin/vote/:test_hash/approve", to: "admin/vote#approve", as: :admin_approve_vote
+ get "admin/vote/:test_hash/decline", to: "admin/vote#decline", as: :admin_decline_vote
+
get "/admin", to: "admin/dashboard#show", as: :admin
#########################################################################################
diff --git a/db/migrate/20161118023249_candidate_review_system.rb b/db/migrate/20161118023249_candidate_review_system.rb
new file mode 100644
index 0000000..0c4c8b0
--- /dev/null
+++ b/db/migrate/20161118023249_candidate_review_system.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+class CandidateReviewSystem < ActiveRecord::Migration[5.0]
+ def change
+ create_table :reviewer_votes do |t|
+ t.integer :candidate_id
+ t.integer :user_id
+ t.integer :vote, default: 0, null: false
+ t.integer :veto, default: 0, null: false
+ t.datetime :last_reminded
+ t.boolean :locked, default: false, null: false
+
+ t.timestamps
+ end
+ add_index :reviewer_votes, [:candidate_id, :user_id], unique: true
+
+ add_column :candidates, :review_status, :integer, default: 0, null: false
+ end
+end
diff --git a/db/migrate/20161120175737_init_reviewer_votes.rb b/db/migrate/20161120175737_init_reviewer_votes.rb
new file mode 100644
index 0000000..706c8af
--- /dev/null
+++ b/db/migrate/20161120175737_init_reviewer_votes.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+class InitReviewerVotes < ActiveRecord::Migration[5.0]
+ def up
+ Candidate.where(completed: true).each(&:build_reviews)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 41a294d..2126b30 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: 20160915164450) do
+ActiveRecord::Schema.define(version: 20161120175737) do
create_table "answers", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.integer "candidate_id"
@@ -33,9 +33,10 @@ ActiveRecord::Schema.define(version: 20160915164450) do
t.integer "recruiter_id"
t.boolean "completed"
t.boolean "reminded"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "quiz_id"
+ t.integer "review_status", default: 0, null: false
t.index ["quiz_id"], name: "index_candidates_on_quiz_id", using: :btree
t.index ["recruiter_id"], name: "index_candidates_on_recruiter_id", using: :btree
t.index ["test_hash"], name: "index_candidates_on_test_hash", unique: true, using: :btree
@@ -73,6 +74,18 @@ ActiveRecord::Schema.define(version: 20160915164450) do
t.index ["quiz_id"], name: "index_reviewer_to_quizzes_on_quiz_id", using: :btree
end
+ create_table "reviewer_votes", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
+ t.integer "candidate_id"
+ t.integer "user_id"
+ t.integer "vote", default: 0, null: false
+ t.integer "veto", default: 0, null: false
+ t.datetime "last_reminded"
+ t.boolean "locked", default: false, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["candidate_id", "user_id"], name: "index_reviewer_votes_on_candidate_id_and_user_id", unique: true, using: :btree
+ end
+
create_table "users", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "name"
t.string "email"
diff --git a/erd.pdf b/erd.pdf
index 1d050f2..35d725d 100644
Binary files a/erd.pdf and b/erd.pdf differ
diff --git a/test/controllers/admin/question_controller_test.rb b/test/controllers/admin/question_controller_test.rb
index 767eada..71212b0 100644
--- a/test/controllers/admin/question_controller_test.rb
+++ b/test/controllers/admin/question_controller_test.rb
@@ -67,6 +67,18 @@ module Admin
assert_select 'p', 'foo bar baz'
end
+ test "should post attachment" do
+ question = questions(:fed1)
+ post admin_update_question_url(question.to_i), params: { question:
+ { quiz_id: quizzes(:fed).to_i, attachment: 'https://dev.perficientdigital.com/logo.png' } }
+ assert_redirected_to admin_question_path(question.to_i)
+
+ get admin_question_path question.to_i
+ assert_select 'img' do
+ assert_select "[src=?]", "https://dev.perficientdigital.com/logo.png"
+ end
+ end
+
test "should fail to update question" do
question = questions(:fed9)
post admin_update_question_url(question.to_i), params: { question: { question: nil } }
diff --git a/test/controllers/admin/result_controller_test.rb b/test/controllers/admin/result_controller_test.rb
index 699517d..eb9ac57 100644
--- a/test/controllers/admin/result_controller_test.rb
+++ b/test/controllers/admin/result_controller_test.rb
@@ -19,5 +19,19 @@ module Admin
assert assigns(:quiz), "@quiz not present"
assert assigns(:status), "@status not present"
end
+
+ test "reviewer can view result for henry" do
+ auth_reviewer
+
+ get admin_result_url(candidates(:henry).test_hash)
+ assert_response :success
+ end
+
+ test "recruiter can view result for henry" do
+ auth_user users(:recruiter)
+
+ get admin_result_url(candidates(:henry).test_hash)
+ assert_response :success
+ end
end
end
diff --git a/test/controllers/admin/user_controller_test.rb b/test/controllers/admin/user_controller_test.rb
index 8498ffc..be8c9a9 100644
--- a/test/controllers/admin/user_controller_test.rb
+++ b/test/controllers/admin/user_controller_test.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: true
+# frozen_string_literal: true()
require 'test_helper'
module Admin
diff --git a/test/controllers/admin/vote_controller_test.rb b/test/controllers/admin/vote_controller_test.rb
new file mode 100644
index 0000000..f05e4e2
--- /dev/null
+++ b/test/controllers/admin/vote_controller_test.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+require 'test_helper'
+
+module Admin
+ class VoteControllerTest < ActionDispatch::IntegrationTest
+ test "reviewer can up vote henry" do
+ auth_user users(:reviewer)
+ henry = candidates(:henry)
+
+ assert_difference("Candidate.find(#{henry.id}).votes.yea.count", 1) do
+ get admin_up_vote_url(henry.test_hash)
+ end
+ assert_response :success
+ end
+
+ test "reviewer can down vote henry" do
+ auth_user users(:reviewer)
+ henry = candidates(:henry)
+
+ assert_difference("Candidate.find(#{henry.id}).votes.nay.count", 1) do
+ get admin_down_vote_url(henry.test_hash)
+ end
+ assert_response :success
+ end
+
+ test "reviewer can change vote on henry" do
+ auth_user users(:reviewer)
+ henry = candidates(:henry)
+ get admin_up_vote_url(henry.test_hash)
+
+ assert_difference("Candidate.find(#{henry.id}).votes.yea.count", -1) do
+ assert_difference("Candidate.find(#{henry.id}).votes.nay.count", 1) do
+ get admin_down_vote_url(henry.test_hash)
+ end
+ end
+ assert_response :success
+ end
+
+ test "manager can approve henry" do
+ auth_user users(:manager)
+ henry = candidates(:henry)
+ get admin_approve_vote_url(henry.test_hash)
+
+ assert_equal 1, henry.votes.approved.count
+ assert_equal 'approved', Candidate.find(henry.to_i).review_status
+ assert_response :success
+ end
+
+ test "manager can decline henry" do
+ auth_user users(:manager)
+ henry = candidates(:henry)
+ get admin_decline_vote_url(henry.test_hash)
+
+ assert_equal 1, henry.votes.rejected.count
+ assert_equal 'declined', Candidate.find(henry.to_i).review_status
+ assert_response :success
+ end
+ end
+end
diff --git a/test/fixtures/answers.yml b/test/fixtures/answers.yml
index 9c3455a..de70e0c 100644
--- a/test/fixtures/answers.yml
+++ b/test/fixtures/answers.yml
@@ -404,3 +404,295 @@ juan10:
created_at: <%= DateTime.now() - 38.hours - 40.minutes %>
updated_at: <%= DateTime.now() - 38.hours - 20.minutes %>
+stacy1:
+ candidate: stacy
+ question: Cras justo odio, dapibus ac facilisis in, egestas eget quam. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit.
+ answer: option 3
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 22.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 22.minutes %>
+
+stacy2:
+ candidate: stacy
+ question: fed2
+ answer: 'indexOf()'
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 24.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 4.minutes %>
+
+stacy3:
+ candidate: stacy
+ question: fed3
+ answer: {html: 'Salmon ', css: 'h1 {color: salmon;}', js: '', text: 'Gotta lotta GOOD things on sale, strangah.'}
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 26.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 6.minutes %>
+
+stacy4:
+ candidate: stacy
+ question: fed4
+ answer: Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 28.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 28.minutes %>
+
+stacy5:
+ candidate: stacy
+ question: fed5
+ answer: 'Dynamic listeners'
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 30.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 30.minutes %>
+
+stacy6:
+ candidate: stacy
+ question: fed6
+ answer: Integer posuere erat a ante venenatis dapibus posuere velit aliquet.
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 32.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 12.minutes %>
+
+stacy7:
+ candidate: stacy
+ question: fed7
+ answer: {html: 'This means jQuery needs to be available in live-coder!
', css: "strong {font-size: 1.6em;}\n.green {color: green;}", js: '$("strong").addClass("green");'}
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 34.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 14.minutes %>
+
+stacy8:
+ candidate: stacy
+ question: fed8
+ answer:
+ other: Some generic user input
+ options:
+ - other
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 36.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 16.minutes %>
+
+stacy9:
+ candidate: stacy
+ question: fed9
+ answer:
+ other: Brunch
+ options:
+ - Neither
+ - other
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 38.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 18.minutes %>
+
+stacy10:
+ candidate: stacy
+ question: fed10
+ answer: ["Live long and prosper", "Who you calling Scruffy?"]
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 40.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 20.minutes %>
+
+
+henry1:
+ candidate: henry
+ question: Cras justo odio, dapibus ac facilisis in, egestas eget quam. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit.
+ answer: option 3
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 22.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 22.minutes %>
+
+henry2:
+ candidate: henry
+ question: fed2
+ answer: 'indexOf()'
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 24.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 4.minutes %>
+
+henry3:
+ candidate: henry
+ question: fed3
+ answer: {html: 'Salmon ', css: 'h1 {color: salmon;}', js: '', text: 'Gotta lotta GOOD things on sale, strangah.'}
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 26.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 6.minutes %>
+
+henry4:
+ candidate: henry
+ question: fed4
+ answer: Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 28.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 28.minutes %>
+
+henry5:
+ candidate: henry
+ question: fed5
+ answer: 'Dynamic listeners'
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 30.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 30.minutes %>
+
+henry6:
+ candidate: henry
+ question: fed6
+ answer: Integer posuere erat a ante venenatis dapibus posuere velit aliquet.
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 32.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 12.minutes %>
+
+henry7:
+ candidate: henry
+ question: fed7
+ answer: {html: 'This means jQuery needs to be available in live-coder!
', css: "strong {font-size: 1.6em;}\n.green {color: green;}", js: '$("strong").addClass("green");'}
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 34.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 14.minutes %>
+
+henry8:
+ candidate: henry
+ question: fed8
+ answer:
+ other: Some generic user input
+ options:
+ - other
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 36.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 16.minutes %>
+
+henry9:
+ candidate: henry
+ question: fed9
+ answer:
+ other: Brunch
+ options:
+ - Neither
+ - other
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 38.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 18.minutes %>
+
+henry10:
+ candidate: henry
+ question: fed10
+ answer: ["Live long and prosper", "Who you calling Scruffy?"]
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 40.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 20.minutes %>
+
+wade1:
+ candidate: wade
+ question: Cras justo odio, dapibus ac facilisis in, egestas eget quam. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit.
+ answer: option 3
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 22.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 22.minutes %>
+
+wade2:
+ candidate: wade
+ question: fed2
+ answer: 'indexOf()'
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 24.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 4.minutes %>
+
+wade3:
+ candidate: wade
+ question: fed3
+ answer: {html: 'Salmon ', css: 'h1 {color: salmon;}', js: '', text: 'Gotta lotta GOOD things on sale, strangah.'}
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 26.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 6.minutes %>
+
+wade4:
+ candidate: wade
+ question: fed4
+ answer: Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 28.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 28.minutes %>
+
+wade5:
+ candidate: wade
+ question: fed5
+ answer: 'Dynamic listeners'
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 30.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 30.minutes %>
+
+wade6:
+ candidate: wade
+ question: fed6
+ answer: Integer posuere erat a ante venenatis dapibus posuere velit aliquet.
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 32.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 12.minutes %>
+
+wade7:
+ candidate: wade
+ question: fed7
+ answer: {html: 'This means jQuery needs to be available in live-coder!
', css: "strong {font-size: 1.6em;}\n.green {color: green;}", js: '$("strong").addClass("green");'}
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 34.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 14.minutes %>
+
+wade8:
+ candidate: wade
+ question: fed8
+ answer:
+ other: Some generic user input
+ options:
+ - other
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 36.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 16.minutes %>
+
+wade9:
+ candidate: wade
+ question: fed9
+ answer:
+ other: Brunch
+ options:
+ - Neither
+ - other
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 38.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 18.minutes %>
+
+wade10:
+ candidate: wade
+ question: fed10
+ answer: ["Live long and prosper", "Who you calling Scruffy?"]
+ saved: 0
+ submitted: true
+ created_at: <%= DateTime.now() - 36.hours - 40.minutes %>
+ updated_at: <%= DateTime.now() - 36.hours - 20.minutes %>
+
diff --git a/test/fixtures/candidates.yml b/test/fixtures/candidates.yml
index c55d18f..4def21b 100644
--- a/test/fixtures/candidates.yml
+++ b/test/fixtures/candidates.yml
@@ -59,6 +59,7 @@ richard: # Richard has completed AND submitted the test
completed: true
reminded: false
test_hash: 6NjnourLE6Y
+ review_status: 1
juan: # Juan has chosen "finish later" for live coders
name: Juan Campbell
@@ -68,4 +69,46 @@ juan: # Juan has chosen "finish later" for live coders
quiz: fed
completed: false
reminded: true
- test_hash: <%= CryptSerializer.dump 'qKQo0l4dyol
+ test_hash: qKQo0l4dyol
+
+stacy: # Stacy has completed AND submitted the test
+ name: Stacy Scott
+ email: <%= CryptSerializer.dump 'stacy.scott@mailinator.com' %>
+ experience: 7-9
+ recruiter: recruiter
+ quiz: fed
+ completed: true
+ reminded: false
+ test_hash: s6oFExZliYYFx
+ review_status: 2
+
+henry: # Henry has completed AND submitted the test
+ name: Henry Butler
+ email: <%= CryptSerializer.dump 'henry.butler@mailinator.com' %>
+ experience: 4-6
+ recruiter: recruiter
+ quiz: fed
+ completed: true
+ reminded: false
+ test_hash: egPomAuVDeCEp
+
+wade: # Wade has completed AND submitted the test
+ name: Wade Armstrong
+ email: <%= CryptSerializer.dump 'wade.armstrong@mailinator.com' %>
+ experience: 0-3
+ recruiter: recruiter
+ quiz: fed
+ completed: true
+ reminded: false
+ test_hash: BkSkpapJnkz2N
+
+gustov: # Gustov is NOT for FED
+ name: Gustov
+ email: <%= CryptSerializer.dump 'gustov@mailinator.com' %>
+ experience: 0-3
+ recruiter: recruiter
+ quiz: admin
+ completed: false
+ reminded: false
+ test_hash: kp6tfghjyapJnkz2N
+
diff --git a/test/fixtures/questions.yml b/test/fixtures/questions.yml
index 97c7d00..4380750 100644
--- a/test/fixtures/questions.yml
+++ b/test/fixtures/questions.yml
@@ -55,7 +55,7 @@ fed5:
fed6:
quiz: fed
question: Comment on how realistic the following image is.
- attachment: "http://dev.perficientxd.com/skill_assets/commets_css.jpg"
+ attachment: "https://dev.perficientdigital.com/skills-app-images/commets_css.jpg"
category: CSS
input_type: text
input_options:
diff --git a/test/fixtures/reviewer_to_quizzes.yml b/test/fixtures/reviewer_to_quizzes.yml
index 4e8812f..cb91027 100644
--- a/test/fixtures/reviewer_to_quizzes.yml
+++ b/test/fixtures/reviewer_to_quizzes.yml
@@ -7,3 +7,7 @@ one:
two:
user: reviewer2
quiz: fed
+
+three:
+ user: manager
+ quiz: fed
diff --git a/test/fixtures/reviewer_votes.yml b/test/fixtures/reviewer_votes.yml
new file mode 100644
index 0000000..2669604
--- /dev/null
+++ b/test/fixtures/reviewer_votes.yml
@@ -0,0 +1,68 @@
+gustov:
+ candidate: gustov
+ user_id: 12341234
+
+
+manager_richard:
+ candidate: richard
+ user: manager
+ vote: 1
+
+reviewer_richard:
+ candidate: richard
+ user: reviewer
+ vote: 1
+
+reviewer2_richard:
+ candidate: richard
+ user: reviewer2
+ vote: 1
+
+
+
+manager_stacy:
+ candidate: stacy
+ user: manager
+ vote: 2
+
+reviewer_stacy:
+ candidate: stacy
+ user: reviewer
+ vote: 2
+
+reviewer2_stacy:
+ candidate: stacy
+ user: reviewer2
+ vote: 2
+
+
+manager_henry:
+ candidate: henry
+ user: manager
+ vote: 0
+ veto: 2
+
+reviewer_henry:
+ candidate: henry
+ user: reviewer
+
+reviewer2_henry:
+ candidate: henry
+ user: reviewer2
+
+
+manager_wade:
+ candidate: wade
+ user: manager
+ vote: 2
+ veto: 2
+
+reviewer_wade:
+ candidate: wade
+ user: reviewer
+ vote: 2
+
+reviewer2_wade:
+ candidate: wade
+ user: reviewer2
+
diff --git a/test/mailers/reviewer_mailer_test.rb b/test/mailers/reviewer_mailer_test.rb
index 6241752..35673eb 100644
--- a/test/mailers/reviewer_mailer_test.rb
+++ b/test/mailers/reviewer_mailer_test.rb
@@ -6,6 +6,7 @@ class ReviewerMailerTest < ActionMailer::TestCase
candidate = candidates :dawn
mail = ReviewerMailer.candidate_submission candidate
assert_match "Results", mail.subject
+ assert_match candidate.test_hash, mail.subject
assert_equal candidate.quiz.reviewers.map(&:email), mail.to
assert_equal [ENV["default_mail_from"]], mail.from
assert_match candidate.test_hash, mail.body.encoded
diff --git a/test/models/candidate_test.rb b/test/models/candidate_test.rb
index 7cb0f5d..393c7e8 100644
--- a/test/models/candidate_test.rb
+++ b/test/models/candidate_test.rb
@@ -24,4 +24,11 @@ class CandidateTest < ActiveSupport::TestCase
refute_equal email, enc_email
end
+
+ test "can build reviewer records" do
+ candidate = candidates(:dawn)
+
+ candidate.build_reviews
+ assert_equal 3, candidate.votes.count
+ end
end
diff --git a/test/models/reviewer_vote_test.rb b/test/models/reviewer_vote_test.rb
new file mode 100644
index 0000000..48db0fe
--- /dev/null
+++ b/test/models/reviewer_vote_test.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+require 'test_helper'
+
+class ReviewerVoteTest < ActiveSupport::TestCase
+ test "the truth" do
+ assert ReviewerVoteTest
+ end
+
+ test "richard has 3 votes" do
+ richard = candidates(:richard)
+
+ assert_equal 3, richard.votes.size
+ end
+
+ test "manager has 4 votes" do
+ manager = users(:manager)
+
+ assert_equal 4, manager.votes.size
+ end
+
+ test "richard has been approved" do
+ richard = candidates(:richard)
+
+ assert richard.approved?
+ refute richard.declined?
+ end
+
+ test "stacy has been declined" do
+ stacy = candidates(:stacy)
+
+ assert stacy.declined?
+ refute stacy.approved?
+ end
+end
diff --git a/test/models/user_test.rb b/test/models/user_test.rb
index bc372e4..d7d9327 100644
--- a/test/models/user_test.rb
+++ b/test/models/user_test.rb
@@ -20,14 +20,14 @@ class UserTest < ActiveSupport::TestCase
refute user.reviewer?
end
- test 'manager should act as manager' do
+ test 'manager should act as manager and reviewer' do
user = users(:manager)
assert user.acts_as_manager?
+ assert user.acts_as_reviewer?
refute user.acts_as_admin?
refute user.acts_as_recruiter?
- refute user.acts_as_reviewer?
end
test 'manager should only be manager' do
diff --git a/test/policies/reviewer_vote_policy_test.rb b/test/policies/reviewer_vote_policy_test.rb
new file mode 100644
index 0000000..1824293
--- /dev/null
+++ b/test/policies/reviewer_vote_policy_test.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+require 'test_helper'
+
+class ReviewerVotePolicyTest < PolicyAssertions::Test
+ test 'should require current_user' do
+ assert_raise Pundit::NotAuthorizedError do
+ ReviewerVotePolicy.new(nil, ReviewerVote.first).view?
+ end
+ end
+
+ test 'should allow admin to scope' do
+ scope = ReviewerVotePolicy::Scope.new(users(:admin), ReviewerVote).resolve
+ assert_equal ReviewerVote.count, scope.count
+ end
+
+ test 'should allow manager to scope' do
+ scope = ReviewerVotePolicy::Scope.new(users(:manager), ReviewerVote).resolve
+ assert_equal ReviewerVote.count, scope.count
+ end
+
+ test 'should allow reviewer to scope' do
+ scope = ReviewerVotePolicy::Scope.new(users(:reviewer), ReviewerVote).resolve
+ assert_equal users(:reviewer).votes.count, scope.count
+ end
+
+ test 'should NOT allow recruiter to scope' do
+ scope = ReviewerVotePolicy::Scope.new(users(:recruiter), ReviewerVote).resolve
+ assert_equal 0, scope.count
+ end
+
+ def test_up
+ assert_permit users(:manager), reviewer_votes(:manager_richard)
+ assert_permit users(:reviewer), reviewer_votes(:reviewer_richard)
+ assert_permit users(:admin), reviewer_votes(:manager_henry)
+
+ refute_permit users(:recruiter), reviewer_votes(:manager_henry)
+ refute_permit users(:reviewer), reviewer_votes(:gustov)
+ refute_permit users(:manager), reviewer_votes(:gustov)
+ end
+
+ def test_down
+ assert_permit users(:manager), reviewer_votes(:manager_richard)
+ assert_permit users(:reviewer), reviewer_votes(:reviewer_richard)
+ assert_permit users(:admin), reviewer_votes(:manager_henry)
+
+ refute_permit users(:recruiter), reviewer_votes(:manager_henry)
+ refute_permit users(:reviewer), reviewer_votes(:gustov)
+ refute_permit users(:manager), reviewer_votes(:gustov)
+ end
+
+ def approve
+ assert_permit users(:manager), reviewer_votes(:manager_richard)
+ assert_permit users(:admin), reviewer_votes(:manager_henry)
+
+ refute_permit users(:recruiter), reviewer_votes(:manager_henry)
+ refute_permit users(:reviewer), reviewer_votes(:reviewer_richard)
+ end
+
+ def decline
+ assert_permit users(:manager), reviewer_votes(:manager_richard)
+ assert_permit users(:admin), reviewer_votes(:manager_henry)
+
+ refute_permit users(:recruiter), reviewer_votes(:manager_henry)
+ refute_permit users(:reviewer), reviewer_votes(:reviewer_richard)
+ end
+end
diff --git a/test/test_helpers/README.txt b/test/test_helpers/README.md
similarity index 100%
rename from test/test_helpers/README.txt
rename to test/test_helpers/README.md