What is the RSpec syntax equivalent for assert (minitest) - ruby-on-rails

I am following Michael Hartl's Ruby on Rails tutorial. I observe that he used minitest to run his tests. I use RSpec. Below is a line of code from the tutorial I want to replicate with RSpec
test "email validation should accept valid addresses" do
valid_addresses = %w[user#example.com USER#foo.COM A_US-ER#foo.bar.org
first.last#foo.jp alice+bob#baz.cn]
valid_addresses.each do |valid_address|
#user.email = valid_address
assert #user.valid?, "#{valid_address.inspect} should be valid"
end
end
This is how I will do this in with RSpec.
it "email validation should accept valid addresses" do
valid_addresses = ["user#example.com", "USER#foo.COM", "A_US-ER#foo.bar.org",
"first.last#foo.jp", "alice+bob#baz.cn"]
valid_addresses.each do |valid_address|
user.email = valid_address
expect(#user.valid?).to be true, "#{valid_address.inspect} is not correct"
end
end
However, I get Argument error when I run this test. It appears RSpec expects only one argument in test cases.

RSpec thinks that you're passing a single argument to the to method and two arguments to the be method, and hence it's giving you an error. It's seeing your statement as:
expect(#user.valid?).to(be(true, "#{valid_address.inspect} is not correct"))
So, you can change your spec to be the following, and it should work:
expect(#user.valid?).to be(true), "#{valid_address.inspect} is not correct"
Here, RSpec is seeing two arguments being passed to the to method, which is valid.

What exactly is the error message you are getting. It looks like you have a typo. Should
user.email = valid_address
be
#user.email = valid address
You're providing 2 arguments and the expect statement takes one.
expect(#user.valid?).to be true

Related

assert / assert_not in ruby

when do we use assert and asert_not in ruby on rails tests, what's the difference between the to?
Example:
test 'email should not be too long' do
#user.email = 'a' * 244 + '#example.com'
assert_not #user.valid?
end
test 'email validation should accept valid addresses' do
valid_addresses = %w[user#example.com USER#foo.COM A_US-ER#foo.bar.org
first.last#foo.jp alice+bob#baz.cn]
valid_addresses.each do |valid_address|
#user.email = valid_address
assert #user.valid?, "#{valid_address.inspect} should be valid"
end
end
Use assert_not when you expect the result to be false.
https://apidock.com/rails/ActiveSupport/Testing/Assertions/assert_not
Use assert when you expect the result to be true.
https://docs.ruby-lang.org/en/2.1.0/Test/Unit/Assertions.html

Hartl Rails Tutorial: upcase-ing email address in user_test

I'm about halfway through the Rails tutorial (excellent, btw), and have a little question. Is there a reason that this test uses duplicate_user.email = #user.email.upcase and not the more succinct duplicate_user.email.upcase ?
Here is the full test.
test "email addresses should be unique" do
duplicate_user = #user.dup
duplicate_user.email = #user.email.upcase
#user.save
assert_not duplicate_user.valid?
end
As far as I can tell, the test performs correctly doing it either way.
I'm not familiar with the tutorial but you seem to be asking why the test is not written as:
test "email addresses should be unique" do
duplicate_user = #user.dup
duplicate_user.email.upcase
#user.save
assert_not duplicate_user.valid?
end
In this case, the line duplicate_user.email.upcase will just return the upcased email. It will not affect the attribute on the object. The test still passes because the duplicate_user has the same email address as the original #user, satisfying the test spec that email addresses should be unique.
What the test is actually doing is verifying that the code recognises an upcased email to be the same as a downcased email. In such a case, the original line in the test has the effect of assigning to the email attribute of the duplicate_user an upcased version of the email address.

Rails code validation working but Rspec tests failing

Can anyone see what's wrong about the Rspec? All of my tests for invalid emails are failing (i.e., they are supposed to not be valid but somehow are in Rspec), but in the actual code, it works fine, no emails that are bad are allowed. The validation even works in my console....
Two notes:
I realize the formatting isn't ideal... will work on that later. This was just me writing things individually without going through and DRYing it up yet.
I also realize there exists an easier way to validate these things individually in the model, but I wanted very custom messages without any reference to the attribute, and I disliked the roundabout way that I've read that needs to be done.
Model code
validate :create_validation, on: :create
def create_validation
errors[:base] << "Please enter a valid email address to continue" if self.email.blank? || (( /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i =~ self.email) == nil)
end
#The RegEx is from Michael Hartl's tutorial
Spec code
describe Signup do
before do
#signup = FactoryGirl.create(:signup)
end
subject { #signup }
describe "email tests" do
describe "invalid tests" do
# blank email
before { #signup.email = " " }
it { should_not be_valid }
# invalid format email
addresses = %w[user#foo..com, user#foo,com user_at_foo.org example.user#foo. foo#bar_baz.com foo#bar+baz.com]
addresses.each do |invalid_address|
before { #signup.email = invalid_address }
it { should_not be_valid }
end
end
end
end
Factory girl code in spec helper
FactoryGirl.define do
factory :signup do |f|
f.email { Faker::Internet.email }
#... other attributes
end
end
As I understood code you validate only on create! But in tests you created object in before block and it is persisted in your tests - so validation is skipped.
Try this variant
describe Signup do
before do
#signup = FactoryGirl.build(:signup)
end
subject { #signup }
describe "email tests" do
describe "invalid tests" do
# blank email
before { #signup.email = " " }
it { should_not be_valid }
# invalid format email
addresses = %w[user#foo..com, user#foo,com user_at_foo.org example.user#foo. foo#bar_baz.com foo#bar+baz.com]
addresses.each do |invalid_address|
before { #signup.email = invalid_address }
it { should_not be_valid }
end
end
end
end
I hope validation will be triggered for built but not saved record.
PS Or you can remove option on: :create

RSpec failling in email should not be valid

I'm new to all this rails/rspec and so on, so im trying to follow some tests that I had found in the project that i'm working and make sense, they were generated by scaffold but the app is very different and no tests were updated so im re-doing every test.
The problem is when I try to validate that invalid emails should make the user invalid it fails.
I know that it's ok because I already done tests and they pass without no problem.
It is possible that I'm looking at this the wrong way but ...
User_spec
describe "when email format is invalid" do
it "should be invalid" do
addresses = %w[user#foo,com user_at_foo.org example.user#foo.
foo#bar_baz.com foo#bar+baz.com]
addresses.each do |invalid_address|
#user.email = invalid_address
#user.should_not be_valid
end
end
end
User_test
test "fail save new user with an corrupt email" do
user = User.new
user.name = 'Someone Name'
user.password = '12345678'
user.email = 'Someone Name#gmail..com'
assert !user.save , "User was saved with an corrupt email"
end
The validation is done by devise and the failure message is "expected valid? to return false, got true"
---- edit ---
My user setup
...
describe User do
before :each do
#user = User.new(name: "Name of Names", email:"someone1#somewhere.com",password: "foobarfoobar", password_confirmation: "foobarfoobar" )
end
...
You could do something along the lines of this:
context "validations" do
describe "email" do
subject { FactoryGirl.create(:user, email: email) }
context "with an valid address" do
let(:email) { "valid#email.com" }
it { should be_valid }
end
context "with an invalid email address" do
let(:email) { "invalid.email.com" }
it { should_not be_valid }
end
end
end
So I'm assuming you are using FactoryGirl to create an valid user object. Just create new tests per invalid email, this way you can see which tests are passing and which aren't. Then you could TDD your way to green.

Rails Tutorial Rspec misunderstanding

The listing 6.20 of Michael Hartl's rails tutorial shows the following code:
before do
#user = User.new(name: "Example User", email: "user#example.com")
end
.
.
.
describe "when email address is already taken" do
before do
user_with_same_email = #user.dup
user_with_same_email.email = #user.email.upcase
user_with_same_email.save
end
it { should_not be_valid }
end
I am having trouble grasping this concept because #user.dup returns a representation of the exact same object, which is copied over to user_with_same email, but #user was never saved into the database anywhere in the file. Therefore, the user_with_same_email.save test should be valid every time. However, the test passes. Someone please explain this... is there an implicit database save on #user = User.new(...)? I know if it was User.create(...) there would be a save, but not for the new method. Thanks!
You're not missing an implicit save.
user_with_same_email does save correctly (personally I would always use save! to be sure it was not failing silently)
What the spec is speccing is that the subject (ie #user) cannot be saved, because of the existance of a row in the database with the same email.

Resources