Cucumber scenario searching in a file using ruby - file-io

I have a cucumber scenario which checks for certain strings in a file. Not a very ideal way of doing things but it has been deemed an absolute need.
My Cucumber scenario which has a table:
And the email should have
|search_string|
|Nokogiri |
|Cucumber |
|White Tiger |
My Step definition
Given /^the email should have$/ do |table|
table.hashes.each do |hash|
check_email(hash["search_string"])
end
end
My check_email method
require 'nokogiri'
def check_email(search_string)
htmlFile = File.open(filename).read
doc = Nokogiri::HTML::DocumentFragment.parse(htmlFile)
if (doc.content["#{search_string}"])
puts true
return true
end
htmlFile.close
puts false
return false
end
The file I am reading although is ".txt" file extension the contents in the file are in HTML format.
The method is reading the correct file
The file has the contents that the method is trying to locate
Now to the actual problem that I am seeing.
The search_string in my cucumber scenario has 3 values to be searched. "White Tiger" is not there in the file
Since "White Tiger" is not in the file the test should fail, but instead the test passes / I should say I see "green" and when I output the actual results as above in the code it clearly shows (true for Nokogiri, true for Cucumber and false for White Tiger).
My question is so how can I do this. Cucumber table results should show GREEN/PASS only for values that are available in the file and RED/FAIL for values not in the file.
Can someone please help me with this. Appreciate in advance.

Cucumber won't fail a step unless an exception is raised (this is what happens when an RSpec matcher is not satisfied). Simply returning true or false is meaningless.
Your assertion should probably look something like
if (!doc.content["#{search_string}"])
raise "Expected the file to contain '#{search_string}'"
end

If you want to use your check_email function as is, you can add an assertion to your step definition:
Given /^the email should have$/ do |table|
table.hashes.each do |hash|
check_email(hash["search_string"]).should be_true
end
end
You could also just make your e-mail function return a string, and check its contents in your step definition:
require 'nokogiri'
def email_contents
html = IO.read(filename)
doc = Nokogiri::HTML::DocumentFragment.parse(html)
return doc.content
end
# ...
Given /^the email should have$/ do |table|
contents = email_contents
table.hashes.each do |hash|
contents.should include(hash["search_string"])
end
end
These aren't better or worse than Jon M's approach--just another alternative.

Related

Using a rails model in Capybara tests

I set up a project where all I have to do is display a set of records from an SQLlite3 database. I have a table in that database, and I want the root page to display all the records in the database. I have this working, but now I want to set up a Capybara test to make sure that the page has the first and last record from the table on the page.
require 'rails_helper'
describe "seeing record from scotlands model " do
specify "I can see a list of all charities" do
visit "/"
expect(page).to have_content "#table.first_record"
end
end
However, the above provides no link to the model so I cannot access it. How do I get a link to the table from the test file?
Do you generally try to access real data from tests? I've always learned to keep those things separate.
I like to work with Rspec and Capybara. Here is something simple and straight forward that should accomplish what you've discussed:
require 'rails_helper'
feature "user sees all scotlands records" do
scenario "successfully" do
charity1 = Charity.create(name: name1, info: info1)
charity2 = Charity.create(name: name2, info: info2)
charity3 = Charity.create(name: name3, info: info3)
visit root_path
expect(page).to have_content(charity1.name)
expect(page).to have_content(charity1.info)
expect(page).to have_content(charity2.name)
expect(page).to have_content(charity2.info)
expect(page).to have_content(charity3.name)
expect(page).to have_content(charity3.info)
end
end
I actually usually work with FactoryGirl also. In this case it'd make things easier because you could use create_list and make as many records as you'd like with just one line of code.

Can we list all the scenarios which fall under a Cucumber tag

I have three-four Cucumber tags (say #smoke, #testing, #test) which are randomly put on scenarios and feature files. Now, I need to list all the scenarios which fall only under smoke. Can someone please suggest a way to do this
You can use the dryRun=true option in CucumberOptions with tag filters in your runner to get the list of scenarios in the report. This option will not execute your features but will list them out plus check if the steps have the appropriate glue code.
#CucumberOptions(plugin={"pretty", "html:report"}, tags={"#smoke"},
snippets=SnippetType.CAMELCASE,
glue="....", features="src/test/resources/features", dryRun=true)
Make sure you add the correct path of your glue code. Also the features should point to the top directory containing the feature files.
The above should list out the any scenario containing the #smoke tag in the html report.
But if you are looking for scenario list with only #smoke tag and not the others use this filter (tags="#smoke","~#testing","~#test").
Point of caution, if you have Scenario Outlines they will be repeated by the number of scenarios in the examples table.
You can write your own filter to print what you would run but run nothing.
require 'cucumber/core/filter'
# put inside features/support/
class PrintOnlyCukeFilter < Cucumber::Core::Filter.new
def test_case(test_case)
puts test_case.location.to_s
end
end
AfterConfiguration do |config|
config.filters << PrintOnlyCukeFilter.new
end
Put the file in features/support.
To print only file names you can see this gist.

CarrierWave multiple file types validation with single uploader

How to validate the extension of uploaded file when using single uploader for multiple file type?
I am using the single model namely Asset containing the attribute file. Uploader is mounted on file attribute. Asset model having one more attribute called feature_id. feature_id refers to features like video, audio, etc.
So, how should I validate the file type with multiple extension whitelist depending upon feature_id value?
Using ruby 1.9 and rails 3.2.11
Any help will be greatly appreciated.
Although the answer has been accepted but I've got a better way for this. Try this code.
class MyUploader < CarrierWave::Uploader::Base
def extension_white_list
if model.feature_id == 1
%w(jpg jpeg gif png)
elsif model.feature_id == 2
%w(pdf doc docx xls xlsx)
elsif model.feature_id == 3
%w(mp3 wav wma ogg)
end
end
end
feature_id == 1 means you want to allow just picture uploads, feature_id == 2 means that only documents will be allowed to be uploaded and feature_id == 3 will allow you to upload only audio files.
Hopefully it answers the question. You can add more checks for other types of files.
Define your white list in your uploader as shown in the docs for carrierwave.
class MyUploader < CarrierWave::Uploader::Base
def extension_white_list
%w(jpg jpeg gif png)
end
end
I ran into the exact same use case:
In Asset.rb
Validate the format of the filename
validates :asset_file,
format:{
with: %r{\.(pdf|doc|png)$}i, message: "Wrong file format"
}
Use a regular expression to test the file name:
Here you can play with the regex:
http://rubular.com/r/Z3roRDDXAf
Hope this helps!

rails user input with <script>, stored, and displayed

I have an application that collect user input and store to DB and show back to user.
One user entered "alert(1)" into the name field and saved it into DB.
Whenever the name is displayed, the page will be broken.
I know how to fix that input only with validation for input, and h() for output.
However, I have so many input fields and so many outputs that accept users' text.
Is there any simple way to prevent this happening(i.e. overriding params method, etc)?
I also want to know how you expert guys are dealing with this problem?
As of Rails 3, my understanding was that embedded ruby code was html escaped by default. You don't need to use h() to make it that way. That is, if you use <%= "<script>a=1/0;</script>" %> in a view, the string is going to be made html safe, and so the script doesn't execute. You would have to specifically use raw() or something similar to avoid it - which you should naturally not do unless you're really confident about the contents.
For output, Rails 3 automatically html-encode all text unless I use raw() method.
For input, How about making a common validator and apply to all fields that are text or string? Is it desirable?
http://api.rubyonrails.org/classes/ActiveModel/Validator.html
class MyValidator < ActiveModel::Validator
def validate(record)
record.class.columns.each do |c|
if c.type==:text || c.type == :string
record.errors.add c.type, "script tag is not allowed" if c[/<script[^>]*>/]
end
end
end
end

cucumber step_definitions Q on style/approach on I should see

I'd like to get opinions from others with more experience on writing Cucumber step definitions.
My initial intention was to verify that a particular link was present in one scenario and
verify that it wasn't present in another scenario.
So I have the following two steps. In my naivety I thought I could use the '!find_link(...)'.
In the end I decided to use exceptions.
I'd like to solicit feedback on two aspects:
1. the approach I've taken on using the exceptions within the step_definition
2. is it meaningful to expect to explicitly look for links in the rendered page?
As I finished up work last night I couldn't help thinking "why didn't I simply use:
I should not see 'Sign up'?" and this morning it dawned on me that 'Sign up' could be included in a paragraph on the page somewhere.
Here are the steps, thanks in advance...
Then /^I should see link: ?"([^"]*)"$/ do |link|
find_link("#{link}")
end
Then /^I should not see link: ?"([^"]*)"$/ do |link|
# !find_link("#{link}") - commented out because it won't fail if link is present
begin
find_link("#{link}")
raise FindException
rescue Capybara::ElementNotFound
end
end
'Then' step definitions definition should always contain an assertion, e.g. should if using RSpec or assert if using Test::Unit.
So if want you want to verify a specific URL isn't present, it would be better to do:
should_not have_link(link)
However, it would probably be better to re-write the step as:
Then I should not see a sign-up option
And in the step definition, rather than checking for a URL, you could check for a link with a particular class:
should_not have_css('a.signup')