How do you test for an empty input field? - ruby-on-rails

I'm trying to test to see if an input field matches one of my factories where the field is empty.
address => {:first_name => '', :last_name => ''}
When checking for what is in the input field I've been using this:
assert_select '#first_name[value=?]', address.first_name
Except this does not work if the first name is blank. I'll get this error and the test fails.
Expected at least 1 element matching "#first_name[value='']", found 0.
<false> is not true.
This makes sense because the code generated will not have the value attribute. Is there a better way to verify the value of an input field?
As of now to test for this I can check if the address field is blank then check if there is an input field without a value attribute. But this is messy and verbose.
Example of a universal check that works but is lengthy:
if address.first_name.blank?
assert_select '#first_name[value]', 0
assert_select '#first_name[type=text]', 1
else
assert_select '#first_name[value=?]', address.first_name
end
Related Information I'm using:
Hpricot 0.8.1
Nokogiri 1.1.1
Rails 2.2.2
Thoughtbot-Shoulda 2.0.5
Webrat 0.4.1

Maybe you can use:
assert_select "#first_name" do
assert_select "[value=?]", address.first_name unless address.first_name.blank?
end
I don't think I can get it any shorter. If it is a recurring pattern in your test case, you could extract it to a custom assertion:
def assert_has_value_unless_blank(selector, value)
assert_select selector do
assert_select "[value=?]", value unless value.blank?
end
end
assert_has_value_unless_blank "#first_name", address.first_name

Related

Capybara ingore `within` scope at specify assertion

Suppose I'm testing a form with Capybara and Minitest, the form has a text input, which using bootstrap-datepicker, I wanna unscope(like ActiveRecord) the within('form') scope only at assert_selector '.datepicker-dropdown', count: 1, as .datepicker-dropdown is appended to body not the form
within "form" do
# other tests...
find("input.date-picker").click
assert_selector '.datepicker-dropdown', count: 1
# failed because .datepicker-dropdown is appended to body
end
Though bootstrap-datepicker have an option container to specify where to append the datepicker-dropdown widget, but not suitable for this case.
There are two ways of escaping the scope of within. The first would be to use XPath and taking advantage of the Xpath-trap (https://github.com/teamcapybara/capybara#beware-the-xpath--trap) by intentionally breaking the scope
assert_xpath '//*', class: 'datepicker-dropdown', count: 1
The second (and probably clearer) method would be to use the page.document method to escape the current scope
assert_selector page.document, '.datepicker-dropdown', count: 1

capybara not wait ajax request

I get the following error in rspec + capybara + poltergeist:
given!(:user_owner) { create(:user) }
given!(:second_user) { create(:user) }
given!(:question) { create(:question, user: user_owner) }
describe 'as not question owner' do
before do
login_as(second_user, scope: :user, run_callbacks: false)
visit question_path(question)
end
scenario 'can upvote just one time', js: true do
first('a#question-upvote').click
expect(first('div#question-score').text).to eq '1'
first('a#question-upvote').click
expect(first('div#question-score').text).to eq '1'
end
Failure/Error: expect(page.first('div#question-score').text).to eq '-1'
expected: "-1"
got: "0"
When I insert sleep 1:
scenario 'can upvote just one time', js: true do
first('a#question-upvote').click
sleep 1
expect(first('div#question-score').text).to eq '1'
first('a#question-upvote').click
sleep 1
expect(first('div#question-score').text).to eq '1'
end
Test pass.
I understood that page not waited asynchronous request.
How can I rewrite test to start it to work well without sleeping?
P.S. Sorry for English.
You're killing any waiting behavior by using the eq matcher. This is because once you call .text on a found element you have a String and there is no way to reload/re-query that string when used with the eq matcher. If you want waiting/retrying behavior you need to use the matchers provided by Capybara with Capybara elements.
So instead of expect(first('div#question-score').text).to eq '1' you should be doing
expect(first('div#question-score')).to have_text('1', exact: true) # you could also use a Regexp instead of specifying exact: true
Another thing to note is that all/first disable reloading of elements, so if the entire page is changing (or the element you are waiting for text on is being completely replaced) and the initial page had an element that would match the selector but you actually want the element from the second page (or replaced element) to be checked you shouldn't be using first/all - In that case you would want to use find with a query using the css :first-child/:first-of-type, etc type things (or equivalent XPath) to uniquely identify your element instead of returning multiples and picking one of them. If it's just the value of the element being replaced asynchronously on the page then you did not to worry about it.

Mutate string for testing with rspec and factory_girl

I'd like to test the validation of a model's attribute with rspec and factory_girl. The 'special' thing is, that one attribute (the name) isn't allowed to start with Numbers or special signs like %,&,$, ...
For testing this it would be great to write only one example like
it "is invalid with name starting by special character" do
["1","$","%"].each do |i|
name = i + "test"
FactoryGirl.build(:tutu, name: name).should_not be_valid
end
end
This work's for the first case but it won't return the result for the whole list. Is it possible to tell rspec not to stop on the error?
Do this instead:
["1","$","%"].each do |i|
it "is invalid with name starting by '#{i}'" do
FactoryGirl.build(:tutu, name: "#{i}test").should_not be_valid
end
end

how to check/test specific field in json using rspec

This is my rspec code:-
it "which has max value" do
get :index, Devise.token_authentication_key => #user.authentication_token, business_id: #business.id, max: '1'
expect(request.flash[:alert]).to eq(nil)
expect(response.body).to eq([#location].to_json(LocationFinder::API_PARAMS.merge(:root => false)))
end
and testing result is-
expected: "[{\"address\":\"1120 Milky Way\",\"business_id\":1,\"city\":\"Cupertino]"
got: "[{\"address\":\"1120 Milky Way\",\"business_id\":1,\"city\":\"Cupertino,\"distance\":260.33452958767384,]"
Here Distance is an extra field , how can i check particular fields or if it is not possible , how to eliminate "distance" field which is not check by rspec.
You could check individual fields using something like:
# get the first entry in the JSON array
json_response = JSON.parse(response.body).first
# compare each field
expect(json_response['address']).to eq(#location.address)
expect(json_response['business_id']).to eq(#location.business_id)
expect(json_response['city']).to eq(#location.city)
Of course you may need to adjust the exact methods you call on #location depending on your implementation, but that's the gist of it.

ArgumentError: assertion message must be String or Proc using assert_select

I'm writing a controller test for a rails 3.1 app using testunit 2.4.0.
I want to assert that a certain heading does not appear on the page.
I'm using assert_select like this:
assert_select 'h1', {:text => /Key Dates/, :count => 0}
and getting the following error:
ArgumentError: assertion message must be String or Proc: <</Key Dates/>
expected but was <"Planner Maternity leave">.>(<Test::Unit::Assertions::AssertionMessage>)
I've tracked this down to the fact that assert_select calls build_message which creates an instance of AssertionMessage and passes it through to test-unit's assert. However in version 2.2 of testunit (Feb 2011) checks were added which check the type of the message passed in. These checks trigger the ArgumentError seen above.
I'm not sure whether the mistake lies with test-unit being over-strict or assert_select passing the wrong object type.
Can you advise how best to follow this up? Any work-arounds?
So, the assert_select documentation shows the following example, passing a block in:
assert_select "ol" do |elements|
elements.each do |element|
assert_select element, "li", 4
end
end
So what if you did something like...
assert_select 'h1' do |elements|
elements.length == 0 ? fail
elements.each do |element|
element.text ~= /Key Dates/ ? fail
end
end
Which basically fails if it finds the pattern OR if the number of h1 elements is zero. Obviously you would change the conditions to match what it is you're trying to test for, but does that get you any closer to what you need?
If you cannot upgrade to a bug-free version, you can just pass a third argument (the message), so you do not force the message be built:
assert_select 'h1', {:text => /Key Dates/, :count => 0}, "Unexpected Key Dates found."

Resources