require "rails_helper"
describe TestMailer do
let(:error_code) { "404" }
let(:success_code) { "200" }
def expect_sg_api_errors(errors)
error_messages = errors.map { |err| err['message'] }.join('. ')
message = "Sendgrid API error. Code: #{error_code}. Errors: #{error_messages}"
expect { deliver }.to raise_error(SendGridMailer::ApiError, message) do |e|
expect(e.error_code).to eq(error_code.to_i)
expect(e.errors).to eq(errors)
end
end
def expect_valid_sg_api_send_mail_request(request_body)
expect_sg_api_send_mail_request(success_code, request_body)
deliver
end
def expect_invalid_sg_api_send_mail_request(request_body, errors)
result = { errors: errors }.to_json
expect_sg_api_send_mail_request(error_code, request_body, result)
expect_sg_api_errors(errors)
end
def expect_sg_api_send_mail_request(status_code, request_body, result = nil)
result = double(status_code: status_code, body: result)
client2 = double(post: result)
client1 = double(_: client2)
expect_any_instance_of(SendGrid::Client).to receive(:_).with(:mail).and_return(client1)
expect(client2).to receive(:post).with(request_body: request_body).and_return(result)
end
def expect_valid_sg_api_get_template_request(response)
expect_sg_api_get_template_request(success_code, response)
deliver
end
def expect_invalid_sg_api_get_template_request(errors)
result = { errors: errors }.to_json
expect_sg_api_get_template_request(error_code, result)
expect_sg_api_errors(errors)
end
def expect_sg_api_get_template_request(status_code, result = nil)
result = double(status_code: status_code, body: result)
client2 = double(post: result)
client1 = double(_: client2)
expect_any_instance_of(SendGrid::Client).to receive(:_).with(:templates).and_return(client1)
expect(client2).to receive(:get).and_return(result)
end
context "when setting delivery_method to :sendgrid" do
before { allow(TestMailer).to receive(:delivery_method).and_return(:sendgrid) }
context "with valid API key" do
before { allow_any_instance_of(SendGridMailer::Deliverer).to receive(:api_key).and_return("X") }
context "with unsuccessful response" do
let(:deliver) { described_class.body_email.deliver_now! }
it "doesn't send mail" do
request_body = {
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"subject" => "Body email"
}
],
"content" => [
{
"type" => "text/plain",
"value" => "Body"
}
]
}
errors = [
{
'field' => 'from.email',
'message' => 'The from email does not...'
},
{
'field' => 'personalizations.0.to',
'message' => 'The to array is required...'
}
]
expect_invalid_sg_api_send_mail_request(request_body, errors)
end
end
context "when setting body" do
let(:deliver) { described_class.body_email.deliver_now! }
it "sends mail with valid body" do
request_body = {
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"subject" => "Body email"
}
],
"content" => [
{
"type" => "text/plain",
"value" => "Body"
}
]
}
expect_valid_sg_api_send_mail_request(request_body)
end
end
context "when setting body from params" do
let(:deliver) { described_class.body_params_email.deliver_now! }
it "sends mail with valid body" do
request_body = {
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"subject" => "Body params email"
}
],
"content" => [
{
"type" => "text/html",
"value" => "
Body Params
"
}
]
}
expect_valid_sg_api_send_mail_request(request_body)
end
end
context "when setting body from rails template" do
let(:deliver) { described_class.rails_tpl_email.deliver_now! }
it "sends mail with valid body" do
request_body = {
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"subject" => "Rails tpl email"
}
],
"content" => [
{
"type" => "text/html",
"value" => "\n \n Rails Template!\n\n \n\n"
}
]
}
expect_valid_sg_api_send_mail_request(request_body)
end
end
context "when overriding default from" do
let(:request_body) do
{
"from" =>
{
"email" => "override@platan.us"
},
"personalizations" => [
{
"subject" => subject
}
],
"content" => [
{
"type" => "text/plain",
"value" => "X"
}
]
}
end
context "when using params" do
let(:deliver) { described_class.from_params_email.deliver_now! }
let(:subject) { "From params email" }
it "sends mail with valid sender" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
context "when using methods" do
let(:deliver) { described_class.from_email.deliver_now! }
let(:subject) { "From email" }
it "sends mail with valid sender" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
end
context "with setting recipients" do
let(:request_body) do
{
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"to" => [
{
"email" => "r1@platan.us"
},
{
"email" => "r2@platan.us"
}
],
"cc" => [
{
"email" => "r4@platan.us"
}
],
"bcc" => [
{
"email" => "r5@platan.us"
}
],
"subject" => subject
}
],
"content" => [
{
"type" => "text/plain",
"value" => "X"
}
]
}
end
context "when using params" do
let(:deliver) { described_class.recipients_params_email.deliver_now! }
let(:subject) { "Recipients params email" }
it "sends mail with valid recipients" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
context "when using methods" do
let(:deliver) { described_class.recipients_email.deliver_now! }
let(:subject) { "Recipients email" }
it "sends mail with valid recipients" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
end
context "when setting template id" do
let(:request_body) do
{
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"subject" => subject
}
],
"template_id" => "XXX"
}
end
context "when using params" do
let(:deliver) { described_class.template_id_params_email.deliver_now! }
let(:subject) { "Template id params email" }
it "sends mail with valid template" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
context "when using methods" do
let(:deliver) { described_class.template_id_email.deliver_now! }
let(:subject) { "Template id email" }
it "sends mail with valid template id" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
end
context "when setting subject" do
let(:request_body) do
{
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"subject" => "My Subject"
}
],
"content" => [
{
"type" => "text/plain",
"value" => "X"
}
]
}
end
context "when using params" do
let(:deliver) { described_class.subject_params_email.deliver_now! }
it "sends mail with valid subject" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
context "when using methods" do
let(:deliver) { described_class.subject_email.deliver_now! }
it "sends mail with valid subject" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
end
context "when setting headers" do
let(:request_body) do
{
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"subject" => subject,
"headers" =>
{
"HEADER-1" => "VALUE-1",
"HEADER-2" => "VALUE-2"
}
}
],
"content" => [
{
"type" => "text/plain",
"value" => "X"
}
]
}
end
context "when using params" do
let(:deliver) { described_class.headers_params_email.deliver_now! }
let(:subject) { "Headers params email" }
it "sends mail with valid headers" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
context "when using methods" do
let(:deliver) { described_class.headers_email.deliver_now! }
let(:subject) { "Headers email" }
it "sends mail with valid headers" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
end
context "when adding attachments" do
let(:deliver) { described_class.add_attachments_email.deliver_now! }
it "sends mail with valid body" do
expect_any_instance_of(SendGrid::Attachment).to receive(:content).and_return("X")
expect_any_instance_of(SendGrid::Attachment).to receive(:content_id).and_return("A")
request_body = {
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"subject" => "Add attachments email"
}
],
"content" => [
{
"type" => "text/plain",
"value" => "X"
}
],
"attachments" => [
{
"content" => "X",
"type" => "image/png",
"filename" => "nana.png",
"disposition" => "attachment",
"content_id" => "A"
}
]
}
expect_valid_sg_api_send_mail_request(request_body)
end
end
context "when adding substitutions" do
let(:deliver) { described_class.substitutions_email.deliver_now! }
it "sends mail with valid body" do
request_body = {
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"subject" => "Substitutions email",
"substitutions" =>
{
"%key1%" => "value1",
"%key2%" => "value2"
}
}
],
"content" => [
{
"type" => "text/plain",
"value" => "X"
}
]
}
expect_valid_sg_api_send_mail_request(request_body)
end
end
context "when working with recipient interceptor" do
let(:interceptor) { double(:interceptor, class: "RecipientInterceptor") }
let(:deliver) { described_class.recipients_email.deliver_now! }
let(:request_body) do
{
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"to" => [
{ "email" => "interceptor1@platan.us" },
{ "email" => "interceptor2@platan.us" }
],
"subject" => "[STAGING] Recipients email",
"headers" =>
{
"X-Intercepted-To" => "r1@platan.us, r2@platan.us",
"X-Intercepted-Cc" => "r4@platan.us",
"X-Intercepted-Bcc" => "r5@platan.us"
}
}
],
"content" => [
{
"type" => "text/plain",
"value" => "X"
}
]
}
end
before do
allow(interceptor).to receive(:instance_variable_get)
.with(:@recipients).and_return(["interceptor1@platan.us", "interceptor2@platan.us"])
allow(interceptor).to receive(:instance_variable_get)
.with(:@subject_prefix).and_return("[STAGING]")
allow(Mail).to receive(:class_variable_get)
.with(:@@delivery_interceptors).and_return([interceptor])
end
it "sends mail with valid recipients" do
expect_valid_sg_api_send_mail_request(request_body)
end
end
end
context "with invalid API key" do
let(:deliver) { described_class.body_email.deliver_now! }
before do
allow_any_instance_of(SendGridMailer::Deliverer).to receive(:api_key).and_return(nil)
end
it { expect { deliver }.to raise_error(SendGridMailer::InvalidApiKey) }
end
end
context "when setting delivery_method to :sendgrid_dev" do
before { allow(TestMailer).to receive(:delivery_method).and_return(:sendgrid_dev) }
context "with valid API key" do
before do
allow_any_instance_of(SendGridMailer::DevDeliverer).to receive(:api_key).and_return("X")
end
context "with unsuccessful response" do
let(:sub) { 'value' }
let(:deliver) { described_class.template_with_substitutions_email(sub).deliver_now! }
it "raises sendgrid mailer error" do
errors = [
{
'field' => 'from.email',
'message' => 'The from email does not...'
},
{
'field' => 'personalizations.0.to',
'message' => 'The to array is required...'
}
]
expect_invalid_sg_api_get_template_request(errors)
end
end
context "with succesful response" do
let(:lo) { double(deliver!: nil) }
before { allow(LetterOpener::DeliveryMethod).to receive(:new).and_return(lo) }
context 'when there are no versions but there is a rails template' do
let(:response) { {}.to_json }
let(:deliver) { described_class.rails_tpl_email.deliver_now! }
let(:content) do
"\r\n \r\n Rails Template!\r\n\r\n \r\n\r\n"
end
let(:request_body) do
{
"from" =>
{
"email" => "default-sender@platan.us"
},
"personalizations" => [
{
"subject" => "Rails tpl email"
}
],
"content" => [
{
"type" => "text/html",
"value" => content
}
]
}
end
it "calls letter_opener with template content as html_part" do
expect_valid_sg_api_get_template_request(response)
expect(lo).to have_received(:deliver!) do |arg|
expect(arg.html_part.to_s).to include(content)
end
end
end
context 'when there are template versions' do
context "when using substitutions" do
let(:sub) { 'value' }
let(:deliver) { described_class.template_with_substitutions_email(sub).deliver_now! }
let(:response) do
{
versions: [
{
active: 1,
html_content: active_template
},
{
active: 0,
html_content: ''
}
]
}.to_json
end
def active_template(sub = "%key%")
"Active version
"\
"This should be replaced: #{sub}"\
"This should not be replaced: %key2%"
end
it "gets templates from sendgrid api, applies substitutions to active one and "\
"uses LetterOpener to deliver it" do
expect_valid_sg_api_get_template_request(response)
expect(lo).to have_received(:deliver!) do |arg|
expect(arg.html_part.to_s).to include(active_template(sub))
end
end
end
context "when using dynamic templates" do
let(:data) { 'value' }
let(:deliver) { described_class.dynamic_template_email(data).deliver_now! }
let(:response) do
{
versions: [
{
active: 1,
html_content: active_dynamic_template
},
{
active: 0,
html_content: ''
}
]
}.to_json
end
def active_dynamic_template(data = "{{key}}")
"Active dynamic version
"\
"This should be replaced: #{data}"
end
it "gets templates from sendgrid api, applies dynamic data to active one and "\
"uses LetterOpener to deliver it" do
expect_valid_sg_api_get_template_request(response)
expect(lo).to have_received(:deliver!) do |arg|
expect(arg.html_part.to_s).to include(active_dynamic_template(data))
end
end
end
end
end
end
end
end