This article will cover creating integration tests using Rails 6 Active Storage. It will include the create and edit actions.
Scaffold out the model.
$ rails g scaffold Profile name:string
Update the model/profile.rb to include a profile picture.
class Profile < ApplicationRecord
has_one_attached :profile_picture
end
Update the views/profiles/_form.html.erb to include a input for the profile picture.
<div class="field">
<%= form.label :profile_picture %>
<%= form.file_field :profile_picture %>
</div>
Update the controllers/profile_controller.rb to allow for the profile_picture params.
def profile_params
params.require(:profile).permit(:name, :profile_picture)
end
Add the integration test settings to test_helper.rb.
require 'capybara/minitest'
class ActionDispatch::IntegrationTest
# Make the Capybara DSL available in all integration tests
include Capybara::DSL
# Make `assert_*` methods behave like Minitest assertions
include Capybara::Minitest::Assertions
def setup
Capybara.default_driver = :selenium_chrome_headless
Capybara.default_max_wait_time = 5
end
# Reset sessions and driver between tests
# Use super wherever this method is redefined in your individual test classes
def teardown
Capybara.reset_sessions!
Capybara.use_default_driver
Capybara.default_max_wait_time = 2
end
end
Create a file called test/integration/profile_integration_test.rb and add the first test to create a profile. Remember to add a picture called picture_one.jpg to the test directory.
# frozen_string_literal: true
require 'test_helper'
class ProfileIntegrationTest < ActionDispatch::IntegrationTest
test 'that a profile can be created' do
visit new_profile_path
fill_in "Name", with: 'Jane Doe'
find(:css, '#profile_profile_picture').set(File.join(Rails.root + "test", 'picture_one.jpg'))
click_button 'Create Profile'
assert_current_path profile_path(Profile.order("created_at").last)
assert_equal ActiveStorage::Attachment.count, 1
end
end
Add a fixture to test/fixtures/profile.yml to represent the profile.
remove_existing_profile_picture:
name: 'Jane Doe'
We need to add an attribute to the model which we can use to determine if the profile picture should be removed or not.
class Profile < ApplicationRecord
has_one_attached :profile_picture
attr_accessor :remove_existing_profile_picture
end
Update the controller to allow for the new parameter.
def profile_params
params.require(:profile).permit(:name, :profile_picture, :remove_existing_profile_picture)
end
Update the form to show the remove profile picture checkbox, but only if a picture is attached.
<% if profile.profile_picture.attached? %>
<%= form.label :remove_existing_profile_picture %>
<%= form.check_box :remove_existing_profile_picture %>
<% end %>
Update the controller to check for the remove_existing_profile_picture and remove the profile picture.
def update
if profile_params[:remove_existing_profile_picture] == "1"
@profile_picture = @profile.profile_picture
@profile_picture.purge_later
end
...
end
Add the integration test to remove the profile picture.
test 'that a profile picture can be removed ' do
profile = profiles(:remove_existing_profile_picture)
profile.profile_picture.attach(
io: File.open(File.join(Rails.root + "test", 'picture_one.jpg')),
filename: 'picture_one.JPG', content_type: 'image/jpeg'
)
profile.save!
visit edit_profile_path(profile)
find(:css, "#profile_remove_existing_profile_picture").set(true)
click_button 'Update Profile'
assert_equal ActiveStorage::Attachment.count, 0
end