pboling/sanitize_email

Email is not sanitized in rspec

richthedev opened this issue · 11 comments

I have installed sanitize_email (1.1.4) an am having issues with my rspec test.
I tried following the example in your README, this is /spec/support/sanitize_email.rb:

require "sanitize_email"
require "sanitize_email/rspec_matchers"

RSpec.configure do |config|
  config.include SanitizeEmail::RspecMatchers
end

describe "SanitizeEmail" do
  context "receiver email should be sanitized" do
    subject { Mail.new(from: "server@example.com", to: "email1@example.com", subject: "test") }
    it { should be_to "sanitized@example.com" }
  end
end

And in my /config/environments/test.rb:

SanitizeEmail::Config.configure do |config|
  config[:activation_proc] = Proc.new { true }
  config[:sanitized_to] = "sanitized@example.com"
end

The test fails with:

1) SanitizeEmail receiver email should be sanitized
     Failure/Error: it { should be_to "sanitized@example.com" }
       expected #<Mail::Message:46409500, Multipart: false, Headers: <From: server@example.com>, <To: email1@example.com>, <Subject: test>> to be to "sanitized@example.com"
     # ./spec/support/sanitize_email.rb:11:in `block (3 levels) in <top (required)>'

Sorry that was a typo in the readme. I think it should be Mail.deliver, not Mail.new

describe "SanitizeEmail" do
  context "receiver email should be sanitized" do
    subject { Mail.deliver(from: "server@example.com", to: "email1@example.com", subject: "test") }
    it { should be_to "sanitized@example.com" }
  end
end

Let me know if that works, please!

Interesting, now I'm getting the following:

Errno::ECONNREFUSED:
       Connection refused - connect(2)

OK, so I need to explain a bit more.

sanitize_email does not prevent mail from being sent, it only overrides the addresses that get sent to.

Thus unless you have configured your test suite otherwise, your test suite will send email.

sanitize_email does not sanitize Mail objects at time of creation, but it intercepts them with a delivery hook, modifies them, and then passes them on to delivery.

So, in order to test it, you will need to deliver them.

Fortunately, there are several ways to prevent communication with the mail server, since you probably don't want your test runs to fill actual email accounts.

One option would be the 'letter_opener' gem:

    location = File.expand_path('../tmp/mail_dump', __FILE__)
    Mail.defaults do
      delivery_method LetterOpener::DeliveryMethod, :location => location
    end

Another option is built right into the mail gem:

    Mail.defaults do
      delivery_method :test
    end

Yet another option would be the mail_catcher gem:
http://mailcatcher.me/

One more thing. I see you have used the :activation_proc setting, and have it set to true.

If you are attempting to test that the activation_proc setting works, that's fine.

But otherwise, this is slightly simpler and faster (no eval on a Proc, just is true):

SanitizeEmail::Config.configure {|config| config[:engage] = true }

Second more thing. If you see a warning that SanitizeEmail wasn't able to register an interceptor when running the tests, it is because the mail gem loads itself dynamically, and you may need to register the interceptor yourself:

Mail.register_interceptor(SanitizeEmail::Bleach.new(:engage => true))

In this last case you don't need the config[:activation_proc] = Proc.new { true }, or the config[:engage] = true, because the interceptor will just be turned on. Of course if you don't want it to be ALWAYS ON, then:

Mail.register_interceptor(SanitizeEmail::Bleach.new)
SanitizeEmail::Config.configure do |config|
  config[:activation_proc] = Proc.new { 'SOME CONDITION HERE! }
  config[:sanitized_to] = "sanitized@example.com"
end

I did understand the fact that sanitizing would not prevent mail delivering, that's why I added in /config/environment/test.rb

config.action_mailer.delivery_method = :test

and it does the job for other tests (user creation). The connection refused message is really mysterious.

It is probably because you aren't using ActionMailer to deliver the message.

Mail.deliver(from: "server@example.com", to: "email1@example.com", subject: "test") would bypass Action Mailer entirely.

You will need to set the Mail delivery system to :test as well (or use one of the alternatives I outlined in a comment above):

    Mail.defaults do
      delivery_method :test
    end

I would recommend doing that in spec_helper.rb and NOT in the rails config directory.

Okay I'm getting closer, thanks for the awesome support by the way.

I made the modifications you mentioned, now I get this weird error:

Failure/Error: it { should be_to "sanitized@example.com" }
       expected #<Mail::Message:55354600, Multipart: false, Headers: <Date: Mon, 27 Jan 2014 08:56:51 -0500>, <From: server@example.com>, <To: sanitized@example.com>, <Cc: >, <Bcc: >, <Message-ID: <52e665a39121c_9f3843e88839e5@cbx4dev.mail>>, <Subject: (email1 at example.com) [test] Test email>, <Mime-Version: 1.0>, <Content-Type: text/plain>, <Content-Transfer-Encoding: 7bit>, <X-Sanitize-Email-To: email1@example.com>> to be to "sanitized@example.com"

It seems the email was correctly sanitized, but the test does not validate the address?

Also, everything works like a charm if I use the have_to matcher.

I don't remember at the moment if I defined both have_to and be_to... I think be_to would be more complicated since it implies, sort of, a single recipient. I think my intent was to allow for testing of multiple overridden recipients. Anyways, sounds like you've got it working, yes?

Yes it is indeed working. Although I would prefer to be able to test a single recipient to be absolutely sure that the emails are being sanitized. Thanks for the gem and support!

You can do, should_not have_to @original_recipient ;)