json[:errors] = ["Username can't be blank", "Email can't be blank"]
The error, in en.yml, itself is provided as:
username: "can't be blank",
email: "can't be blank"
and the test:
expect(json[:errors]).to include t('activerecord.errors.messages.email')
Which fails because it's looking at the string "Email can't be blank", and "can't be blank" doesn't match it.
My question is what is the best (and by that I mean best practice) way to test
that the substring is included in a string contained inside the array json[:errors]
RSpec offers a range of matchers. In this case you'll need to use the include matcher (docs) to check each element of the array. And, you'll need to use the match regex matcher (docs) to match the substring:
expect(json[:errors]).to include(match(/can't be blank/))
For readability, the match regex matcher is aliased as a_string_matching, like this:
expect(json[:errors]).to include(a_string_matching(/can't be blank/))
UPDATE:
I just noticed that the OP's question include an array with multiple matching elements. The include matcher checks to see if ANY elements of the array match the criteria. If you to check to see if ALL elements of the array match the criteria, you can use the all matcher (docs).
expect(json[:errors]).to all(match(/can't be blank/))
Related
I have the following test in rspec
it 'passes regex rules' do
job = create(:job)
job.valid?
expect(job.title).to match(/\A[\w\d .,:-#]+\z/)
end
This regex pattern matches the model pattern. What is the recommended way to test to make sure this pattern does not change in the model from future developers?
Basically I want to test for conditions that do not fall in the approved: can only have 0-9, A-Z, periods, colons, hypens, underscores, and spaces. No new lines (enter keys)
Update
Based on Generate random string based on Regex? I decided to go with (0..255).map(&:chr).select{|x| x != /\A[\w\d .,:-#]+\z/}.sample(5).join for now which appears to work, thoughts?
Based on the update, I went with the following:
describe 'title' do
let(:bad_string) { (0..255).map(&:chr).select{|x| x != /\A[\w\d .,:-#]+\z/}.sample(20).join }
it 'should exist' do
job = build(:job, title: nil)
job.valid?
expect(job.errors[:title].size).to eq(3)
end
it 'passes regex rules' do
job = build(:job, title: bad_string)
job.valid?
expect(job.errors[:title].size).to eq(1)
end
end
I am trying to write and test a regex valiation which allows only for a sequence of paired integers, in the format
n,n n,n
where n is any integer not beginning with zero and pairs are space separated. There may be a single pair or the field may also be empty.
So with this data, it should give 2 errors
12,2 11,2 aa 111,11,11
error 1: the 'aa'
error 2: the triplet (111,11,11)
In my Rails model I have this
validates_format_of :sequence_excluded_region, :sequence_included_region,
with: /[0-9]*,[0-9] /, allow_blank: true
In my Rspec model test I have this
it 'is invalid with alphanumeric SEQUENCE_INCLUDED_REGION' do
expect(DesignSetting.create!(sequence_included_region: '12,2 11,2 aa 111,11,11')).to have(1).errors_on(:sequence_included_region)
end
The test fails, as the regex does not find the errors, or perhaps I am calling the test incorrectly.
Failures:
1) DesignSetting is invalid with alphanumeric SEQUENCE_INCLUDED_REGION
Failure/Error: expect(DesignSetting.create!(sequence_included_region: '12,2 11,2 aa 111,11,11')).to have(2).errors_on(:sequence_included_region)
expected 2 errors on :sequence_included_region, got 0
# ./spec/models/design_setting_spec.rb:5:in `block (2 levels) in <top (required)>'
Regex
Your regex matches a single pair followed by a space anywhere in the string.
'12,2 11,2 aa 111,11,11 13,3'.scan /[0-9]*,[0-9] /
=> ["12,2 ", "11,2 "]
So any string with one valid pair followed by a space will be valid. Also a single pair would fail 3,4 as there is no space.
A regex that would validate the entire string:
positive_int = /[1-9][0-9]*/
pair = /#{positive_int},#{positive_int}/
re_validate = /
\A # Start of string
#{pair} # Must have one number pair.
(?:\s#{pair})* # Can be followed by any number of pairs with a space delimiter
\z # End of string (no newline)
/x
Validators
I don't use rails much but it seems like you are expecting too much from a simple regex validator for it to parse out the individual error components from a string for you.
If you split the variable up by space and then validated each element of the array you could get that detail for each field.
'12,2 11,2 aa 111,11,11 13,3'.split(' ').reject{|f| f =~ /^[1-9][0-9]*,[1-9][0-9]*$/ }
You can put something like that into a custom validator class using validates_with which you can then have direct control of your errors with...
class RegionValidator < ActiveModel::Validator
def validate(record)
record.sequence_included_region.split(' ').reject{|f| f =~ /^[1-9][0-9]*,[1-9][0-9]*$/ }.each do |err|
record.errors[sequence_included_region] << "bad region field [#{err}]"
end
end
end
(?<=\s|^)\d+,\d+(?=\s|$)
Try this.Replace with empty string.The left string split by are your errors.
See demo.
http://regex101.com/r/rQ6mK9/22
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.
I want to check if the given string is not in the table row. But when using the code below:
page.should have_xpath('//td', :text => r)
It matches the text within the table too. For example there are not values with 'G' in the table but 'PG' are, so the above code returns positive for 'G' also.
How can I check the precise string with Capybara?
Solved it with this:
regex = Regexp.new("(^#{r}$)")
page.should_not have_xpath('//td', :text => regex)
I've written a regex to help validate a String for game character names. It's somehow passing seemingly invalid strings and not passing seemingly valid strings.
Requirements:
Starts with a capital letter
Has any number of alphanumeric characters after that (this includes spaces)
This is the rails code that does the validation in the Character Model:
validates :name, format: { with: %r{[A-Z][a-zA-Z0-9\s]*} }
Here's the unit test I'm using
test "character name should be properly formatted and does not contain any special characters" do
character = get_valid_character
assert character.valid?
character.name = "aBcd"
assert character.invalid?, "#{character.name} should be invalid"
character.name = "Number 1"
assert character.valid?, "#{character.name} should be valid"
character.name = "McDonalds"
assert character.valid?, "#{character.name} should be valid"
character.name = "Abcd."
assert character.invalid?, "#{character.name} should be invalid"
character.name = "Abcd%"
assert character.invalid?, "#{character.name} should be invalid"
end
The problems:
The regex passes "aBcd", "Abcd.", and "Abcd%" when it shouldn't. Now, I know this works because I tested this out in Python and it works just as you would expect.
What gives?
Thank you for your help!
Regular expressions look for matches anywhere in the given string unless told otherwise.
So the test string 'aBcd' is invalid, but it contains a valid substring: 'Bcd'. Same with 'Abcd%', where the valid substring is 'Abcd'.
If you want to match the entire string, use this as your regex:
# \A matches string beginning, \z matches string end
%r{\A[A-Z][a-zA-Z0-9\s]*\z}
PS: Some people will say to match the beginning of a string with ^ and the end with $. In Ruby, those symbols match the beginning and end of a line, not a string. So "ABCD\n%" would still match if you used ^ and $, but won't match if you use \A and \z. See the Rails security guide for more on this.
If you only want to match the capital letter at the beginning of the string, you need to put in the "start of line" marker ^ so it would look like:
validates :name, format: { with: %r{^[A-Z][a-zA-Z0-9\s]*} }
Check out Rubular to play around with your regex