I have Sinatra application and need to test my application.
features/support/env.rb:
require_relative "../../application"
require "capybara"
require "capybara/cucumber"
require "rspec"
World do
Capybara.app = Application
include Capybara::DSL
include RSpec::Matchers
end
features/one.feature:
Feature: Test homepage
In order to make sure people can open my site
I want to check it opened
Scenario: Opening first page
Given I have opened homepage
Then I should see site header
Test it:
cucumber features\one.feature
Result:
Feature: Test homepage
In order to make sure people can open my site
I want to check it opened
Scenario: Opening first page # features\one.feature:5
Given I have opened homepage # features\one.feature:6
Then I should see site header # features\one.feature:7
1 scenario (1 undefined)
2 steps (2 undefined)
0m0.006s
You can implement step definitions for undefined steps with these snippets:
Given /^I have opened homepage$/ do
pending # express the regexp above with the code you wish you had
end
Then /^I should see site header$/ do
pending # express the regexp above with the code you wish you had
end
Well, I have created features/step_definitions/agenda_steps.rb:
Given /^I have opened homepage$/ do
pending # express the regexp above with the code you wish you had
end
Then /^I should see site header$/ do
pending # express the regexp above with the code you wish you had
end
Test it:
cucumber features\one.feature
Result:
Feature: Test homepage
In order to make sure people can open my site
I want to check it opened
Scenario: Opening first page # features\one.feature:5
Given I have opened homepage # features/step_definitions/agenda_steps.rb:1
C:/Ruby193/bin/cucumber:19: stack level too deep (SystemStackError)
Why and how can I fix it?
Updated: the problem dissapeared if I rewrite my env.rb like this:
require_relative "../../application"
require "capybara"
require "capybara/cucumber"
require "rspec"
Capybara.app = Application
#World do
# Capybara.app = Application
#
# include Capybara::DSL
# include RSpec::Matchers
#end
i was getting the same look alike error..as
stack level too deep (SystemStackError)
/usr/local/rvm/gems/ruby-1.9.2-p290/gems/cucumber-1.1.4/lib/cucumber/core_ext/instance_exec.rb:73..
i added require 'cucumber/rails' on first line of env.rb...which get loaded first.
Now no more im facing that error.
I believe that only Capybara.app = Application should not be declared inside World as show in your example.
So here is mine working env.rb:
ENV['RACK_ENV'] = 'test'
require File.join(File.dirname(__FILE__), '..', '..', 'rvs.rb')
require 'capybara'
require 'capybara/cucumber'
require 'rspec'
require 'r18n-core'
Capybara.app = RVS
class RVSWorld
include R18n::Helpers
include Capybara::DSL
include RSpec::Expectations
include RSpec::Matchers
end
World do
RVSWorld.new
end
As you can see RVSWorld class has only statements which includes necessary modules.
Related
I'm working on website test automation using Cucumber/Ruby/Selenium-Webdriver/Capybara. I want to switch to Watir-Webdriver in combination with Cucumber and Ruby, but I'm struggling with the following:
Every time I run my cucumber test, Watir opens two browser windows, a blank screen to the site I configurated as default, plus another in which the actual test steps are executed.
My 'Support/env.rb' file has:
require 'allure-cucumber'
require 'rspec'
require 'watir-webdriver'
AllureCucumber.configure do |c|
c.output_dir = 'D:\Test\result'
c.clean_dir = true
c.tms_prefix = '#PRACTEST--'
c.issue_prefix = '#JIRA++'
c.severity_prefix = '#URGENCY:'
c.tms_prefix = ''
end
My steps file begins with:
require 'watir-webdriver'
require 'cucumber'
require 'rspec'
require_relative 'D:\EntelTest\src\PageObject\home_page.rb'
Before do
#test = AbstractPage.new(Watir::Browser.new :ff)
#test.full_size
end
After do
#test.quit
end
home_page = nil
When(/^Go to home page$/) do
home_page = #test.goToHomePage
end
Can you put these before do and after do in hooks.rb? In the steps.rb file, just mention the code for your cucumber steps, and before that declare browser = Watir::Browser.new :ff
The best practice is to put it in hooks.rb. env.rb usually should consist the desired capabilities plus server environment codes. :)
What you have put in step file should go in hooks.rb file.
Please install gem called testnow.
It will help you to create most standard and easy to use watir-webdriver framework with all pre-configured browsers.
Steps:
1) gem install testnow
2) testnow watir_cucumber_now
It will as you to install dependecies, enter Y to set it up completely.
It will create robust framework with a sample scenario.
Just run the sample scenario with any of the following commands.
rake testnow BROWSER=firefox
rake testnow BROWSER=chrome
rake testnow BROWSER=opera
This will only work provided you have browsers pre-installed and webdriver present in PATH variable.
Please comment for more information.
Hope it helps!!
I am trying to add SimpleCov coverage to my gem that has a binary.
I would like to test its command line interface, so I wish to test the binary execution itself, and not the library it uses.
I am getting no coverage report (0 LOC) by SimpleCov.
As I understand, the issue is most likely due to the fact that in my test (either cucumber features or rspec specs), I am executing the gem's binary with system or popen3, but I don't know how I can tell SimpleCov to "follow through" (or if I am barking at the right tree...).
I have tried playing with SimpleCov.command_name, SimpleCov.pid = $$, SimpleCov.track_files and almost every other remotely related configuration I found.
I do not wish to use Aruba, although I have tried reviewing their source to look for possible answers.
Related code snippets:
# spec_helper.rb
require 'simplecov'
SimpleCov.start
require 'rubygems'
require 'bundler'
Bundler.require :default, :development
# test_spec.rb
require 'spec_helper'
describe "my bin" do
it "should be covered" do
system 'bin/runme'
end
end
I have prepared a minimal repo as an easy testing ground, if that helps at all.
well it's not easy to find a solution to this issue in particular.
not sure this solves your problem but maybe a start?
without the start block which modifies the filters i could not get SimpleCov to watch the bin directory (using the sample github repo you provided).
Used command_name to give the main processes coverage reports a name and then in the fork used command_name to give the forked processes report a name (SimpleCov merges them for us as long as they have different names).
then used load to load the bin file instead of using system.
(I couldn't figure out a way to make system or spawn add to the coverage reports, maybe if you called it through a script that restarts SimpleCov for you with an alternate command_name)
again, not sure if this is exactly what you are looking for but may be a start. code below:
# spec_helper.rb
require 'simplecov'
SimpleCov.command_name "main_report"
SimpleCov.start do
filters.clear # This will remove the :root_filter and :bundler_filter that come via simplecov's defaults
add_filter do |src|
!(src.filename =~ /^#{SimpleCov.root}/) unless src.filename =~ /bin/ #make sure the bin directory is allowed
end
end
require 'rubygems'
require 'bundler'
Bundler.require :default, :development
# test_spec.rb
require 'spec_helper'
describe "my bin" do
it "should be covered" do
pid = Process.fork do
SimpleCov.start do
command_name "bin_report_section"
end
load "bin/runme"
end
end
end
result:
Coverage report generated for bin_report_section, main_report to
/home/korreyd/simplecov-debug/coverage.
1 / 1 LOC (100.0%) covered.
Have you tried this? https://blog.yossarian.net/2018/04/01/Code-coverage-with-Simplecov-across-multiple-processes
Basically, in your spec_helper.rb
if ENV["COVERAGE"]
require "simplecov"
# Only necessary if your tests *might* take longer than the default merge
# timeout, which is 10 minutes (600s).
SimpleCov.merge_timeout(1200)
# Store our original (pre-fork) pid, so that we only call `format!`
# in our exit handler if we're in the original parent.
pid = Process.pid
SimpleCov.at_exit do
SimpleCov.result.format! if Process.pid == pid
end
# Start SimpleCov as usual.
SimpleCov.start
end
Then inside your bin/runme, add:
if ENV["COVERAGE"]
# Give our new forked process a unique command name, to prevent problems
# when merging coverage results.
SimpleCov.command_name SecureRandom.uuid
SimpleCov.start
end
Child process' test coverage will merge into the parent's process.
If you use SimpleCov's coverage_dir, make sure it's in all SimpleCov.start blocks so that results are written to same location.
I am writing a gem which includes a Sinatra application that a developer can extend. For example:
# gem code:
require 'sinatra'
module Mygem
class Application < Sinatra::Base
get 'auth/login' {}
get 'auth/logout {}
end
end
# developer code:
require 'mygem'
class DeveloperApp < Mygem::Application
# ..
end
I am also getting started using RSpec. How should I configure RSpec for testing this functionality?
The references above are all informative and useful but mostly rails specific. I found it quite hard to find a simple recipe for a basic test of a modular Sinatra app, so I am hoping this will answer the question for others. Here is a completely bare-bones, small as possible test. This is probably not the only way to do it, but it works well for a modular app:
require 'sinatra'
class Foo < Sinatra::Base
get '/' do
"Hello"
end
end
require 'rack/test'
describe Foo do
include Rack::Test::Methods
def app
Foo.new
end
it "should be testable" do
get '/'
last_response.should be_ok
end
end
Note that there is no need to have the server running when you launch the test (some tutorials I saw implied that you do) - it's not an integration test.
It's actually pretty simple -- just add rspec to your gemfile (then bundle install), and make a directory in your gem called spec/. Once you've done that, add a file spec/spec_helper.rb that contains some configuration for rspec (mostly requiring various files from your library) as well as defining some helper methods for your specs. Then, for each model and controller, make a file called my_model_name_spec.rb or my_controller_name_spec.rb, and do the test there.
Here are some useful resources for getting started with rspec:
Railscasts:
http://railscasts.com/episodes/275-how-i-test
http://railscasts.com/episodes/71-testing-controllers-with-rspec
http://railscasts.com/episodes/157-rspec-matchers-macros/
And for some more advanced (but well-explained) stuff:
http://benscheirman.com/2011/05/dry-up-your-rspec-files-with-subject-let-blocks
Be sure to include the rack-test gem.
You spec helper should have:
require 'rack/test'
require 'foo' # or where ever your app is
# This can go in a helper somewhere
module AppHelper
def app
Foo.new
end
end
RSpec.configure do |config|
config.include Rack::Test::Methods
config.include AppHelper
end
Then, your spec can be as follows:
require 'spec_helper'
# Example app. Delete this example.
class Foo < Sinatra::Base
get '/' do
'Jesse Pinkman'
end
end
describe Foo do
it 'is testable' do
get '/' do
expect(last_response).to be_ok
end
end
end
Ok so. I'm wanting to do request specs with RSpec for my Sinatra app.
I have a config.ru
# config.ru
require File.dirname(__FILE__) + '/config/boot.rb'
map 'this_route' do
run ThisApp
end
map 'that_route' do
run ThatApp
end
The boot.rb just uses Bundler and does additional requires for the rest of the app:
ThisApp looks like:
# lib/this_app.rb
class ThisApp < Sinatra::Base
get '/hello' do
'hello'
end
end
So I'm using RSpec and I want to write request specs like:
# spec/requests/this_spec.rb
require_relative '../spec_helper'
describe "This" do
describe "GET /this_route/hello" do
it "should reach a page" do
get "/hello"
last_response.status.should be(200)
end
end
it "should reach a page that says hello" do
get "/hello"
last_response.body.should have_content('hello')
end
end
end
end
This works fine because my spec_helper.rb is setup as follows:
# spec/spec_helper.rb
ENV['RACK_ENV'] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/boot")
require 'capybara/rspec'
RSpec.configure do |config|
config.include Rack::Test::Methods
end
def app
ThisApp
end
But my problem is that I want to test "ThatApp" from my rackup file along with any amount more apps I might add later along with "ThisApp". For example if I had a second request spec file:
# spec/requests/that_spec.rb
require_relative '../spec_helper'
describe "That" do
describe "GET /that_route/hello" do
it "should reach a page" do
get "/hello"
last_response.status.should be(200)
end
end
it "should reach a page that says hello" do
get "/hello"
last_response.body.should have_content('hello')
end
end
end
end
RackTest requires the rack app I'm testing be defined in the spec_helper file with that 'app' method, and I think eventually I'm going to have to feed Capybara.app the same thing as well when doing further request specs with it.
I feel like I'm missing something and maybe there's an easy way to setup 'app' for RackTest and Capybara at runtime depending on what route and consequent rack app I'm testing in my request specs. Like a before filter in RSpec.configure maybe, but I can't think of or find how I'd access what rack app is currently loaded and try and set it there before the test suite runs.
Anyone get what I'm trying to do and can think of something? Thanks for any help.
Define a different helper module for each sinatra app you want to test, each of which should define its own app method that returns the corresponding app. Then you can simply include MySinatraAppHelper in the appropriate example groups where you want to test the the given app.
You can also use rspec metadata to have the module included in example groups automatically.
Have a look at my sinatra-rspec-bundler-template. Especially at the spec files. I think that's what you are trying to achieve.
It combines two separate Sinatra apps each with it's own specs.
I'm building out a medium-sized application using Sinatra and all was well when I had a single app.rb file and I followed Aslak's guidance up on Github:
https://github.com/cucumber/cucumber/wiki/Sinatra
As the app grew a bit larger and the app.rb file started to bulge, I refactored out a lot of of the bits into "middleware" style modules using Sinatra::Base, mapping things using a rack-up file (config.ru) etc.
The app works nicely - but my specs blew up as there was no more app.rb file for webrat to run against (as defined in the link above).
I've tried to find examples on how to work this - and I think I'm just not used to the internal guts of Cuke just yet as I can't find a single way to have it cover all the apps. I tried just pointing to "config.ru" instead of app.rb - but that doesn't work.
What I ended up doing - which is completely hackish - is to have a separate app.rb file in my support directory, which has all the requires stuff so I can at least test the model stuff. I can also specify routes in there - but that's not at all what I want to do.
So - the question is: how can I get Cucumber to properly work with the modular app approach?
Update to include dealing with multiple Sinatra apps
Require the file where your app comes together and change
def app
Sinatra::Application
end
to
def app
Rack::Builder.new do
map '/a' { run MyAppA }
map '/b' { run MyAppB }
end
end
and just test the app proper.
eg, if you define middleware in your config.ru that you want to test, maybe move loading those into your app's definition.
Thanks to Mr. BaroqueBobcat - the answer now, of course, seems so damn obvious :). Here's the env.rb (/features/support/env.rb):
require 'sinatra'
require 'test/unit'
require 'spec/expectations'
require 'rack/test'
require 'webrat'
require 'app1'
require 'app2'
require 'app3'
Webrat.configure do |config|
config.mode = :rack
end
class MyWorld
require 'test/unit'
set :environment, :test
include Rack::Test::Methods
include Webrat::Methods
include Webrat::Matchers
Webrat::Methods.delegate_to_session :response_code, :response_body, :response
def app
Rack::Builder.new do
map '/' do
run App1 #important - this is the class name
end
map '/app1' do
run App2
end
map '/app2' do
run App3
end
end
end
end
World do
MyWorld.new
end
https://gist.github.com/28d510d9fc25710192bc
def app
eval "Rack::Builder.new {( " + File.read(File.dirname(__FILE__) + '/../config.ru') + "\n )}"
end