I have a webpage with two different strings depending on time of the day - "Good day" or "Good night".
Is there any way to do some sort of assert_content(my_string) that check if one of the two given strings is present?
It doesn't matter which one is present, just that one is.
If using MiniTest then you can use assert_match:
assert_match /Good day|Good night/, string
If using RSpec then you can use match:
expect(string).to match /Good day|Good night/
While Sebastian's answer will work as long as the page is loaded when you go to check, it loses Capybaras waiting/retrying behavior and can lead to flaky tests if used to check content while a page is changing (immediately after clicking a button, etc).
When using minitest a better solution would be to continue using the Capybara provided assert_content matcher but pass it a regex
assert_content(/Good day|Good night/)
If using RSpec you can do the same
expect(page).to have_content(/Good day|Good night/)
or you can write it in a potentially more readable manner
expect(page).to have_content('Good day').or(have_content('Good night'))
Related
I have feature specs for my ActiveAdmin view. It works on my local machine. But when ran in CircleCi it fails with
undefined method `text' for nil:NilClass
spec
it 'uses the update_at date when prepaid_invoice' do
travel_to(5.days.ago) { create_prepayment }
travel_to(3.days.ago) do
visit '/admin/payments'
expect(page).not_to have_css('.col.col-created > div')
amount = all('.col-amount').last
expect(amount.text).to eq('$1,000.00') # failing here
all behaves different depending on whether you're on a current release of Capybara or the older 2.x version. In current versions all will wait for up to Capybara.default_max_wait_time seconds for any matching elements to appear and if none do it will return an empty array (actually Array like Result object, but close enough). In 2.x all (by default) did no waiting for matching elements, it would just return the empty array if no elements matched. Either way - you're not finding any matching elements, and then calling last on an empty array - giving you nil.
There are a couple of ways around this. You could tell all that you expect at least one matching element ( which will then force waiting for matching elements Capybara 2.x )
amount = all('.col-amount', minimum: 1).last
or depending on exactly what you're checking you could just combine it into one
expect(page).to have_css('.col-amount', exact_text:'$1,000.00')
which gets away from calling methods on Capybara elements and using the generic RSpec matchers on them (which is something you don't want to do, for test stability reasons, unless you have no other options). Those two solution don't test exactly the same thing, but may test enough for what you want. Depending on exactly how your HTML is structured there may be more efficient solutions too.
If you're already using a recent version of Capybara then your error would indicate that what you expect to be on the page isn't (maybe you're on an error page, etc) or you don't have Capybara.default_max_wait_time set high enough for the system you're testing on.
I'm using rspec with ruby on rails for testing.
Question - In a spec if I was to do a cross check a pre-condition is established properly before starting the test, what approach is recommended?
For example, using an rspec ".should" type assertion doesn't seem like this would be the right thing as I'm only checking a precondition...
I would have two different tests: one asserting that things like your precondition can be set correctly, the other assuming it works and then testing whatever depends on it.
A should is perfectly valid in this situation as it is a condition that should be valid at the start of the test. As a very trivial example:
it "should increment by one" do
value = 10
value.should eql(10)
value += 1
value.should eql(11)
end
I don't think current RSpec has that kind of feature, it would be nice to have some other method for these pre-condition assertions such as
it "should increment by one" do
value = 10
value.must eql(10) # This is a necessary pre-condition, not the actual test
value += 1
value.should eql(11)
end
But I guess there is no such method to distinguish things, but the rspec-given gem might be of interest.
I have been using rspec for a little while and recently switched style from
it "should do something cool" do
#something.should work
end
to the more concise
subject(#something)
it {should work}
Whilst I much prefer the more concise style when writing the tests and for viewing them in code, I miss being able to specify the description for each test, particularly since the equality messages just display the values that are being tested. So in the example above, assuming the test passes, with the first style, I would get a message saying 'it should do something cool', whereas the second will just say that it has worked.
Does anyone know of a way to do this? Cheers
I think you got the wrong concept of what the specify/subject blocks do. They are not meant to be a complete replacement for the more verbose syntax you switched from, but should be used when there is no need for a desciption.
So if you want a desciption, just use
it "should do something cool" do
#something.should work
end
Also, I personally don't think that the specify/subject is more concise. For me it's a step away from the more DSL-like way specifications created with rspec read, but that might be a matter of personal preference.
For the sake of simplicity, I've left out most of my test and only included the offending code. It is:
click_button('Search')
page.select 'Preferred', :from => 'ticket_service_type'
When I run this, I receive the following:
Failure/Error: page.select 'Preferred', :from => 'ticket_service_type'
Capybara::ElementNotFound:
cannot select option, no select box with id, name, or label 'ticket_service_type' found`
The AJAX request this button click event triggers doesn't have anything to do with the select tag, so reversing the order in the test causes the test to pass. I know that Capybara's default wait time is 2 seconds and so I changed it to 10 with:
Capybara.default_wait_time = 10
This does not cause the test to pass. How can I get these two methods to play nice with one another and work in the order in which a user would operate the web page?
(Had I posted the code from my spec, I bet this would have been solved quickly.)
From The Cucumber Book (emphasis mine):
Luckily, Capybara knows how to deal with this situation in a simple way. If we add an explicit call to find, passing a CSS selector for a DOM element on the page that doesn’t yet exist, Capybara will wait a little (50ms) and try again until the element appears. If it doesn’t appear after a while (two seconds by default, though this is configurable), it will raise an exception, causing the step definition to fail.
So have your AJAX write something to the DOM then find() it in your step definition. It's not ideal. In my case I'm introducing a (hidden) DOM element just to facilitate testing but I haven't found another way.
Be sure to add :js => true to integration tests which depend upon JavaScript.
I am using cucumber with rails, and I'm checking if the parent of an element has a certain class. I found this code, but it doesn't work. I'm using Capybara by the way. Thanks in advance!
Then the element "([^"]*)" with parent "([^"]*)" should have class "([^"]*)" do |element_id,parent,css_class|
response.should have_selector "#{parent} .#{css_class}" do |matches|
matches.should have_selector element_id
end
end
Technically, this isn't really the way you should be testing with cucumber. Cucumber is for testing behaviour, not checking the DOM - though of course it can be used in that way.
If you're really wanting to write something like this, you could make that much simpler:
Then /^the element "([^"]*)" with parent "([^"]*)" should have class "([^"]*)"$/ do |element_id,parent,css_class|
page.should have_css("#{parent}.#{css_class} #{element_id}")
end
This sucks on many levels, though. Not only are you checking the DOM directly from the step, which makes for very unreadable features, but you're mixing passing in element names, class names and element IDs - each with a slightly different style... In this step, element can be any type of selector whereas parent and css_class are much more fixed - they must always 'fit' into the selector string or it won't find anything.
I haven't really explained that very well, but in a nutshell, you should consider what you're actually trying to test and think whether it can be renamed to something more useful and re-usable. Would you ever be able to re-use that step without looking at it's implementation to figure out what goes where?
Also, with more expressive naming, the test instantly becomes more useful later down the line. For example, the step Then I should see the current list is active is much more readable and expressive than Then the element "li.active" with parent "ul" should have class "active-list". Be specific in the step definition implementation, not your features!
Have a read of this blog post - http://elabs.se/blog/15-you-re-cuking-it-wrong - it should give you a good idea of how to write better steps.