Rails 6 all validate_presence_of tests fail - ruby-on-rails

they fail with: unitialized constant ActiveModel::SecurePassword::InstanceMethodsOnActivation
I'm trying to update a rails 5.2 app to the rails 6 beta, and everything seems to be working fine except for my validate_presence_of specs.
For example
RSpec.describe Post, type: :model do
context 'validations' do
subject { Post.new(body: Faker::Movie.quote)}
it { should validate_presence_of :body }
it { should validate_length_of(:body).is_at_most(5000).on(:create) }
end
end
the validate_length_of passes fine, and the validate_presence of does not. Posts do belong to a user that inherits from a Clearance::User, but I'm not sure why the constant would vary on different tests for the same model?

I've made this work.
There's a Pull Request to shoulda_matchers here:
https://github.com/thoughtbot/shoulda-matchers/pull/1169
Until the shoulda_matchers team merge it, use my version here:
https://github.com/morsedigital/shoulda-matchers
In your Gemfile:
gem 'shoulda-matchers', groups: [:test], git: 'https://github.com/morsedigital/shoulda-matchers'

Turns out this is a bug with shoulda-matchers.
https://github.com/thoughtbot/shoulda-matchers/issues/1167

In my case this was quick fix:
# spec/rails_helper.rb - add to bottom
class ActiveModel::SecurePassword::InstanceMethodsOnActivation; end;

Related

undefined method `file_fixture_path' after upgrade to ruby 3 and rails 6.1

After upgrade to ruby 3 and rails 6.1 my tests break on the line
subject.avatar.attach(fixture_file_upload(Rails.root.join('spec', 'fixtures', 'images', 'avatar.jpg')))
with:
NoMethodError:
undefined method `file_fixture_path' for RSpec::Rails::FixtureFileUploadSupport::RailsFixtureFileWrapper:Class
Did you mean? fixture_path
the error stack points to
webmock-3.11.0/lib/webmock/rspec.rb:37
Any suggestions how to debug it?
Ran into the same error, but had to solve it differently as the post in a request spec doesn't accept the object returned by file_fixture.
Including include ActionDispatch::TestProcess::FixtureFile in my request solved it for me.
RSpec.describe "Attachments", type: :request do
include Rack::Test::Methods
include ActionDispatch::TestProcess::FixtureFile
#...
expect {
file = fixture_file_upload("image.jpg", "image/jpeg", :binary)
post collection_work_attachments_path(collection, work), {attachment: {file: file, name: image_name, visibility: [:admin]}}
}.to change(Attachment, :count).by(1)
#...
end
Anything above didn't worked for me, but I found another solution.
In the factory changed this:
photo { fixture_file_upload(Rails.root.join('spec/support/images/test_image.png'), 'image/png') }
to this:
photo { Rack::Test::UploadedFile.new('spec/support/images/test_image.png', 'image/png') }
But after that I faced with another error:
unknown attribute 'service_name' for ActiveStorage::Blob
And solved this with two commands:
rails active_storage:update
rails db:migrate
I hope this may be useful to anybody.
Adding the following initializer addresses the issue without potential side-effects of including the ActionDispatch::TestProcess::FixtureFile module.
# config/initializers/rspec.rb
module RSpec
module Rails
module FixtureFileUploadSupport
class RailsFixtureFileWrapper
class << self
attr_accessor :file_fixture_path
end
end
end
end
end
This is how the issue is actually fixed by RSpec maintainers. As of the date of this post, the patch is not yet released.
I was having the same issue for a long time and kept landing on this SO answer. My problem was that in a lot of my specs, one of my FactoryBot factories was calling fixture_file_upload and nothing suggested here fixed the issue.
I went into the ActionDispatch code and found that in the ActionDispatch::TestProcess::FixtureFile module's fixture_file_upload method, the factory object was queried for its fixture_path attribute, which it doesn't have. This is why the answer by #murb will work if your fixture_file_upload is within a spec file, but not in a factory file. For me, the answer was to add the following code to spec/support/factory_bot.rb in my Rails project:
FactoryBot::SyntaxRunner.instance_eval do
def fixture_path
File.absolute_path('spec/fixtures/files')
end
def file_fixture_path
'spec/fixtures/files'
end
end
Note that the second method (file_fixture_path) is to silence the warning in ActionDispatch::TestProcess::FixtureFile#fixture_file_upload.
I hope this helps someone, took me and another engineer a couple of days to land on this solution.
After changing to file_fixture it works just fine relishapp.com/rspec/rspec-rails/v/3-8/docs/file-fixture

Shoulda matcher `validate_length_of` in RSpec with Reform form

I'm setting up specs for my forms (using Reform gem) with RSpec and Shoulda Matchers gems. I'cant figure out why I'm having validation issues.
My actual configurations :
ruby '2.5.1'
gem 'rails', '~> 5.2.0'
gem 'rspec-rails', '~> 3.8'
gem 'shoulda-matchers', '~> 4.0'
gem 'reform-rails', '~> 0.1'
I've already tried different sorts of length validations in my form. But nothing make things much better.
Here is the minimal form used for testing :
# frozen_string_literal: true
class UserForm < Reform::Form
# == Properties ==========================================================
property :nickname
# == Validations ==========================================================
validates :nickname, presence: true, length: { minimum: 3, maximum: 100 }
end
Here is the spec :
# frozen_string_literal: true
RSpec.describe UserForm, type: :model do
subject { described_class.new(User.new) }
it { is_expected.to validate_presence_of :nickname }
it { is_expected.to validate_length_of(:nickname).is_at_least(3).is_at_most(100) }
end
Note that the validate_presence_of matcher works perfectly.
I'm having as RSpec output :
1) UserForm should validate that the length of :nickname is between 3 and 100
Failure/Error: it { is_expected.to validate_length_of(:nickname).is_at_least(3).is_at_most(100) }
Expected UserForm to validate that the length of :nickname is between
3 and 100, but this could not be proved.
After setting :nickname to ‹"xxx"›, the matcher expected the
UserForm to be valid, but it was invalid instead, producing these
validation errors:
* nickname: ["is too short (at least 3 characters)"]
I'm obviously excepting to make these sorts of validations working.
I hope I can find help here :)
Reform is known not to work with shoulda-matchers. Basically, all of the model matchers in shoulda-matchers work by:
Making a new instance of the class under test.
Setting attributes on that instance.
Calling validate on that instance.
Reading any possible validation errors from errors.
However, Reform doesn't work this way; you don't set properties on the form object individually and then call valid?, you call validate with the properties you want to set on the form object, and then those properties are validated in the process of being set. So that's likely why you're getting this error — because shoulda-matchers is trying to manually set the properties, and then validate is blowing them away.
Unfortunately, there's not a way to get shoulda-matchers to work with Reform without writing some kind of adapter. We don't plan on adding this to the gem any time soon but we will take a PR! Other than this, apparently the Reform team was talking about making some RSpec matchers in the spirit of shoulda-matchers, but I'm not sure how much progress has been made there, if any.
Sorry I couldn't be more helpful :/

rails 4 RSpec test validations

It looks like you used to be able to write RSpec tests with the following syntax
it { should validate_presence_of :privacy }
However I'm receiving the following error
error undefined method `validate_presence_of' for #<RSpec::ExampleGroups::Review:0x007fd819c1bdc8>
I can write tests the following way but the above syntax is much simpler
it "should require privacy" do
expect(FactoryGirl.build(:review, privacy: "")).to_not be_valid
end
Is there a 1 liner to test validations using Rails 4.2 and rspec-rails 3.0? I feel like I'm missing something...
Yes there is:
it { is_expected.not_to be_valid }
You can read all about it at Relish
Edited to add clarification:
This assumes the subject is either explicitly stated, like
subject{ FactoryGirl.build(:wiget) }
or is able to be inferred.

How to test for mass assignment errors in Rspec and Rails 4?

I recently upgraded my Rails app from Rails 3 to 4 and this Rspec test is no longer passing:
# spec/models/user_spec.rb:
require 'spec_helper'
describe User do
it "should not allow access to admin" do
expect do
User.new(:admin => true)
end.to raise_error(ActiveModel::MassAssignmentSecurity::Error)
end
end
I am getting this error:
Failure/Error: end.to raise_error(ActiveModel::MassAssignmentSecurity::Error)
NameError: uninitialized constant ActiveModel::MassAssignmentSecurity
I suspect that this is somehow due to the switch to Rails 4's strong parameters.
How can I test for mass assignment errors now?
Thanks for any help.
As Baldrick pointed out rightly there's no need in Rails 4 to test for mass assignment issues in Rspec model tests. The whole idea of Rails 4's Strong Parameters is to move all that functionality to the controller.
To make your test pass you need add config.active_record.mass_assignment_sanitizer = :strict to
config/aplication.rb and add gem https://github.com/rails/protected_attributes to Gemfile.
If you want test strong parameters read this article http://pivotallabs.com/rails-4-testing-strong-parameters/

Remarkable active record association

i'm using gem Remarkable activerecord for association. i've installed remarkable and remarkable activerecrod both gem. i've added both gem in my Gemfile. i've added "remarkable_activerecord" as required in spec_helper.rb.
describe Authentication do
FactoryGirl.build(:authentication).should belong_to(:user)
end
i got error:
Authentication
Failure/Error: it { should belong_to(:user) }
NoMethodError:
undefined method `belong_to' for #
what should be done now..?? thanks in advance
You need to define what it refers to by including subject { something } right above the test example.
You are missing some RSpec syntax. In order to use the "should" assertion, it has to be within an "it" or "specify" block. There are a number of different ways you can do this, but here's one concise way:
describe Authentication do
subject { FactoryGirl.build(:authentication) }
it { should belong_to(:user) }
end

Resources