undefined method `valid?` for "possimus":String - ruby-on-rails

Tested code:
context 'validations' do
let(:super_campaign){FactoryGirl.create(:super_campaign)}
context 'package' do
it "Package should be present" do
expect(super_campaign.package).to be_valid
end
end
end
I am getting error like undefined method "valid?" for "possimus":String

expect(super_campaign).to be_valid # AR object, not it's attribute

You can only test that the whole model is valid. You can test if you have an error for the package attribute, though.
context 'validations' do
let(:super_campaign){FactoryGirl.create(:super_campaign)}
context 'package' do
it "Package should be present" do
expect(super_campaign).to be_valid
expect(super_campaign.errors[:package]).to be_nil
end
end
end

Related

Rspec.Undefined method `valid?' for :user:Symbol

I try to create test for users-factories.But when I running test, 'rspec' show me an error
Failure/Error: expect(:user).to be_valid
NoMethodError:
undefined method `valid?' for :user:Symbol
this is my user_spec.rb
require 'rails_helper'
RSpec.describe do
it "has a valid factory" do
user = FactoryGirl.create(:user)
expect(:user).to be_valid
end
end
and this is users-factories(with 'faker' gem)
FactoryGirl.define do
factory :user do
email Faker::Internet.email
password Faker::Internet.password(8)
end
end
how fix and why this method don't work?
sorry for my bad English
Here is a fix :
RSpec.describe do
it "has a valid factory" do
user = FactoryGirl.create(:user)
expect(user).to be_valid
end
end
You passed the symbol :user as an argument to the expect(:user), which you shouldn't. You should pass the local variable user, you have created, and passed to it expect(user).

getting started with rspec in rails

I'm trying to write a spec for a Student class. So far it's simple; it only has a first name and a last name. I need to make sure both those fields aren't blank. I have this so far:
describe Student do
context "is valid" do
before do
#student = Student.new
end
it "should have a first name" do
expect(student).not_to be_valid
end
it "should have a last name" do
expect(student).not_to be_valid
end
end
end
When I run the tests it says student is an undefined local variable for both of them. Why does the before not work?
Because #student is an instance variable, and RSpec does not create attributes automagically. If you want to use student instead of #student, use let:
describe Student do
context "is valid" do
let(:student) { Student.new }
it "should have a first name" do
expect(student).not_to be_valid
end
it "should have a last name" do
expect(student).not_to be_valid
end
end
end
Related documentation: http://www.betterspecs.org/#let

Rspec/Capybara cant find my model when trying to use "should_not change"

I am trying to verify that the validators are working correctly on my model, and for that I am using Rspec and Capybara. Here is my code.
describe "#when registering" do
before { visit new_record_path }
describe "#with invalid information" do
describe "#should not modify database" do
subject { -> { click_button submit } }
it { should_not change(Pet, :count) }
it { should_not change(Owner, :count) }
end
end
end
end
When I run the specs, i get an error: "undefined method 'model_name' for NilClass:Class"
What could be causing rspec to think my model is nil?
Thanks!
You should not test your validations with a feature/acceptance test, it should be with a model test. Then for each form you could test an error is raised if something is invalid instead of testing every error through acceptance tests. For each model it should be something like so:
describe Pet do
describe "validations" do
# These can echo any model validation
it "is invalid if attribute is not present" do
Pet.new(:attribute => "Invalid Item").should_not be_valid
end
end
end
or with Factory Girl:
describe Pet do
describe "validations" do
it "is invalid if attribute is not present" do
build(:pet, :attribute => "Invalid Item").should_not be_valid
end
end
end
Then in an acceptance test you can have something like:
it "displays an error if validation fails" do
visit new_pet_path
#Something to make the form submission fail, not everything
fill_in("Attribute", :with => "")
click_button("Create Pet")
page.should have_content("can't be blank")
current_path.should == pets_path
end
This will help to keep your acceptance tests light and test the validations in the model where it belongs. Hope this helps!

Reusing RSpec behavior validation

In my Rails 3 application, I have a RSpec spec that checks behavior of a given field (role in the User model) to guarantee that the value is within a list of valid values.
Now I am going to have the exact same spec for another field, in another model with another set of valid values. I would like to extract the common code instead of merely copying and pasting it, changing the variables.
I am wondering if this would be the case to use a shared example or other RSpec reuse technique.
Here's the relevant RSpec code:
describe "validation" do
describe "#role" do
context "with a valid role value" do
it "is valid" do
User::ROLES.each do |role|
build(:user, :role => role).should be_valid
end
end
end
context "with an empty role" do
subject { build(:user, :role => nil) }
it "is invalid" do
subject.should_not be_valid
end
it "adds an error message for the role" do
subject.save.should be_false
subject.errors.messages[:role].first.should == "can't be blank"
end
end
context "with an invalid role value" do
subject { build(:user, :role => 'unknown') }
it "is invalid" do
subject.should_not be_valid
end
it "adds an error message for the role" do
subject.save.should be_false
subject.errors.messages[:role].first.should =~ /unknown isn't a valid role/
end
end
end
end
What would be the best case to reuse this code, but extracting role (the field being verified) and User::ROLES (the collection of valid values) into parameters being passed to this code?
I think this is a perfectly reasonable use case for shared examples. e.g. something like this:
shared_examples_for "attribute in collection" do |attr_name, valid_values|
context "with a valid role value" do
it "is valid" do
valid_values.each do |role|
build(:user, attr_name => role).should be_valid
end
end
end
context "with an empty #{attr_name}" do
subject { build(:user, attr_name => nil) }
it "is invalid" do
subject.should_not be_valid
end
it "adds an error message for the #{attr_name}" do
subject.save.should be_false
subject.errors.messages[attr_name].first.should == "can't be blank"
end
end
context "with an invalid #{attr_name} value" do
subject { build(:user, attr_name => 'unknown') }
it "is invalid" do
subject.should_not be_valid
end
it "adds an error message for the #{attr_name}" do
subject.save.should be_false
subject.errors.messages[attr_name].first.should =~ /unknown isn't a valid #{attr_name}/
end
end
end
Then you can call it in your specs like this:
describe "validation" do
describe "#role" do
behaves_like "attribute in collection", :role, User::ROLES
end
end
Haven't tested this but I think it should work.
You can DRY your spec with shared_examples technic this way:
shared_examples "no role" do
it "is invalid" do
subject.should_not be_valid
end
end
context "with an empty role" do
subject { Factory.build(:user, :name => nil) }
it_behaves_like "no role"
end
context "with an invalid role value" do
subject { Factory.build(:user, :name => '') }
it_behaves_like "no role"
end
But what about your idea to DRY few specs..I think it's too much. I'm convince that spec has to be readable firstly and only then DRY'ing. If you DRY few specs, it will be probably a headache for future reading/refactoring/changing this code.

Trouble on specifying explicit 'subject's?

I am using Ruby on Rails 3.0.9 and RSpect 2. I am trying to refactoring some spec file in the following way (in order to test with less code similar User class object attribute values):
describe User do
let(:user1) { Factory(:user, :users_attribute_a => 'invalid_value') }
let(:user2) { Factory(:user, :users_attribute_b => 'invalid_value') }
let(:user3) { Factory(:user, :users_attribute_c => 'invalid_value') }
it "foreach user" do
[ user1, user2, user3 ].each do |user|
subject { user }
it "should be whatever"
user.should_not be_valid
...
end
end
end
end
However, if I run the above test I get the following error:
Failure/Error: it "should be whatever" do
NoMethodError:
undefined method `it' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_2::Nested_2:0x00000106ccee60>
What is the problem? How can I solve that?
UPDATE after the #Emily answer.
If in the above code I use context "foreach user" do ... instead of it "foreach user" do ... I get the following error:
undefined local variable or method `user1' for #<Class:0x00000105310758> (NameError)
The problem is having one spec nested within another. You need to replace it "foreach user" with context "foreach user".
Edited to add: After some investigation, it looks like helpers set with let are only available inside of the it "should ..." block, and not in the surrounding context. I'd recommend is trying to find a different structural solution. What the best solution is will depend on what you're actually trying to test. I'm guessing what you're trying to do is make sure the user is invalid when you remove any of the required attributes. In that case, what I've done is something like this:
describe User do
let(:user_attributes){ Factory.attributes_for(:user) }
# Testing missing values aren't valid
[:name, :email, :phone].each do |required_attribute|
it "should not be valid without #{required_attribute}" do
User.new(user_attributes.except(required_attribute)).should_not be_valid
end
end
# Testing invalid values aren't valid
[[:email, 'not_an_email'], [:phone, 'not a phone']].each do |(attribute, value)|
it "should not be valid with bad value for #{attribute}" do
User.new(user_attributes.update(attribute => value)).should_not be_valid
end
end
end
If you're doing something that requires more complex differences in the instance you're creating, there may not be a clean way to do it with iteration. I don't think DRY is quite as essential in testing as it is in other parts of your code. There's nothing wrong with having three different contexts for the three user types, and a validity test in each context.
describe User do
context "with user1" do
subject{ Factory(:user, :users_attribute_a => 'invalid_value') }
it{ should_not be_valid }
end
context "with user2" do
subject{ Factory(:user, :users_attribute_b => 'invalid_value') }
it{ should_not be_valid }
end
context "with user3" do
subject{ Factory(:user, :users_attribute_c => 'invalid_value') }
it{ should_not be_valid }
end
end
You're mixing and matching all sorts of rspec stuff. Here's your stuff, fixed:
describe User do
let(:user1) { Factory(:user, :users_attribute_a => 'invalid_value') }
let(:user2) { Factory(:user, :users_attribute_b => 'invalid_value') }
let(:user3) { Factory(:user, :users_attribute_c => 'invalid_value') }
it "should not be valid" do
[ user1, user2, user3 ].each do |user|
user.should_not be_valid
end
end
end
I would do it this way:
describe User do
subject{Factory.build(:user)}
it "should not be valid with invalid users_attribute_a" do
subject.users_attribute_a = "invalid_value"
subject.should_not be_valid
end
it "should not be valid with invalid users_attribute_b" do
subject.users_attribute_b = "invalid_value"
subject.should_not be_valid
end
end
If you want to have "context", then cool, but you can't have variables before your context inside of your context.
If you want to have a specification, then have one, but you can't net "it" statements
UPDATE WITH LEAST POSSIBLE CODE
describe User do
it "should not be valid with other attributes" do
{:users_attribute_a => 'invalid_value', :users_attribute_b => 'invalid_value', :users_attribute_c => 'invalid_value'}.each do |key, value|
Factory.build(:user, key => value).should_not be_valid
end
end
end
The problem is that the helpers that are set with "let" do not exist outside of a example context.
What you're trying to do could be achieved as:
it "does something with all users" do
[user1, user2, user3] do |user|
user.valid?.should be_true
end
end
Both contexts are different
Another way it might work (haven't tried it) it's like this:
context "for all users" do
[:user1, :user2, :user3].each do |user|
it "does something" do
send(user).valid?.should be_true
end
end
end
This should work. Note how the context is written, it will make the output of tests clearer. From writing it this way it implies (to me) that you should make a test for each attribute separately, but it's your choice:
describe User do
let!(:users) {
[:users_attribute_a, :users_attribute_b, :users_attribute_c].map do |a|
Factory(:user, => 'invalid_value')
end
}
context "Given a user" do
context "With an invalid value" do
subject { users }
it { subject.all?{|user| should_not be_valid }
end
end
end

Resources