Reputation: 3120
I have a rails method which allows a user to submit a review and to counterparty, it sends an email using the delayed jobs.
def update_review
@review.add_review_content(review_params)
ReviewMailer.delay.review_posted(@review.product_owner, params[:id])
end
And I am trying to add a rspec
test for this to check if the mailer is delivered properly and to whom. The delayed jobs run immediately after they are created on test
because I want other jobs like the job to update the product owners overall rating to be completed immediately.
So the email does get fired but how can I add a test for it?
EDIT: Adding current tests
My current tests are:
describe 'PUT #update the review' do
let(:attr) do
{ rating: 3.0, raw_review: 'Some example review here' }
end
before(:each) do
@review = FactoryBot.create :review
put :update, id: @review.id, review: attr
end
it 'creates a job' do
ActiveJob::Base.queue_adapter = :test
expect {
AdminMailer.review_posted(@coach, @review.id).deliver_later
}.to have_enqueued_job
end
it { should respond_with 200 }
end
This does test that the mailer works properly but I want to test that it gets triggered properly in the method flow as well.
Upvotes: 0
Views: 919
Reputation: 3615
It sounds like what you want is to ensure that the update_review
method enqueues a job to send the correct email to the correct recipient. Here's a simpler way to accomplish that:
describe 'PUT #update the review' do
let(:params) { { rating: rating, raw_review: raw_review } }
let(:rating) { 3.0 }
let(:raw_review) { 'Some example review here' }
let(:review) { FactoryBot.create(:review) }
let(:delayed_review_mailer) { instance_double(ReviewMailer) }
before do
# assuming this is how the controller finds the review...
allow(Review).to receive(:find).and_return(review)
# mock the method chain that enqueues the job to send the email
allow(ReviewMailer).to receive(:delay).and_return(delayed_review_mailer)
allow(delayed_review_mailer).to receive(:review_posted)
put :update, id: review.id review: params
end
it 'adds the review content to the review' do
review.reload
expect(review.rating).to eq(rating)
expect(review.raw_review).to eq(raw_review)
end
it 'sends a delayed email' do
expect(ReviewMailer).to have_received(:delay)
end
it 'sends a review posted email to the product owner' do
expect(delayed_review_mailer)
.to have_received(:review_posted)
.with(review.product_owner, review.id)
end
end
The reason I prefer this approach is that a) it could be done without touching the database at all (by swapping the factory for an instance double), and b) it doesn't try to test parts of Rails that were already tested by the folks who built Rails, like ActiveJob and ActionMailer. You can trust Rails' own unit tests for those classes.
Upvotes: 1