adds reviewer vote reminders
completes #86 needs cronjob added on deploy to production
This commit is contained in:
commit
37f6e49592
@ -6,4 +6,17 @@ class ReviewerMailer < ApplicationMailer
|
||||
|
||||
mail to: recipients, subject: "Skills Assessment Results - #{@candidate.test_hash}"
|
||||
end
|
||||
|
||||
def reminder reminder
|
||||
@reminder = reminder
|
||||
|
||||
mail to: reminder.email, subject: "Review Reminder"
|
||||
end
|
||||
|
||||
def notify_manager candidate_id
|
||||
@candidate = Candidate.find_by(id: candidate_id)
|
||||
@manager = @candidate.manager
|
||||
|
||||
mail to: @manager.email, subject: "Voting Complete"
|
||||
end
|
||||
end
|
||||
|
@ -35,6 +35,13 @@ class Candidate < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def manager
|
||||
manager_votes = votes.joins(:user).where("users.role = 'manager'")
|
||||
return nil if manager_votes.empty?
|
||||
|
||||
manager_votes.first.user
|
||||
end
|
||||
|
||||
def submitted_answers
|
||||
answers.where(submitted: true)
|
||||
end
|
||||
|
@ -5,6 +5,8 @@ class ReviewerVote < ApplicationRecord
|
||||
|
||||
validates :user_id, uniqueness: { scope: :candidate_id }
|
||||
|
||||
after_save :notify_manager
|
||||
|
||||
enum vote: {
|
||||
undecided: 0,
|
||||
yea: 1,
|
||||
@ -15,4 +17,38 @@ class ReviewerVote < ApplicationRecord
|
||||
approved: 1,
|
||||
rejected: 2
|
||||
}
|
||||
|
||||
private
|
||||
|
||||
def notify_manager
|
||||
ReviewerMailer.notify_manager(candidate_id).deliver_now if all_reviewers_voted?
|
||||
end
|
||||
|
||||
def all_reviewers_voted? # rubocop:disable Metrics/MethodLength
|
||||
sql = " select distinct rev.candidate_id
|
||||
, full_votes.voters, full_votes.vote_count
|
||||
, c.test_hash
|
||||
from reviewer_votes rev
|
||||
inner join users u on u.id = rev.user_id
|
||||
inner join candidates c on c.id = rev.candidate_id
|
||||
left join (
|
||||
select candidate_id
|
||||
from reviewer_votes
|
||||
where veto > 0 or veto is null
|
||||
) as vetos on vetos.candidate_id = rev.candidate_id
|
||||
left join (
|
||||
select candidate_id
|
||||
, count(vote) voters
|
||||
, sum(case when vote != 0 then 1 else 0 end) vote_count
|
||||
from reviewer_votes
|
||||
left join users on users.id = reviewer_votes.user_id
|
||||
where users.role != 'manager'
|
||||
group by candidate_id
|
||||
) as full_votes on full_votes.candidate_id = rev.candidate_id
|
||||
where vetos.candidate_id is null
|
||||
and full_votes.voters = full_votes.vote_count
|
||||
and rev.candidate_id = #{candidate_id};"
|
||||
result = ActiveRecord::Base.connection.exec_query(sql)
|
||||
result.count == 1
|
||||
end # rubocop:enable Metrics/MethodLength
|
||||
end
|
||||
|
@ -19,6 +19,8 @@ class User < ApplicationRecord
|
||||
end
|
||||
|
||||
# Voting
|
||||
# TODO: Refactor this out of User, belongs on ReviewerVote
|
||||
# ie: cast_yea(candidate, user)
|
||||
def cast_yea_on candidate
|
||||
vote = votes.find_by(candidate_id: candidate.to_i)
|
||||
vote.vote = :yea
|
||||
|
10
app/views/reviewer_mailer/notify_manager.html.inky
Normal file
10
app/views/reviewer_mailer/notify_manager.html.inky
Normal file
@ -0,0 +1,10 @@
|
||||
<row>
|
||||
<columns class="email-body">
|
||||
<p>Hello <%= @manager.name %>,</p>
|
||||
<p>
|
||||
Everyone has voted and you need to request or decline an interview for
|
||||
<%= link_to nil, admin_result_url(@candidate.test_hash) %>
|
||||
</p>
|
||||
</columns>
|
||||
</row>
|
||||
|
6
app/views/reviewer_mailer/notify_manager.text.erb
Normal file
6
app/views/reviewer_mailer/notify_manager.text.erb
Normal file
@ -0,0 +1,6 @@
|
||||
PERFICIENT/digital SKILLS ASSESSMENT RESULTS
|
||||
|
||||
Hello <%= @manager.name %>,
|
||||
|
||||
Everyone has voted and you need to request or decline an interview for
|
||||
<%= admin_result_url(@candidate.test_hash) %>
|
9
app/views/reviewer_mailer/reminder.html.inky
Normal file
9
app/views/reviewer_mailer/reminder.html.inky
Normal file
@ -0,0 +1,9 @@
|
||||
<row>
|
||||
<columns class="email-body">
|
||||
<p>Hello <%= @reminder.name %>,</p>
|
||||
<p>
|
||||
Please review and vote on the results for <%= link_to nil, admin_result_url(@reminder.test_hash) %>
|
||||
</p>
|
||||
</columns>
|
||||
</row>
|
||||
|
5
app/views/reviewer_mailer/reminder.text.erb
Normal file
5
app/views/reviewer_mailer/reminder.text.erb
Normal file
@ -0,0 +1,5 @@
|
||||
PERFICIENT/digital SKILLS ASSESSMENT RESULTS
|
||||
|
||||
Hello <%= @reminder.name %>,
|
||||
|
||||
Please review and vote on the results for <%= admin_result_url(@reminder.test_hash) %>.
|
@ -1,5 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
class Reminder
|
||||
class CandidateReminder
|
||||
def initialize
|
||||
@collection = reminder_collection
|
||||
end
|
33
app/workers/reviewer_reminder.rb
Normal file
33
app/workers/reviewer_reminder.rb
Normal file
@ -0,0 +1,33 @@
|
||||
# frozen_string_literal: true
|
||||
class ReviewerReminder
|
||||
def initialize
|
||||
@collection = reminder_collection
|
||||
end
|
||||
|
||||
def count
|
||||
@collection.count
|
||||
end
|
||||
alias size count
|
||||
|
||||
def reminders
|
||||
@reminders ||= @collection.to_hash.map { |r| OpenStruct.new(r) }
|
||||
end
|
||||
|
||||
def send_all
|
||||
reminders.each do |reminder|
|
||||
ReviewerMailer.reminder(reminder).deliver_now
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def reminder_collection
|
||||
sql = "select u.name, u.email, c.test_hash, c.project
|
||||
from reviewer_votes rev
|
||||
inner join users u on u.id = rev.user_id
|
||||
inner join candidates c on c.id = rev.candidate_id
|
||||
where rev.vote = 0 and rev.veto = 0
|
||||
and u.role != 'manager' and u.active is not false;"
|
||||
ActiveRecord::Base.connection.exec_query(sql)
|
||||
end
|
||||
end
|
@ -2,7 +2,13 @@
|
||||
namespace :reminders do
|
||||
desc "send reminders to stagnate quizes"
|
||||
task send_all: :environment do
|
||||
reminders = Reminder.new
|
||||
reminders = CandidateReminder.new
|
||||
reminders.send_all
|
||||
end
|
||||
|
||||
desc "send reminders to reviewers"
|
||||
task reviewers: :environment do
|
||||
reminders = ReviewerReminder.new
|
||||
reminders.send_all
|
||||
end
|
||||
end
|
||||
|
194
test/fixtures/answers.yml
vendored
194
test/fixtures/answers.yml
vendored
@ -696,3 +696,197 @@ wade10:
|
||||
created_at: <%= DateTime.now() - 36.hours - 40.minutes %>
|
||||
updated_at: <%= DateTime.now() - 36.hours - 20.minutes %>
|
||||
|
||||
jorge1:
|
||||
candidate: jorge
|
||||
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 %>
|
||||
|
||||
jorge2:
|
||||
candidate: jorge
|
||||
question: fed2
|
||||
answer: 'indexOf()'
|
||||
saved: 0
|
||||
submitted: true
|
||||
created_at: <%= DateTime.now() - 36.hours - 24.minutes %>
|
||||
updated_at: <%= DateTime.now() - 36.hours - 4.minutes %>
|
||||
|
||||
jorge3:
|
||||
candidate: jorge
|
||||
question: fed3
|
||||
answer: {html: '<h1>Salmon</h1>', 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 %>
|
||||
|
||||
jorge4:
|
||||
candidate: jorge
|
||||
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 %>
|
||||
|
||||
jorge5:
|
||||
candidate: jorge
|
||||
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 %>
|
||||
|
||||
jorge6:
|
||||
candidate: jorge
|
||||
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 %>
|
||||
|
||||
jorge7:
|
||||
candidate: jorge
|
||||
question: fed7
|
||||
answer: {html: '<p>This means <strong>jQuery</strong> needs to be available in live-coder!</p>', 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 %>
|
||||
|
||||
jorge8:
|
||||
candidate: jorge
|
||||
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 %>
|
||||
|
||||
jorge9:
|
||||
candidate: jorge
|
||||
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 %>
|
||||
|
||||
jorge10:
|
||||
candidate: jorge
|
||||
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 %>
|
||||
|
||||
elsie1:
|
||||
candidate: elsie
|
||||
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 %>
|
||||
|
||||
elsie2:
|
||||
candidate: elsie
|
||||
question: fed2
|
||||
answer: 'indexOf()'
|
||||
saved: 0
|
||||
submitted: true
|
||||
created_at: <%= DateTime.now() - 36.hours - 24.minutes %>
|
||||
updated_at: <%= DateTime.now() - 36.hours - 4.minutes %>
|
||||
|
||||
elsie3:
|
||||
candidate: elsie
|
||||
question: fed3
|
||||
answer: {html: '<h1>Salmon</h1>', 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 %>
|
||||
|
||||
elsie4:
|
||||
candidate: elsie
|
||||
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 %>
|
||||
|
||||
elsie5:
|
||||
candidate: elsie
|
||||
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 %>
|
||||
|
||||
elsie6:
|
||||
candidate: elsie
|
||||
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 %>
|
||||
|
||||
elsie7:
|
||||
candidate: elsie
|
||||
question: fed7
|
||||
answer: {html: '<p>This means <strong>jQuery</strong> needs to be available in live-coder!</p>', 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 %>
|
||||
|
||||
elsie8:
|
||||
candidate: elsie
|
||||
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 %>
|
||||
|
||||
elsie9:
|
||||
candidate: elsie
|
||||
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 %>
|
||||
|
||||
elsie10:
|
||||
candidate: elsie
|
||||
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 %>
|
||||
|
||||
|
24
test/fixtures/candidates.yml
vendored
24
test/fixtures/candidates.yml
vendored
@ -116,6 +116,30 @@ wade: # Wade has completed AND submitted the test
|
||||
reminded: false
|
||||
test_hash: BkSkpapJnkz2N
|
||||
|
||||
jorge: # Jorge has completed AND submitted the test
|
||||
name: Jorge Holmes
|
||||
email: <%= CryptSerializer.dump 'jorge.holmes@mailinator.com' %>
|
||||
experience: 0-3
|
||||
project: Client/Project
|
||||
recruiter: recruiter
|
||||
quiz: fed
|
||||
completed: true
|
||||
completed_at: <%= DateTime.current %>
|
||||
reminded: false
|
||||
test_hash: iC5FdWJxcyySBmpOpU
|
||||
|
||||
elsie: # Elsie has completed AND submitted the test
|
||||
name: Elsie Lowe
|
||||
email: <%= CryptSerializer.dump 'elsie.lowe@mailinator.com' %>
|
||||
experience: 0-3
|
||||
project: Client/Project
|
||||
recruiter: recruiter
|
||||
quiz: fed
|
||||
completed: true
|
||||
completed_at: <%= DateTime.current %>
|
||||
reminded: false
|
||||
test_hash: rLSoizA3ATMNSCx
|
||||
|
||||
gustov: # Gustov is NOT for FED
|
||||
name: Gustov
|
||||
email: <%= CryptSerializer.dump 'gustov@mailinator.com' %>
|
||||
|
27
test/fixtures/reviewer_votes.yml
vendored
27
test/fixtures/reviewer_votes.yml
vendored
@ -66,3 +66,30 @@ reviewer2_wade:
|
||||
candidate: wade
|
||||
user: reviewer2
|
||||
|
||||
|
||||
manager_jorge:
|
||||
candidate: jorge
|
||||
user: manager
|
||||
|
||||
reviewer_jorge:
|
||||
candidate: jorge
|
||||
user: reviewer
|
||||
vote: 1
|
||||
|
||||
reviewer2_jorge:
|
||||
candidate: jorge
|
||||
user: reviewer2
|
||||
|
||||
|
||||
manager_elsie:
|
||||
candidate: elsie
|
||||
user: manager
|
||||
|
||||
reviewer_elsie:
|
||||
candidate: elsie
|
||||
user: reviewer
|
||||
|
||||
reviewer2_elsie:
|
||||
candidate: elsie
|
||||
user: reviewer2
|
||||
|
||||
|
@ -4,4 +4,14 @@ class ReviewerMailerPreview < ActionMailer::Preview
|
||||
def candidate_submission
|
||||
ReviewerMailer.candidate_submission Candidate.find_by(test_hash: 'OvP0ZqGKwJ0') # Dawn
|
||||
end
|
||||
|
||||
def reminder
|
||||
reminders = ReviewerReminder.new
|
||||
reminder = reminders.reminders.first
|
||||
ReviewerMailer.reminder reminder
|
||||
end
|
||||
|
||||
def notify_manager
|
||||
ReviewerMailer.notify_manager Candidate.find_by(test_hash: 'OvP0ZqGKwJ0').id # Dawn
|
||||
end
|
||||
end
|
||||
|
@ -11,4 +11,23 @@ class ReviewerMailerTest < ActionMailer::TestCase
|
||||
assert_equal [ENV["default_mail_from"]], mail.from
|
||||
assert_match candidate.test_hash, mail.body.encoded
|
||||
end
|
||||
|
||||
test "reminder" do
|
||||
reminders = ReviewerReminder.new
|
||||
reminder = reminders.reminders.first
|
||||
mail = ReviewerMailer.reminder reminder
|
||||
assert_match "Review Reminder", mail.subject
|
||||
assert_equal [reminder.email], mail.to
|
||||
assert_equal [ENV["default_mail_from"]], mail.from
|
||||
assert_match reminder.test_hash, mail.body.encoded
|
||||
end
|
||||
|
||||
test "notify_manager" do
|
||||
candidate = candidates(:richard)
|
||||
mail = ReviewerMailer.notify_manager candidate.id
|
||||
assert_match "Voting Complete", mail.subject
|
||||
assert_equal [candidate.manager.email], mail.to
|
||||
assert_equal [ENV["default_mail_from"]], mail.from
|
||||
assert_match candidate.test_hash, mail.body.encoded
|
||||
end
|
||||
end
|
||||
|
@ -12,10 +12,11 @@ class ReviewerVoteTest < ActiveSupport::TestCase
|
||||
assert_equal 3, richard.votes.size
|
||||
end
|
||||
|
||||
test "manager has 4 votes" do
|
||||
test "manager has a vote for every completed quiz" do
|
||||
manager = users(:manager)
|
||||
completed_count = Candidate.where(completed: true).count
|
||||
|
||||
assert_equal 4, manager.votes.size
|
||||
assert_equal completed_count, manager.votes.size
|
||||
end
|
||||
|
||||
test "richard has been approved" do
|
||||
@ -31,4 +32,22 @@ class ReviewerVoteTest < ActiveSupport::TestCase
|
||||
assert stacy.declined?
|
||||
refute stacy.approved?
|
||||
end
|
||||
|
||||
test "mailer is queued on last vote" do
|
||||
reviewer = users(:reviewer2)
|
||||
candidate = candidates(:jorge)
|
||||
|
||||
assert_difference("ActionMailer::Base.deliveries.size", 1) do
|
||||
reviewer.cast_yea_on(candidate)
|
||||
end
|
||||
end
|
||||
|
||||
test "mailer is NOT queued on first vote" do
|
||||
reviewer = users(:reviewer2)
|
||||
candidate = candidates(:elsie)
|
||||
|
||||
assert_difference("ActionMailer::Base.deliveries.size", 0) do
|
||||
reviewer.cast_yea_on(candidate)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,14 +1,14 @@
|
||||
# frozen_string_literal: true
|
||||
require 'test_helper'
|
||||
|
||||
class ReminderTest < ActiveSupport::TestCase
|
||||
class CandidateReminderTest < ActiveSupport::TestCase
|
||||
test "collection is created with one result" do
|
||||
reminders = Reminder.new
|
||||
reminders = CandidateReminder.new
|
||||
assert_equal 1, reminders.size
|
||||
end
|
||||
|
||||
test "each candidate has needed attributes" do
|
||||
reminders = Reminder.new
|
||||
reminders = CandidateReminder.new
|
||||
|
||||
assert_instance_of String, reminders.candidates.first.name
|
||||
assert_instance_of String, reminders.candidates.first.test_hash
|
||||
@ -16,7 +16,7 @@ class ReminderTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test "send reminders sends email, and flags reminded" do
|
||||
reminders = Reminder.new
|
||||
reminders = CandidateReminder.new
|
||||
pre_reminded = Candidate.find(reminders.candidates.first.id).reminded
|
||||
|
||||
assert_difference("ActionMailer::Base.deliveries.size", reminders.count) do
|
25
test/workers/reviewer_reminder_test.rb
Normal file
25
test/workers/reviewer_reminder_test.rb
Normal file
@ -0,0 +1,25 @@
|
||||
# frozen_string_literal: true
|
||||
require 'test_helper'
|
||||
|
||||
class ReviewerReminderTest < ActiveSupport::TestCase
|
||||
test "collection is created with results" do
|
||||
reminders = ReviewerReminder.new
|
||||
assert_equal 6, reminders.size
|
||||
end
|
||||
|
||||
test "each reminder has needed attributes" do
|
||||
collection = ReviewerReminder.new
|
||||
|
||||
assert_instance_of String, collection.reminders.first.name
|
||||
assert_instance_of String, collection.reminders.first.email
|
||||
assert_instance_of String, collection.reminders.first.test_hash
|
||||
end
|
||||
|
||||
test "send_all sends emails for each reviewer and test" do
|
||||
collection = ReviewerReminder.new
|
||||
|
||||
assert_difference("ActionMailer::Base.deliveries.size", collection.count) do
|
||||
collection.send_all
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user