Rspec: spec case classified as flaky - ruby

I'm trying to write some tests (spec) using rspec, so far, I'm getting the next example as flaky:
it "when filter by date_of_birth is present" do
get :index, filter: { 'event_timestamps.date_of_birth': format_date(recorded_at + 6.hours) }, format: :json
expect(json_data.count).to eq(1)
end
I supposed the issue is in the parameters, I'm not sure, so my questions are:
Should format in a different way the params?
is my approach wrong? what should be a better one?
Thanks a lot for your comments

Guessing the problem is within 6 hours of the end of the day when your time calculation will be pushing the date into "tomorrow", generally the best idea with anything like that is to use a gem like timecop so you're not relying on an ever-changing state.

Related

Algorithm in Ruby to trigger a method based on presence of certain texts

I don't know if it can be called an algorithm but i think its close.
I will be pulling data from an API that will have certain words in the title, eg:
Great Software 2.0 Download Now
Buy Great Software for just $10
Great Software Torrent Download
So, i want to do different things based on the presence of certain words such as Download, Buy etc. For eg, if it has the word 'buy' in it, i would like to extract the word buy and the amount value that is present in the title and show it in another div, so in this case it would be "Buy for $10" or "Buy $10" etc. I can do if/else as well but I don't want to use if else because there could be more such conditions in the future. So what i am thinking about is using the send method. eg:
def buy(string)
'Buy for just' + string.scan(/\$\d+/).first
end
def whichkeyword(title)
send (title.scan(/(download|buy)/i)[0][0]).downcase.to_sym, title
end
whichkeyword('Buy this software for $10 now')
is there a better way to do this? Or is this even a good way to do it? Any help would be appreciated
First of all, use send if and only you are to call private method, use public_send otherwise.
In this particular case metaprogramming is an overkill. It requires too much redundant code, plus it requires the code to be changed for new items. I would go with building a hash like:
#hash = { 'buy' => { text: 'Buy for just %{placeholder}', re: /\$\d+/ } }
This hash might be places somewhere outside of the code, e. g. it might be stored in yml file near the code and loaded in advance. That way you might be able to change a behaviour without modifying the code, that is handy for instance in gem.
As we have a hash defined/loaded, I would call the method:
def format string
key = string[/#{Regexp.union(#hash.keys).source}/i].downcase
puts #hash[key][:text] % { placeholder: string[#hash[key][:re]] }
end
Yielding:
▶ format("Buy this software for $10 now")
#⇒ Buy for just $10
There are many advantages over declaring methods, e. g. now matches might contain spaces, you might easily add/remove matchers etc.
First of all, your algorithm can work, but has some troubles in it, like what if no keyword is applied.
I have two solutions for you:
NLP
If you want to do it much more dynamic, you can use NLP - Natural language Processing. NLP will find main words in you sentence and then you can find the good solution for each.
A good gem for that is Treat that you can use with stanford-core-nlp. After processing the data you can find the verbs and even synonyms in the sentence and figure out what to do.
sentence('Buy this software for $10 now').verbs # ['buy']
Simple Hash
This solution is less dynamic, but much more simple. Like you did with the scan, just use Constant to manage your keywords, and the output from them(I would do it with lambdas). you can also add default to the hash
KEYWORDS = Hash.new('Default Title').merge(
buy: -> { },
download: -> { }
)
KEYWORDS[sentence[/(#{KEYWORDS.keys.join('|')})/i].downcase]
I think this solution is good enough.
The only thing that looks strange is scan(/(download|buy)/i)[0][0].
As for me I don't very much like using [] syntax in Ruby.
I think using scan here is not necessary.
What about
def whichkeyword(title)
title =~ /(download|buy)/i
send $1.downcase.to_sym, title unless $1.nil?
end
UPDATE
def whichkeyword(title)
action = title[/(download|buy)/i]
public_send action.downcase.to_sym, title if action
end

Better diffs with minitest

I'm looking at my test case results, and it's far to difficult to see where the one small failure in my test is coming from.
I'm dealing with reasonable sized data structures - and I don't want to change the to_s method so that it's slightly better for the minitest diff.
I've looked at the reporters but they don't seem to have anything like what I'm looking for. (I'm using ruby 1.9.3)
Is there any way that minitest or some library for minitest could highlight the part of the string that is different between two results?
Or is there something I'm missing that allows you to visually look at the diff more easily?
Edit: Example
Minitest::Assertion:
--- expected
+++ actual
## -1 +1 ##
-#<struct MyModule::Swipe id=0, lat=37.62996, lng=-122.42115, route=#<struct MyModule::Route id=17, bus_name="test_name", stops=[#<struct MyModule::Stop id=29, name="Cool Stop">]>, date_time="2015-10-29T11:05:02+00:00">
+#<struct MyModule::Swipe id=0, lat=37.62996, lng=-122.42115, route=#<struct MyModule::Route id=17, bus_name="test_name", stops=[#<struct MyModule::Stop id="29", name="Cool Stop">]>, date_time="2015-10-29T11:05:02+00:00">
Instead could show the line, and highlight in another colour the id="29" vs the id=29 only. Minitest seems to show the diff based on the lines printed.
pretty-diff
I had the same problem, and in case of invisible blank characters, this gem is still not good enough for debugging. I end up adding .inspect to both String that I passed to assert_equal in minitest test case.

Ruby strptime method error

So I am working through a tutorial building an event manager program and I'm a bit stuck. I want to build a method that will take registration data from a .csv file and then extract the hour times when people registered. However I'm having trouble getting it to work. Here's what I have so far:
def reg_hour(regtime)
regtime = DateTime.new
DateTime.strptime(regtime, "%H")
end
When I run the code though I get this error:
`block in _strptime_i': undefined method `sub!' for #<DateTime: -4712-01-01T00:00:00+00:00 (-1/2,0,2299161)> (NoMethodError)
I am quite confused and any help would be greatly appreciated.
Here's the link to the tutorial if anyone is interested.
http://tutorials.jumpstartlab.com/projects/eventmanager.html
Not sure what you're doing with the DateTime.new and overriding the regtime variable (I'm new to ruby myself). If the regtime is coming out of a csv file, it's probably coming out as a string. Perhaps you could use a regular expression as long as the regdate format is consistent.
If regdate is: "11/12/08 10:47"
Then using:
regdate.scan(/\s\d+:/)
Would return [" 10:"]. Perhaps then you could store that in a array variable and clean it up by removing white space and the colon. There's probably a more elegant solution, but that's my newbie brute force way.
I am not quite sure I fully understand your intentions, but here it is rewritten:
require 'time'
def reg_hour(regtime)
DateTime.strptime(regtime, "%H")
end
d = reg_hour("21/03/2011 14:39:11.642")
puts d.year
Is this something you're trying to do?

Combining RSpec filters?

I've been looking through the docs, but descriptions of how multiple filters work seem to be a bit lacking. Does anyone have a good explanation or source of a good explanation for the behaviour of multiple filters? Does the order they are listed matter? Here's an example of code that might have behaviour other than what one could expect...
Rspec.configure do |c|
this_version = get_version_number.to_sym
c.filter_run :focus=> true
c.filter_run_excluding :limit_to=>true, this_version => false
c.filter_run :new_stuff=>true
c.run_all_when_everything_filtered
end
it "is focused, but not new", :focus
it "is is new", :new_stuff
it "is new and focused", :new_stuff, :focus
it "is focused and new, but limited to a different version", :focus, :limit_to, :correct_version
Experimenting with this, it also seems like multiple arguments on the "filter_run_excluding" line simple act is if you wrote the line multiple times. Is there a way to get it to actually combine the filter checks so that it excludes (or runs, I suppose) only examples that have both the tags listed?
Run multiple filters from the command line with this:
rspec spec --tag my_tag --tag my_second_tag -- tag ~my_third_tag
The ~ will exclude any spec with those tags, so its often useful to do something like
rspec spec --tag ~long_runing

How to assert on number of html table rows in ruby using capybara + cucumber

I am trying to get to grips with BDD web development in Ruby using cucumber + capybara and I am stuck at what should be an easy task - just to check the number of rows in a table. The intention of what I'm trying to achieve is something along the lines of:
page.should have_xpath("//table[#id='myTable']")
find("//table[#id='myTable']/tr").length.should == 3
But this doesn't work (missing method length) and I can't find a way to assert against the table length.
Any ideas anyone (please be easy on me tho' I'm a ruby nooby)
Thanks in advance
Neil
Even though have_css? will do the trick, your tests should tell you how they failed, rather than just saying some condition was supposed to be true and it was false. With this in mind, the first example below reads much better than the second:
# IF FAILED => "expected 10, got 7"
page.all('table#myTable tr').count.should == 10
# IF FAILED => "expected true, got false"
page.should have_css("table#myTable tr", :count=>10)
I think you can do this:
page.should have_css("table#mytable tr", :count=>3)
For some reason "has_css" does not work for me, however "all(selector)" works really wel
all("table#movies tr").count
I went with this in the end:
Then /^I should see "(.*)" once$/ do |text|
within_table('myTable') do
should have_xpath("//tr", :text => text, :count => 1)
end
end
which seemed suitably elegant.
I realise the other answers work but this seems to read well.
Any comments?
The method #find only returns one element (I think it just returns the first one if there are several matches) so you don't get a #length method because the result of #find is a Node not an Array.
To prove this to yourself, try
puts find("//table[#id='myTable']/tr").class
What you want is #all, which will return you an Array of all the matching nodes.
In this way you can learn the number of lines in the html table.
area = find_by_id('#areaID').all('tr').size
Assume that there are columns at the beginning of the table.You can reach the actual number in this way.
area = area-1

Resources