diff --git a/.rspec b/.rspec
new file mode 100644
index 0000000..83e16f8
--- /dev/null
+++ b/.rspec
@@ -0,0 +1,2 @@
+--color
+--require spec_helper
diff --git a/.rubocop.yml b/.rubocop.yml
index 6fdaa42..17005c3 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -3,3 +3,4 @@ inherit_from:
Metrics/BlockLength:
Exclude:
- 'test/**/*'
+ - 'spec/**/*'
diff --git a/.travis.yml b/.travis.yml
index b72bae5..9b09564 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,7 @@ before_install:
- gem update --system
- rvm @global do gem uninstall bundler -a -x
- rvm @global do gem install bundler -v 1.13.7
-script: 'bundle exec rake test:coverage --trace && bundle exec rubocop'
+script: 'bundle exec rake spec:coverage --trace && bundle exec rubocop'
rvm:
- 2.3.3
- 2.4.0
diff --git a/Rakefile b/Rakefile
index 9e6597c..e1ddb5f 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,17 +1,25 @@
require 'rake'
-require 'rake/testtask'
require 'bundler/gem_tasks'
+require 'rspec/core/rake_task'
+require 'rake/testtask'
Rake::TestTask.new do |t|
t.pattern = 'test/**/*_test.rb'
t.libs.push 'test'
end
-namespace :test do
+namespace :spec do
+ RSpec::Core::RakeTask.new(:unit) do |task|
+ file_list = FileList['spec/**/*_spec.rb']
+ file_list = file_list.exclude("spec/{integration,isolation}/**/*_spec.rb")
+
+ task.pattern = file_list
+ end
+
task :coverage do
- ENV['COVERALL'] = 'true'
- Rake::Task['test'].invoke
+ ENV['COVERAGE'] = 'true'
+ Rake::Task['spec:unit'].invoke
end
end
-task default: :test
+task default: 'spec:unit'
diff --git a/hanami-mailer.gemspec b/hanami-mailer.gemspec
index c92874e..4ea9d9a 100644
--- a/hanami-mailer.gemspec
+++ b/hanami-mailer.gemspec
@@ -26,4 +26,5 @@ Gem::Specification.new do |spec|
spec.add_development_dependency 'bundler', '~> 1.10'
spec.add_development_dependency 'rake', '~> 11'
spec.add_development_dependency 'minitest', '~> 5.7'
+ spec.add_development_dependency 'rspec', '~> 3.5'
end
diff --git a/spec/hanami/mailer/configuration_spec.rb b/spec/hanami/mailer/configuration_spec.rb
new file mode 100644
index 0000000..d08a642
--- /dev/null
+++ b/spec/hanami/mailer/configuration_spec.rb
@@ -0,0 +1,194 @@
+RSpec.describe Hanami::Mailer::Configuration do
+ before do
+ @configuration = Hanami::Mailer::Configuration.new
+ end
+
+ describe '#root' do
+ describe 'when a value is given' do
+ describe 'and it is a string' do
+ it 'sets it as a Pathname' do
+ @configuration.root 'test'
+ expect(@configuration.root).to eq(Pathname.new('test').realpath)
+ end
+ end
+
+ describe 'and it is a pathname' do
+ it 'sets it' do
+ @configuration.root Pathname.new('test')
+ expect(@configuration.root).to eq(Pathname.new('test').realpath)
+ end
+ end
+
+ describe 'and it implements #to_pathname' do
+ before do
+ RootPath = Struct.new(:path) do
+ def to_pathname
+ Pathname(path)
+ end
+ end
+ end
+
+ after do
+ Object.send(:remove_const, :RootPath)
+ end
+
+ it 'sets the converted value' do
+ @configuration.root RootPath.new('test')
+ expect(@configuration.root).to eq(Pathname.new('test').realpath)
+ end
+ end
+
+ describe 'and it is an unexisting path' do
+ it 'raises an error' do
+ expect do
+ @configuration.root '/path/to/unknown'
+ end.to raise_error(Errno::ENOENT)
+ end
+ end
+ end
+
+ describe 'when a value is not given' do
+ it 'defaults to the current path' do
+ expect(@configuration.root).to eq(Pathname.new('.').realpath)
+ end
+ end
+ end
+
+ describe '#mailers' do
+ it 'defaults to an empty set' do
+ expect(@configuration.mailers).to be_empty
+ end
+
+ it 'allows to add mailers' do
+ @configuration.add_mailer(InvoiceMailer)
+ expect(@configuration.mailers).to include(InvoiceMailer)
+ end
+
+ it 'eliminates duplications' do
+ @configuration.add_mailer(RenderMailer)
+ @configuration.add_mailer(RenderMailer)
+
+ expect(@configuration.mailers.size).to eq(1)
+ end
+ end
+
+ describe '#prepare' do
+ before do
+ module FooRendering
+ def render
+ 'foo'
+ end
+ end
+
+ class PrepareMailer
+ end
+ end
+
+ after do
+ Object.__send__(:remove_const, :FooRendering)
+ Object.__send__(:remove_const, :PrepareMailer)
+ end
+
+ it 'raises error in case of missing block' do
+ expect { @configuration.prepare }.to raise_error(ArgumentError, 'Please provide a block')
+ end
+ end
+
+ # describe '#reset!' do
+ # before do
+ # @configuration.root 'test'
+ # @configuration.add_mailer(InvoiceMailer)
+
+ # @configuration.reset!
+ # end
+
+ # it 'resets root' do
+ # root = Pathname.new('.').realpath
+
+ # @configuration.root.must_equal root
+ # @configuration.mailers.must_be_empty
+ # end
+
+ # it "doesn't reset namespace" do
+ # @configuration.namespace(InvoiceMailer)
+ # @configuration.reset!
+
+ # @configuration.namespace.must_equal(InvoiceMailer)
+ # end
+
+ # end
+
+ describe '#load!' do
+ before do
+ @configuration.root 'test'
+ @configuration.load!
+ end
+
+ it 'loads root' do
+ root = Pathname.new('test').realpath
+ expect(@configuration.root).to eq(root)
+ end
+ end
+
+ describe '#delivery_method' do
+ describe 'when not previously set' do
+ before do
+ @configuration.reset!
+ end
+
+ it 'defaults to SMTP' do
+ expect(@configuration.delivery_method).to eq([:smtp, {}])
+ end
+ end
+
+ describe 'set with a symbol' do
+ before do
+ @configuration.delivery_method :exim, location: '/path/to/exim'
+ end
+
+ it 'saves the delivery method in the configuration' do
+ expect(@configuration.delivery_method).to eq([:exim, { location: '/path/to/exim' }])
+ end
+ end
+
+ describe 'set with a class' do
+ before do
+ @configuration.delivery_method MandrillDeliveryMethod,
+ username: 'mandrill-username', password: 'mandrill-api-key'
+ end
+
+ it 'saves the delivery method in the configuration' do
+ expect(@configuration.delivery_method).to eq([MandrillDeliveryMethod, username: 'mandrill-username', password: 'mandrill-api-key'])
+ end
+ end
+ end
+
+ describe '#default_charset' do
+ describe 'when not previously set' do
+ before do
+ @configuration.reset!
+ end
+
+ it 'defaults to UTF-8' do
+ expect(@configuration.default_charset).to eq('UTF-8')
+ end
+ end
+
+ describe 'when set' do
+ before do
+ @configuration.default_charset 'iso-8859-1'
+ end
+
+ it 'saves the delivery method in the configuration' do
+ expect(@configuration.default_charset).to eq('iso-8859-1')
+ end
+ end
+ end
+
+ describe '#prepare' do
+ it 'injects code in each mailer'
+ # it 'injects code in each mailer' do
+ # InvoiceMailer.subject.must_equal 'default subject'
+ # end
+ end
+end
diff --git a/spec/hanami/mailer/delivery_spec.rb b/spec/hanami/mailer/delivery_spec.rb
new file mode 100644
index 0000000..3807819
--- /dev/null
+++ b/spec/hanami/mailer/delivery_spec.rb
@@ -0,0 +1,164 @@
+RSpec.describe Hanami::Mailer do
+ describe '.deliver' do
+ before do
+ Hanami::Mailer.deliveries.clear
+ end
+
+ it 'can deliver with specified charset' do
+ CharsetMailer.deliver(charset: charset = 'iso-2022-jp')
+
+ mail = Hanami::Mailer.deliveries.first
+ expect(mail.charset).to eq(charset)
+ expect(mail.parts.first.charset).to eq(charset)
+ end
+
+ it "raises error when 'from' isn't specified" do
+ expect { MissingFromMailer.deliver }.to raise_error(Hanami::Mailer::MissingDeliveryDataError)
+ end
+
+ it "raises error when 'to' isn't specified" do
+ expect { MissingToMailer.deliver }.to raise_error(Hanami::Mailer::MissingDeliveryDataError)
+ end
+
+ describe 'test delivery with hardcoded values' do
+ before do
+ WelcomeMailer.deliver
+ @mail = Hanami::Mailer.deliveries.first
+ end
+
+ after do
+ Hanami::Mailer.deliveries.clear
+ end
+
+ it 'delivers the mail' do
+ expect(Hanami::Mailer.deliveries.length).to eq(1)
+ end
+
+ it 'sends the correct information' do
+ expect(@mail.from).to eq(['noreply@sender.com'])
+ expect(@mail.to).to eq(['noreply@recipient.com', 'owner@recipient.com'])
+ expect(@mail.cc).to eq(['cc@recipient.com'])
+ expect(@mail.bcc).to eq(['bcc@recipient.com'])
+ expect(@mail.subject).to eq('Welcome')
+ end
+
+ it 'has the correct templates' do
+ expect(@mail.html_part.to_s).to include(%(template))
+ expect(@mail.text_part.to_s).to include(%(template))
+ end
+
+ it 'interprets the prepare statement' do
+ attachment = @mail.attachments['invoice.pdf']
+
+ expect(attachment).to be_kind_of(Mail::Part)
+
+ expect(attachment).to be_attachment
+ expect(attachment).to_not be_inline
+ expect(attachment).to_not be_multipart
+
+ expect(attachment.filename).to eq('invoice.pdf')
+
+ expect(attachment.content_type).to match('application/pdf')
+ expect(attachment.content_type).to match('filename=invoice.pdf')
+ end
+ end
+
+ describe 'test delivery with methods' do
+ before do
+ @user = User.new('Name', 'student@deigirls.com')
+ MethodMailer.deliver(user: @user)
+
+ @mail = Hanami::Mailer.deliveries.first
+ end
+
+ after do
+ Hanami::Mailer.deliveries.clear
+ end
+
+ it 'delivers the mail' do
+ expect(Hanami::Mailer.deliveries.length).to eq(1)
+ end
+
+ it 'sends the correct information' do
+ expect(@mail.from).to eq(["hello-#{@user.name.downcase}@example.com"])
+ expect(@mail.to).to eq([@user.email])
+ expect(@mail.subject).to eq("Hello, #{@user.name}")
+ end
+ end
+
+ describe 'multipart' do
+ after do
+ Hanami::Mailer.deliveries.clear
+ end
+
+ it 'delivers all the parts by default' do
+ WelcomeMailer.deliver
+
+ mail = Hanami::Mailer.deliveries.first
+ body = mail.body.encoded
+
+ expect(body).to include(%(
Hello World!
))
+ expect(body).to include(%(This is a txt template))
+ end
+
+ it 'can deliver only the text part' do
+ WelcomeMailer.deliver(format: :txt)
+
+ mail = Hanami::Mailer.deliveries.first
+ body = mail.body.encoded
+
+ expect(body).to_not include(%(Hello World!
))
+ expect(body).to include(%(This is a txt template))
+ end
+
+ it 'can deliver only the html part' do
+ WelcomeMailer.deliver(format: :html)
+
+ mail = Hanami::Mailer.deliveries.first
+ body = mail.body.encoded
+
+ expect(body).to include(%(Hello World!
))
+ expect(body).to_not include(%(This is a txt template))
+ end
+ end
+
+ describe 'custom delivery' do
+ before do
+ @options = options = { deliveries: [] }
+
+ # Hanami::Mailer.reset!
+ # Hanami::Mailer.configure do
+ # delivery_method MandrillDeliveryMethod, options
+ # end.load!
+
+ WelcomeMailer.deliver
+
+ @mail = options.fetch(:deliveries).first
+ end
+
+ it 'delivers the mail'
+ # it 'delivers the mail' do
+ # @options.fetch(:deliveries).length.must_equal 1
+ # end
+
+ # it 'sends the correct information' do
+ # @mail.from.must_equal ['noreply@sender.com']
+ # @mail.to.must_equal ['noreply@recipient.com']
+ # @mail.subject.must_equal "Welcome"
+ # end
+
+ # it 'has the correct templates' do
+ # @mail.html_part.to_s.must_include %(template)
+ # @mail.text_part.to_s.must_include %(template)
+ # end
+
+ # it 'interprets the prepare statement' do
+ # @mail.attachments['invoice.pdf'].wont_be_nil
+ # end
+
+ # it 'adds the attachment to the mail object' do
+ # @mail.attachments['render_mailer.html.erb'].wont_be_nil
+ # end
+ end
+ end
+end
diff --git a/spec/hanami/mailer/dsl_spec.rb b/spec/hanami/mailer/dsl_spec.rb
new file mode 100644
index 0000000..c55b19c
--- /dev/null
+++ b/spec/hanami/mailer/dsl_spec.rb
@@ -0,0 +1,47 @@
+RSpec.describe Hanami::Mailer do
+ describe '.template' do
+ describe 'when no value is set' do
+ it 'returns the convention name' do
+ expect(RenderMailer.template).to eq('render_mailer')
+ end
+
+ it 'returns correct namespaced value' do
+ expect(Users::Welcome.template).to eq('users/welcome')
+ end
+ end
+
+ describe 'when a value is set' do
+ it 'returns that name' do
+ expect(InvoiceMailer.template).to eq('invoice')
+ end
+ end
+ end
+
+ describe '.templates' do
+ describe 'when no value is set' do
+ it 'returns a set of templates' do
+ template_formats = LazyMailer.templates.keys
+ expect(template_formats).to eq([:html, :txt])
+ end
+
+ it 'returns only the template for the given format' do
+ template = LazyMailer.templates(:txt)
+ expect(template).to be_kind_of(Hanami::Mailer::Template)
+ expect(template.file).to match(%r{spec/support/fixtures/templates/lazy_mailer.txt.erb\z})
+ end
+ end
+
+ describe 'when a value is set' do
+ it 'returns a set of templates' do
+ template_formats = InvoiceMailer.templates.keys
+ expect(template_formats).to eq([:html])
+ end
+
+ it 'returns only the template for the given format' do
+ template = InvoiceMailer.templates(:html)
+ expect(template).to be_kind_of(Hanami::Mailer::Template)
+ expect(template.file).to match(%r{spec/support/fixtures/templates/invoice.html.erb\z})
+ end
+ end
+ end
+end
diff --git a/spec/hanami/mailer/rendering_spec.rb b/spec/hanami/mailer/rendering_spec.rb
new file mode 100644
index 0000000..290dd88
--- /dev/null
+++ b/spec/hanami/mailer/rendering_spec.rb
@@ -0,0 +1,44 @@
+RSpec.describe Hanami::Mailer do
+ describe '#render' do
+ describe 'when template is explicitly declared' do
+ let(:mailer) { InvoiceMailer.new }
+
+ it 'renders the given template' do
+ expect(mailer.render(:html)).to include(%(Invoice template
))
+ end
+ end
+
+ describe 'when template is implicitly declared' do
+ let(:mailer) { LazyMailer.new }
+
+ it 'looks for template with same name with inflected classname and render it' do
+ expect(mailer.render(:html)).to include(%(Hello World))
+ expect(mailer.render(:txt)).to include(%(This is a txt template))
+ end
+ end
+
+ describe 'when mailer defines context' do
+ let(:mailer) { WelcomeMailer.new }
+
+ it 'renders template with defined context' do
+ expect(mailer.render(:txt)).to include(%(Ahoy))
+ end
+ end
+
+ describe 'when locals are parsed in' do
+ let(:mailer) { RenderMailer.new(user: User.new('Luca')) }
+
+ it 'renders template with parsed locals' do
+ expect(mailer.render(:html)).to include(%(Luca))
+ end
+ end
+
+ describe 'with HAML template engine' do
+ let(:mailer) { TemplateEngineMailer.new(user: User.new('Luca')) }
+
+ it 'renders template with parsed locals' do
+ expect(mailer.render(:html)).to include(%(\n Luca\n
\n))
+ end
+ end
+ end
+end
diff --git a/spec/hanami/mailer/version_spec.rb b/spec/hanami/mailer/version_spec.rb
new file mode 100644
index 0000000..941bcab
--- /dev/null
+++ b/spec/hanami/mailer/version_spec.rb
@@ -0,0 +1,5 @@
+RSpec.describe Hanami::Mailer::VERSION do
+ it "returns current version" do
+ expect(Hanami::Mailer::VERSION).to eq("1.0.0.beta2")
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..6ddae0f
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,61 @@
+if ENV['COVERALL']
+ require 'coveralls'
+ Coveralls.wear!
+end
+
+require 'hanami/utils'
+
+RSpec.configure do |config|
+ config.expect_with :rspec do |expectations|
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+ end
+
+ config.mock_with :rspec do |mocks|
+ mocks.verify_partial_doubles = true
+ end
+
+ config.shared_context_metadata_behavior = :apply_to_host_groups
+
+ config.filter_run_when_matching :focus
+ config.disable_monkey_patching!
+
+ config.warnings = true
+
+ config.default_formatter = 'doc' if config.files_to_run.one?
+
+ config.profile_examples = 10
+
+ config.order = :random
+ Kernel.srand config.seed
+end
+
+$LOAD_PATH.unshift 'lib'
+require 'hanami/mailer'
+
+Hanami::Mailer.configure do
+ root Pathname.new __dir__ + '/support/fixtures/templates'
+end
+
+Hanami::Mailer.class_eval do
+ def self.reset!
+ self.configuration = configuration.duplicate
+ configuration.reset!
+ end
+end
+
+Hanami::Mailer::Dsl.class_eval do
+ def reset!
+ @templates = {}
+ end
+end
+
+Hanami::Utils.require!("spec/support")
+
+Hanami::Mailer.configure do
+ root __dir__ + '/support/fixtures'
+ delivery_method :test
+
+ prepare do
+ include DefaultSubject
+ end
+end.load!
diff --git a/spec/support/fixtures.rb b/spec/support/fixtures.rb
new file mode 100644
index 0000000..c7475b0
--- /dev/null
+++ b/spec/support/fixtures.rb
@@ -0,0 +1,105 @@
+class InvoiceMailer
+ include Hanami::Mailer
+ template 'invoice'
+end
+
+class RenderMailer
+ include Hanami::Mailer
+end
+
+class TemplateEngineMailer
+ include Hanami::Mailer
+end
+
+class CharsetMailer
+ include Hanami::Mailer
+
+ from 'noreply@example.com'
+ to 'user@example.com'
+ subject 'こんにちは'
+end
+
+class MissingFromMailer
+ include Hanami::Mailer
+ template 'missing'
+
+ to 'recipient@example.com'
+ subject 'Hello'
+end
+
+class MissingToMailer
+ include Hanami::Mailer
+ template 'missing'
+
+ from 'sender@example.com'
+ subject 'Hello'
+end
+
+User = Struct.new(:name, :email)
+
+class LazyMailer
+ include Hanami::Mailer
+end
+
+class MethodMailer
+ include Hanami::Mailer
+
+ from :sender
+ to :recipient
+ subject :greeting
+
+ def greeting
+ "Hello, #{user.name}"
+ end
+
+ private
+
+ def sender
+ "hello-#{user.name.downcase}@example.com"
+ end
+
+ def recipient
+ user.email
+ end
+end
+
+class WelcomeMailer
+ include Hanami::Mailer
+
+ from 'noreply@sender.com'
+ to ['noreply@recipient.com', 'owner@recipient.com']
+ cc 'cc@recipient.com'
+ bcc 'bcc@recipient.com'
+
+ subject 'Welcome'
+
+ def greeting
+ 'Ahoy'
+ end
+
+ def prepare
+ mail.attachments['invoice.pdf'] = '/path/to/invoice.pdf'
+ end
+end
+
+class MandrillDeliveryMethod
+ def initialize(options)
+ @options = options
+ end
+
+ def deliver!(mail)
+ @options.fetch(:deliveries).push(mail)
+ end
+end
+
+module Users
+ class Welcome
+ include Hanami::Mailer
+ end
+end
+
+module DefaultSubject
+ def self.included(mailer)
+ mailer.subject 'default subject'
+ end
+end
diff --git a/spec/support/fixtures/templates/charset_mailer.txt.erb b/spec/support/fixtures/templates/charset_mailer.txt.erb
new file mode 100644
index 0000000..92dea23
--- /dev/null
+++ b/spec/support/fixtures/templates/charset_mailer.txt.erb
@@ -0,0 +1 @@
+蓮
diff --git a/spec/support/fixtures/templates/invoice.html.erb b/spec/support/fixtures/templates/invoice.html.erb
new file mode 100644
index 0000000..06c5a5a
--- /dev/null
+++ b/spec/support/fixtures/templates/invoice.html.erb
@@ -0,0 +1,5 @@
+
+
+ Invoice template
+
+
diff --git a/spec/support/fixtures/templates/lazy_mailer.html.erb b/spec/support/fixtures/templates/lazy_mailer.html.erb
new file mode 100644
index 0000000..9605ceb
--- /dev/null
+++ b/spec/support/fixtures/templates/lazy_mailer.html.erb
@@ -0,0 +1,5 @@
+
+
+ Hello World!
+
+
diff --git a/spec/support/fixtures/templates/lazy_mailer.txt.erb b/spec/support/fixtures/templates/lazy_mailer.txt.erb
new file mode 100644
index 0000000..179d397
--- /dev/null
+++ b/spec/support/fixtures/templates/lazy_mailer.txt.erb
@@ -0,0 +1 @@
+This is a txt template
diff --git a/spec/support/fixtures/templates/method_mailer.txt.erb b/spec/support/fixtures/templates/method_mailer.txt.erb
new file mode 100644
index 0000000..9c4e98d
--- /dev/null
+++ b/spec/support/fixtures/templates/method_mailer.txt.erb
@@ -0,0 +1 @@
+<%= greeting %>
diff --git a/spec/support/fixtures/templates/missing.txt.erb b/spec/support/fixtures/templates/missing.txt.erb
new file mode 100644
index 0000000..b69a6b1
--- /dev/null
+++ b/spec/support/fixtures/templates/missing.txt.erb
@@ -0,0 +1 @@
+Missin'
diff --git a/spec/support/fixtures/templates/render_mailer.html.erb b/spec/support/fixtures/templates/render_mailer.html.erb
new file mode 100644
index 0000000..00db125
--- /dev/null
+++ b/spec/support/fixtures/templates/render_mailer.html.erb
@@ -0,0 +1 @@
+Hello <%= user.name %>,
diff --git a/spec/support/fixtures/templates/template_engine_mailer.html.haml b/spec/support/fixtures/templates/template_engine_mailer.html.haml
new file mode 100644
index 0000000..2680454
--- /dev/null
+++ b/spec/support/fixtures/templates/template_engine_mailer.html.haml
@@ -0,0 +1,2 @@
+%h1
+ = user.name
diff --git a/spec/support/fixtures/templates/welcome_mailer.html.erb b/spec/support/fixtures/templates/welcome_mailer.html.erb
new file mode 100644
index 0000000..cede28f
--- /dev/null
+++ b/spec/support/fixtures/templates/welcome_mailer.html.erb
@@ -0,0 +1,8 @@
+
+
+
+ Hello World!
+ <%= greeting %>
+ This is a html template
+
+
diff --git a/spec/support/fixtures/templates/welcome_mailer.txt.erb b/spec/support/fixtures/templates/welcome_mailer.txt.erb
new file mode 100644
index 0000000..51015e8
--- /dev/null
+++ b/spec/support/fixtures/templates/welcome_mailer.txt.erb
@@ -0,0 +1,2 @@
+This is a txt template
+<%= greeting %>