How to use rspec-expectations outside cucumber step-definitions - ruby

I'm using watir-cucumber for test automation. I wrote following method in a separate .rb, this method is not in step definitions.
def has_logged_in?
$browser.text.should include("t788")
end
When I call this method from step definition this error comes,
wrong argument type String (expected Module) (TypeError)
the same code works fine in step definitions. I searched around and found out that include method is used to include module but that is ruby-include method and should include comes under rspec\expectations. So how do I call should include method outside step definition like above.
I'm using watir-cucumber on linux

The include method that you want is in the RSpec::Matchers module.
If your has_logged_in? method is in a class (not part of main), you can include the RSpec::Matchers module in your class. This would give you access to the include method.
So your class would look like:
class YourClass
include RSpec::Matchers
def has_logged_in?
$browser.text.should include("t788")
end
end
Note: I have not had to do this before, but from a quick check, it does work as long as the RSpec::Matchers are included in a class rather than the main. Including it in the main does not appear to do anything (ie include continues to call the standard include module method). I did not explore to see if if there are any negative side effects of doing this.

In your gem file:
gem 'rspec', "1.3.2", :require => "spec/expectations"
Or in your env.rb for RSpec 1.X.X:
require 'spec/expectations'
Or in your env.rb for RSpec 2.X:
require 'rspec/expectations'

Related

Want help regarding 'module' usage in ruby project (using 3rd party gem of 'ruby-jmeter'

I am trying to create performance automation framework for my company . Beinbg newbie to ruby field , I thought to keep it simple . Here is structure for performance framewrok
I do have multiple ruby files , as request.rb,payload.rb etc in 'common' folder(as these are containing some utilities) and then my test in test.rb (under one of 'TestFlows->SimpleFlow->test.rb) .
See above structure for more detail
Exact Code , which I am having right now under those files are
request.rb
require 'ruby-jmeter' #(Consider any 3rd party gem )
require 'rubygems'
module Company #Note that i am using same module name 'company'
module Request
def self.send_request()
visit '192.148.1.2' # this is function defined under ruby-jmeter
end
end
end
payload.rb
require 'ruby-jmeter' #(Consider any 3rd party gem )
require 'rubygems'
module Company #Note that i am using same module 'company'
module Payload
def self.get_payload()
------- Again some 'ruby-jmeter' function calls
end
end
end
etc files as well
Test.rb
require 'ruby-jmeter' #(Consider any 3rd party gem )
require 'rubygems'
require 'require_all' #(gem to load all files from folder)
require_all '../../common/'
module Company #Note that i am using same module 'company'
test name:'GooglePerformanceTest' do
defaults domain: 'http://google.com' ,protocol: http
threads name: 'NoOfUsers',scheduler: false,continue_forever:
false, count: 2 do
Request.send_request()
end
end #end of testPlan
view_results_tree
puts "JMX FILE IS GONNA SAVED #
"+Dir.pwd+"/CreatedJMeter_DB2Navigation.jmx"
end.jmx(file: Dir.pwd+"/CreatedJMeter_DB2Navigation.jmx")
end
When I run this programme , it goes to above , I am getting errors of those (3rd party ruby gem's function undefined).
Can anyone point me out my problem regarding above structure & suggest me proper way to do this ?
edit :
I am getting below error
Test.rb:3:in `send_request': undefined method `visit ' for
company::Request:Module (NoMethodError)
Edit
Have defined my changes here & it is working fine
Facing issues while calling method of module(having object of class , contained in another ruby file)
I'm assuming you're using the gem hosted at this repository: https://github.com/flood-io/ruby-jmeter, latest release version (2.13.8).
Looking through the source code and examples, there are a couple things to think about.
The 'visit' method is an alias for a method called 'get' defined here
.
That is an object method, for an object of class RubyJmeter::ExtendedDSL. You are using module methods, and should probably consider making an object and calling the method on that.
obj = RubyJmeter::ExtendedDSL.new
obj.visit '192.148.1.2' # 'visit' is a method alias for 'get'
However, the examples listed by the gem developer follow a different pattern, calling 'visit' from within a closure (the do..end code block, known simply as a 'block' in Ruby). You could rewrite your code to build test plans and run them in this fashion.
It's not clear from what you post why you are using modules. Typically, you use 'include' within a Module or Class to mix in the gem's methods into your namespace. But since you're attempting to use module methods, I'm not sure mixing in object methods will be fruitful.
Since I can't see how your Test.rb file is run, I can't say for sure that your test code is loading your own modules. Typically a 'load' or 'include' statement would be used to load the code you wrote in request.rb and payload.rb
Personally, I'd try to follow the pattern shown by the developer of RubyJmeter; as a second approach, I'd write a class that inherits from RubyJemeter's subclass and extend its behavior to suit. My test code would initialize an object and call its methods directly. (Your Mileage May Vary.)
Updated to add: if you want your module method to stand in place of the object method mentioned, you can simply call the latter inside your method:
def self.send_request()
RubyJmeter::ExtendedDSL.new.visit '192.148.1.2'
end
Doing this essentially creates a disposable object, which is destroyed after the :visit method returns its data.
P.S. Always capitalize your class and module names. It's a Ruby best practice and your module name 'company' will raise warnings from the interpreter.

Undefined method 'delegate' for capybara::dsl::module

I have a capybara monkey patch to deal with jquery-ui, which works pretty well running on Ubuntu... although when moving to windows I get the following error (all dependency gems were installed successfully):
Undefined method 'delegate' for capybara::dsl::module
The line of code that this occurs is:
module Capybara::DSL
delegate :datepick, :datetimepick, :timepick, to: :page
end
any ideas of what this could be? a bit lost of why this error is shown just by switching OS...
In standard ruby delegation is handled by the module Forwardable. You need to require and then extend Forwardable to access these methods like so:
require 'forwardable'
module Capybara::DSL
extend Forwardable
#notice syntax is accessor, *methods
def_delegators :page, :datepick, :datetimepick, :timepick
end
The type of delegation you are trying to use right now is part of active support Module Class. If you would like to use this syntax then do so like this:
require 'active_support/core_ext/module'
module Capybara::DSL
#active_support syntax allows a to: element in the hash to act as the accessor
delegate :datepick, :datetimepick, :timepick, to: :page
end

Is there an rspec matcher to confirm a class includes a library, module or gem?

Found this tutorial using minitest, and was wondering if there is an equivalent matcher in rspec:
Interesting minitest assertion
describe "default attributes" do
it "must include httparty methods" do
Dish::Player.must_include HTTParty
end
it "must have the base url set to the Dribble API endpoint" do
Dish::Player.base_uri.must_equal 'http://api.dribbble.com'
end
end
Testing if a class has included a module is generally wrong, as you are testing implementation details instead of expected behavior.
Included modules can be found by calling ancestors on the class, so you can simply use include matcher:
expect(Dish::Player.ancestors).to include(HTTParty)
Your second expectation should be tested with:
expect(Dish::Player.base_uri).to eq 'http://api.dribbble.com'
EDIT
Until today I did not know that classes implement the <=> operator. You can simply check if Dish::Player < HTTParty.
You could use be_kind_of it also works for included modules:
"expect(obj).to be_kind_of(type): calls obj.kind_of?(type), which returns true if type is in obj's class hierarchy or is a module and is included in a class in obj's class hierarchy." -- https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/type-matchers
it { is_expected.to be_kind_of(HTTParty) }

Kaminari and Capybara conflict

I seem to have some sort of conflict between the page method of capybara and the page method of Kaminari.
That's what I guessed, anyway, here is the error :
Failure/Error: before { sign_in_as user }
ActionView::Template::Error:
wrong number of arguments (1 for 0)
# ./app/models/feed.rb:9:in `microposts'
[Rest of the backtrace]
The code sample :
class Feed
def microposts(opts = { urgent: false })
urgent = opts[:urgent]
p Microposts.where(id: 1).page # <Capybara::Session>
p Microposts.where(id: 1).page(1) # Error
end
end
If I remove the pagination, the test works fine.
I don't understand how this is possible, I guess Capybara is adding the "page" method to the Object scope, but as Kaminari add its page method to ActiveRecord::Base (if I recall correctly) it should override Capybara's one.
I did not see anyone having this kind of trouble, how is it possible ?
Thanks.
I had the same problem with Capybara 2.x
My feature specs are in the spec/feature directory. I realised from reading the Capybara documentation that there is no need to include the Capybara::DSL in your spec_helper if your using the features directory. It's already included.
There is a warning given if you include Capybara::DSL in the spec_helper that it will pollute the global namespace and this is exactly why it's a bad idea!
Check out this rspec-rails page on Capybara for details
This is a little bit of a hack but I was able to work around the problem (where Capybara 'pollutes' the object space) by undef-ing the method in my spec:
# Capybara adds a 'page' method to the Object class which conflicts with the Kaminari scope
# Remove it here to allow things to work
Object.send :undef_method, :page
I have traced back where this is happening and essentially:
The #page method comes from Capybara::DSL
The Capybara::DSL method is included into the Object class via RSpec's #configure.include method (see lib/capybara/rspec.rb).
RSpec then includes it into the 'group', however I believe this is where it drops into Object.
The solution here might just be to change the name of the method in Capybara, but I guess thats not a decision I'm willing to make :)

Getting methods into plain file dynamically in Ruby

I've noticed in some gems, when you simply require 'some_gem', methods will appear (without any monkey patching to my knowledge). I've seen it in some gems like Sinatra, Rake, Rails, and many other helper libraries and such. How would one manage to accomplish this in ones own library?
Example:
require 'sinatra'
# Automatically recieve the 'get' method
get('/') { "I was monkeypatched or included automatically." }
If it is monkeypatching, what classes/modules are common for monkeypatching (other than String, Numeric, Array, etc).
Sinatra is essentially adding those as global methods. When you require sinatra, it extends the Object class with Sinatra::Delegator which is defined in sinatra/base.rb. Methods such as get and put are defined in base, and added via the delegator.
In addition to Beerlington's answer, Rails, for example, and specifically it's part ActiveSupport, uses exactly monkeypatching.
For example, declaration of blank? method from the ActiveSupport source (stripped):
class Object
def blank?
respond_to?(:empty?) ? empty? : !self
end
end
Also, very common approach to monkeypatch Kernel module to add methods that will be available everywhere:
# hello.rb
module Kernel
def say_hello
"Hello!"
end
end
And usage of it:
require 'hello.rb'
=> true
say_hello
=> "Hello!"

Resources