I am a newbie in Ruby and I have a problem with if condition and page.should have when I programmed the A/B Test for log in function.
This is my code:
if (page.should have_css("body.bg-b")) || (page.should have_css("body.bg-c"))
#do something
else
#do something
end
It works fine in the if condition. My problem is in the case the page doesn't have bg-b or bg-c, it should go to else condition, right, but it stopped running and said
Capybara::ExpectationNotMet:
expected to find css "body.bg-b" but there were no matches
Is there something wrong with this code?
Thanks
The keyword "should" seems you're asserting something.
If you simply want to make a IF, you should write something like this :
if (page.has_css?("body.bg-b")) || (page.has_css?("body.bg-c"))
# Check something with should
else
# Check something else with should
end
It you want to check the page have a css or the other one, you should write
(page.has_css?("body.bg-b")) || (page.has_css?("body.bg-c")).should == true
Or
if !page.has_css?("body.bg-b")
page.should have_css("body.bg-c")
end
Related
How do I test if for something like a redirect, if there there are multiple possible truthy statements in my code that would spit out a redirect?
I tried using redirect with the below. But as you can see, they both technically redirect to same path. It does work, but my test doesn't really tell me if it was truthy because the first case was true or the second case was true.
if num == 2
flash[:notice] = "2 does equal 2"
redirect_to root_path
elsif num == 3
flash[:notice] = "3 does equal 3"
redirect_to root_path
end
Here's what I tried below. See how do I tell WHERE in the code this was successful?
test "check if 2 or 3" do
post "/root/path", params: { input: 3 }
assert_redirected_to "/poker/main/"
end
Long story short, my method runs through multiple possible truthy statements, and I need to know WHICH one it was successful on to write my tests.
Any input would be helpful!
figured it out, instead of redirect, I used 'assert_equal', this way I can test for specific notices, which helped me figure out WHERE my test was truthy
assert_equal "full_house. Rank is 4th", flash[:notice]
I want to intercept the validation errors thrown by Rails on a registration form. In English this works like this:
if #user.save
# Do whatever...
else
#errors = #user.errors.full_messages
if !#errors.index("Email has already been taken").nil?
# Present the user with a 'forgot password' UI
else
# Display the error on the screen
end
end
Since the test for a particular error is based on a hard-coded string comparison, it's a bit tenuous but it works when I only have a handful of exception cases.
However this becomes impossibly unwieldy when using more than one language, as the validation errors have already been localized and I'd have to use something monstrous like this:
if !#errors.index("Email has already been taken").nil? ||
!#errors.index("Email n'est pas disponible").nil? ||
!#errors.index("Email wurde bereits angenommen").nil? || ...
I'd like to think that Rails could give me a status code (like HTTP does) so I don't need to compare strings, but I haven't seen that documented anywhere.
What's the best workaround?
You should be able to get a few more details by interrogating #user.errors.details. It gets a brief mention in the guide to validations.
Essentially you should see something like this when the email is taken:
> user.errors.details
=> { :email => [{:error => :taken, :value => 'exists#example.org'}] }
That would allow your check for a "taken" email to be:
if #errors.details[:email] &&
#errors.details[:email].any? { |error| error[:error] == :taken }
There are some articles (e.g. [1]) regarding solving flaky acceptance tests when using Capybara which advocates using e.g.
.to have_text("foo")
instead of
.to eql("foo")
In one of my tests I have .to match(/foo/) and every once in a while this fails. I assume that the match matcher is not in the same category as e.g. the have_text matcher and doesn't wait. The documentation doesn't mention anything regarding this.
Is there any regex matcher so that I can check e.g.
expect(next_url).to match(/foo/)
?
Versions used (not changeable):
capybara: 2.7.x
spec-rails: 3.6.x
[1] https://www.urbanbound.com/make/fix-flaky-feature-tests-by-using-capybaras-apis-properly
The docs for have_text link to the assert_text docs - https://www.rubydoc.info/gems/capybara/Capybara/Node/Matchers#assert_text-instance_method which show that it takes either a string
expect(page).to have_text('Something')
or a Regexp
expect(page).to have_text(/foo/)
As the article you linked to implies, if you find yourself using any non capybara provided matcher with information returned from Capybara you're probably doing something wrong, and setting yourself up for flaky tests.
If you have a page where elements have a delay appearing on the page, you can define a 'wait' method in 'capybara_helpers.rb'
def wait_for timeout = 10, &block
Timeout.timeout(timeout) do
loop do
condition = yield
if (condition)
break true
end
end
end
rescue Timeout::Error
raise "Condition not true in #{timeout} seconds"
end
After that, you can use 'wait_for' method like this:
wait_for { page.has_css?('.class', text: 'Something') }
I am a freshman on Rspec
it "should not ask the database" do
#sqlite_database.should_not_receive(:findISBN)
#result = #cache.findISBN('1234')
#result.should eql(#book)
end
it "should not ask the database" do
#sqlite_database.should_not_receive(:authorSearch)
#result = #cache.authorSearch('author')
#result.should eql(#book)
end
Here are two different part 1,:findISBN and :authorSearch 2 findISBN('1234') and authorSearch('author')
I try to use let but it doesn't work ,who can help ?
#sqlite_database = double()
#cache = SQLiteDataBaseWithCache.new(#sqlite_database)
That's ture ,I'm coming from java background .You coding showed some warning: syntax error, unexpected ':', expecting keyword_end (SyntaxError).I have no ideal about it
without more details on the variables like #sqlite_database, #cache etc its hard to tell whats happening, but following should work
probably a stack trace would help
following is the idea of shared examples :)
shared_examples "it should not ask database" do |symbol, params|
it "should not ask the database" do
#sqlite_database.should_not_receive(symbol)
#result = #cache.send symbol, params
#result.should eql(#book)
end
end
it_behaves_like "it should not ask the database", :findISBN, '1234'
it_behaves_like "it should not ask the database", :authorSearch, 'author'
and on a side note, your method signatures are not ruby kind of... in ruby we normally dont use camel case
so in ruby/rails its should be author_search, probably you are coming from java background :)
I am setting up a cucumber scenario for setting up a valid user where my last step is:
"Then I should be taken to the show user page"
which I define as:
Then /I should be taken to the show user page/ do
#user = User.last
if current_path.respond_to? :should
current_path.should == path_to(user_path(#user))
else
assert_equal path_to(user_path(#user)), current_path
end
visit(user_path(#user))
end
After getting an error "Can't find mapping from "/users/49" to a path." I attempted to define the path as:
when /^users\/(.+)$/ do |user|
user_path(user.to_i)
end
But this yields the error:
syntax error, unexpected keyword_do, expecting keyword_then or ',' or ';' or '\n'
when /^landlords/(.+)$/ do |landlord|
I am relatively new to rails and web development and completely new to cucumber and TDD. Also new to regex. Any help would be appreciated!
Thanks,
John
It looks like user_path(#user) is giving you the path you need, so wrapping that in path_to is causing the error as it tries to do the same thing.
I think getting rid of the path_to call might help:
current_path.should == user_path(#user)
The reason for the "unexpected keyword_do" error is because you have when instead of When, i.e. Ruby is interpreting it as a case-style statement. But as Jon M points, you don't need that anyway.