How to test rails’ action mailer with rspec?

mailer

# app/mailers/notice_mailer.rb
class NoticeMailer < ApplicationMailer
  def welcome(*args)
    @status = args[0]
    mail(to: ENV['MAILER_TO'], subject: subject(@status))
  end

  def subject(status)
    subject = 'Welcome!'
    if status == 'success'
      subject = '[Success]#{subject}'
    elsif status == 'failure'
      subject = '[Failure]#{subject}'
    end
    subject
  end
end

spec

# spec/mailers/notice_spec.rb
require 'rails_helper'
RSpec.describe 'Notice' do
  describe 'Test mail notice feature' do
    let(:subject) { 'Title' }
    let(:from) { ENV['MAILER_FROM'] }
    let(:to) { ENV['MAILER_TO'] }
    let(:content_type) { ["text/plain; charset=UTF-8", "text/html; charset=UTF-8"] }

    context 'When success' do
      before do
        @status = 'success'
        @mail = NoticeMailer.welcome(@status)
      end

      it 'Title is right' do
        expect(@mail.subject).to eq "[Success]#{subject}"
      end

      it 'From is right' do
        expect(@mail.from).to eq [from]
      end

      it 'To is right' do
        expect(@mail.to).to eq [to]
      end

      it 'Content include success' do
        expect(@mail.body.encoded).to include 'success'
      end

      it 'Content type is right' do
        expect(@mail.body.parts.collect(&:content_type)).to eq content_type
      end
    end

    context 'When failure' do
      before do
        @status = 'failure'
        @mail = NoticeMailer.welcome(@status)
      end

      it 'Title is right' do
        expect(@mail.subject).to eq "[Success]#{subject}"
      end

      it 'From is right' do
        expect(@mail.from).to eq [from]
      end

      it 'To is right' do
        expect(@mail.to).to eq [to]
      end

      it 'Content include failure' do
        expect(@mail.body.encoded).to include 'failure'
      end

      it 'Content type is right' do
        expect(@mail.body.parts.collect(&:content_type)).to eq content_type
      end
    end
  end
end

How to upload and download file with AWS S3?

Programming Language

ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]

Framework

Rails 4.2.0

aws-sdk

gem 'aws-sdk', '~> 1.64.0'

set aws config

# config/initializers/aws.rb
AWS.config(
  access_key_id: ENV['ACCESS_KEY_ID'],
  secret_access_key: ENV['SECRET_ACCESS_KEY']
)

set autoload_paths for rails

# config/application.rb
config.autoload_paths << Rails.root.join('lib')                                                                                                                                 config.autoload_paths << Rails.root.join('lib/module')

make a s3 module

# lib/module/s3_module.rb
require 'aws-sdk'

module S3Module
  @s3 = AWS::S3.new
  @bucket = @s3.buckets[ENV['S3_BUCKET_NAME']]

  module_function

  def upload_file
    path = '/your/upload_file/path'
    Dir.glob(path + 'test.*').each do |file|
      basename = File.basename(file)
      send_result = @bucket.objects[basename]
      send_result.write(file: file)
    end
  end

  def download_file
    path = '/your/download_file/path'
    @bucket.objects.each do |object|
      file_path = path + object.key
      File.open(file_path, 'wb') do |file|
        object.read do |chunk|
          file.write(chunk)
        end
      end
      File.chmod(0777, file_path)
    end
  end

  def delete_file(filename)
    object = @bucket.objects[filename]
    object.delete
  end

  def exists_file(filename)
    object = @bucket.objects[filename]
    p object.exists?
  end
end

prepare test files

# under you upload_file path
test.txt
test.pdf

run rails runner

$ rails runner "S3Module.upload_file"
$ rails runner "S3Module.download_file"
$ rails runner "S3Module.delete_file('text.txt')"
$ rails runner "S3Module.exists_file('test.pdf')"

How to test thor with rspec on rails?

What is thor?

http://whatisthor.com

Make a batch with thor

lib/tasks/my_task.rb
require 'thor'
module Tasks
  class MyTask < Thor
    desc 'hello', 'world'
    option :date
    def hello(name)
      puts "Hello #{name} on #{options[:date]}"
    end
  end
end

How to test it?

/spec/lib/tasks/my_task_spec.rb
require 'rails_helper'
describe 'Run batch' do
  it 'should be run' do
    expect(capture(:stdout){
      Tasks::MyTask.new.invoke(:hello, ['tom'], {date: '20150626')
    }.strip).to eq 'Hello tom on 20150626'
  end
end

Resources

Ruby with AWS notes

gem

Official Docs

Questions

How to test rake task with rspec?

A module

# lib/module/s3_module.rb
require 'aws-sdk'

module S3Module
  module_function
  def send_file_to_s3
    # TODO
  end
end

Make a rake task

$ rails g task s3

Write task

# lib/tasks/s3.rake
require 'module/s3_module'

namespace :s3 do
  desc "Send file to S3"
  task :send_file => [:environment] do
    S3Module.send_file_to_s3
  end
end

Write rspec test

# spec/lib/tasks/s3_spec.rb
require 'rails_helper'
require 'rake'

describe "s3:send_file" do
  before(:all) do
    @rake = Rake::Application.new
    Rake.application = @rake
    Rake.application.rake_require 'tasks/s3'
    Rake::Task.define_task(:environment)
  end

  before(:each) do
    @rake[task].reenable
  end

  describe 'send_file_to_s3' do
    let(:task) { 's3:send_file'}

    it 'should success' do
      expect(S3Module).to receive(:send_file_to_s3)
      @rake[task].invoke
    end
  end
end

Resource

http://dev.classmethod.jp/server-side/ruby-on-rails/ruby-on-rails_rspec_rake_test/

How to use thor to run `rails runner` with parameters?

Add thor to Gemfile

gem 'thor'

Install thor

bundle install

Make a tast under lib/tasks folder

touch lib/tasks/my_task.rb

How to do?

require 'thor'

module Tasks
  class MyTask < Thor
    desc "hello NAME", "say hello to NAME"
    option :from
    def hello(name)
      p 'hello:' + name.to_s
      p 'from:' + options['from'].to_s
      # It can access Active Record, too.
      products = Product.all
      p 'products:' + products.inspect.to_s
    end
  end
end

Tasks::MyTask.start(ARGV)

How to run?

./bin/rails runner MyTask hello A --from B