Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

re-introducing cucumber

  • Loading branch information...
commit 018ff1fc78bc84b815b7a909f82a18b37bd3615a 1 parent 3447cb8
Robert Fletcher + Tom Uebel authored
View
3  Gemfile
@@ -19,6 +19,7 @@ gem 'grosser-ssl_requirement', :require => 'ssl_requirement'
group :test do
gem 'shoulda'
+ gem 'cucumber', '1.1.0'
gem 'webrat', '0.7.3'
gem 'rspec', '1.3.2'
gem 'rspec-rails', '1.3.4'
@@ -36,6 +37,8 @@ group :development do
gem 'guard-rspec'
gem 'spork', '0.8.5'
gem 'guard-spork'
+ gem 'cucumber-rails', '0.3.2'
+ gem 'guard-cucumber'
#gem 'reek'
gem 'ruby2ruby', '1.2.2'
gem 'heckle'
View
20 Gemfile.lock
@@ -42,6 +42,15 @@ GEM
childprocess (0.3.5)
ffi (~> 1.0, >= 1.0.6)
columnize (0.3.6)
+ cucumber (1.1.0)
+ builder (>= 2.1.2)
+ diff-lcs (>= 1.1.2)
+ gherkin (~> 2.5.0)
+ json (>= 1.4.6)
+ term-ansicolor (>= 1.0.6)
+ cucumber-rails (0.3.2)
+ cucumber (>= 0.8.0)
+ diff-lcs (1.1.3)
factory_girl (1.3.3)
fakeweb (1.3.0)
fastercsv (1.5.4)
@@ -49,11 +58,16 @@ GEM
fleximage (1.0.4)
aws-s3
rmagick
+ gherkin (2.5.4)
+ json (>= 1.4.6)
grosser-ssl_requirement (0.1.0)
actionpack
guard (1.3.3)
listen (>= 0.4.2)
thor (>= 0.14.6)
+ guard-cucumber (0.7.5)
+ cucumber (>= 0.10)
+ guard (>= 0.8.3)
guard-rspec (1.2.1)
guard (>= 1.1)
guard-spork (1.2.0)
@@ -131,6 +145,9 @@ GEM
steak (1.1.0)
rspec (>= 1.3)
sys-proctable (0.9.1)
+ term-ansicolor (1.0.7)
+ test-unit (1.2.3)
+ hoe (>= 1.5.1)
thor (0.16.0)
webrat (0.7.3)
nokogiri (>= 1.2.0)
@@ -148,11 +165,14 @@ DEPENDENCIES
SystemTimer (= 1.2.2)
capybara
comma!
+ cucumber (= 1.1.0)
+ cucumber-rails (= 0.3.2)
factory_girl (= 1.3.3)
fakeweb
fastercsv (= 1.5.4)
fleximage (= 1.0.4)
grosser-ssl_requirement
+ guard-cucumber
guard-rspec
guard-spork
heckle
View
9 Guardfile
@@ -1,6 +1,7 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
-guard 'spork', :rspec_env => { 'RAILS_ENV' => 'test' } do
+
+guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' } do
watch('config/application.rb')
watch('config/environment.rb')
watch('config/environments/test.rb')
@@ -35,3 +36,9 @@ guard 'rspec', :version => 1, :cli => '--drb --color' do
watch(%r{^spec/acceptance/(.+)\.feature$})
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
end
+
+guard 'cucumber', :cli => '--drb --format progress --no-profile' do
+ watch(%r{^features/.+\.feature$})
+ watch(%r{^features/support/.+$}) { 'features' }
+ watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
+end
View
10 features/bug_7551_new_dash_data_throws_error.feature
@@ -0,0 +1,10 @@
+Feature: (#7551) New dash data throws error when the include_subworkstreams parameter is supplied
+
+Background:
+ Given I am logged in
+ And I am not an administrator
+
+Scenario: New dash data throws error
+ Given I belong to a public workstream
+ When I go to dash data
+ Then I do not see an error screen
View
20 features/extensions/capybara-webkit.rb
@@ -0,0 +1,20 @@
+Capybara::Driver::Webkit::Browser.class_eval do
+ @@pid = nil
+
+ def initialize(options = {})
+ @socket_class = options[:socket_class] || TCPSocket
+ ensure_server
+ connect
+ end
+
+ private
+
+ def ensure_server; start_server unless server_running?; end
+ def start_server
+ server_path = File.expand_path("#{gem_path}/bin/webkit_server", __FILE__)
+ @@pid = fork { exec(server_path) }
+ at_exit { Process.kill("INT", @@pid) }
+ end
+ def gem_path; @gem_path ||= Gem.loaded_specs["capybara-webkit"].full_gem_path; end
+ def server_running?; !@@pid.nil?; end
+end
View
22 features/extensions/webrat.rb
@@ -0,0 +1,22 @@
+Webrat.module_eval do
+ def self.session_class
+ if Webrat.configuration.mode == :selenium
+ Webrat::SeleniumSession
+ elsif Webrat.configuration.mode == :webkit
+ WebkitSession
+ else
+ Webrat::Session
+ end
+ end
+end
+
+Webrat::Scope.class_eval do
+ # Eliminates response caching so ajax can work
+ def dom # :nodoc:
+ if @selector
+ return scoped_dom
+ else
+ return page_dom
+ end
+ end
+end
View
82 features/public_work_streams_list.feature
@@ -0,0 +1,82 @@
+Feature:(#6137) Browse Bettermeans only shows public workstreams
+
+Background:
+ Given I am logged in
+ And I am not an administrator
+
+Scenario: I can see any public workstreams
+ Given I belong to a public workstream
+ When I go to Browse Bettermeans
+ Then I see it
+ Given a public workstream that I do not belong to
+ When I go to Browse Bettermeans
+ Then I see it
+
+Scenario: I cannot see private workstreams even when I am a member
+ Given a private workstream that I do not belong to
+ When I go to Browse Bettermeans
+ Then I do not see it
+ Given I belong to a private workstream
+ When I go to Browse Bettermeans
+ Then I do not see it
+
+Scenario: I cannot see private workstreams that I do not belong to but Anonymous does
+ Given a private workstream that I do not belong to
+ But the anonymous user is a member
+ When I go to Browse Bettermeans
+ Then I do not see it
+
+Scenario: Administrators cannot see any private workstreams
+ Given I am an administrator
+ And a private workstream that I do not belong to
+ When I go to Browse Bettermeans
+ Then I do not see it
+ Given I belong to a private workstream
+ When I go to Browse Bettermeans
+ Then I do not see it
+
+Scenario: Anonymous users can see all public workstreams
+ Given I am not logged in
+ Given I belong to a public workstream
+ When I go to Browse Bettermeans
+ Then I see it
+ Given a public workstream that I do not belong to
+ When I go to Browse Bettermeans
+ Then I see it
+
+Scenario: Anonymous users cannot see any private workstreams at all
+ Given I am not logged in
+ And a private workstream that I do not belong to
+ When I go to Browse Bettermeans
+ Then I do not see it
+ Given I belong to a private workstream
+ When I go to Browse Bettermeans
+ Then I do not see it
+
+Scenario: It only shows root workstreams
+ Given a public workstream that is a child of another public workstream
+ When I go to Browse Bettermeans
+ Then I do not see it
+
+Scenario: It only shows the top 10 workstreams
+ Given there are more than 10 workstreams available
+ When I go to Browse Bettermeans
+ Then I only see 10
+
+@ajax
+Scenario: I cannot see any private workstreams when I load more
+ Given there are 10 workstreams available
+ And a private workstream that I do not belong to
+ And I belong to a private workstream
+ When I go to Browse Bettermeans
+ And I load more
+ And I wait until loaded
+ Then I only see 10
+
+@ajax
+Scenario: I can see public workstreams when I load more
+ Given there are 11 workstreams available
+ When I go to Browse Bettermeans
+ And I load more
+ And I wait until loaded
+ Then I see 11
View
71 features/step_definitions/global_steps.rb
@@ -0,0 +1,71 @@
+Given /^I am logged in$/ do
+ Given "I am logged in as \"brian_dennehy\""
+end
+
+Given /^I am logged in as "([^\"]*)"$/ do |username|
+ @user = ensure_account username,username
+
+ teardown { User.delete @user if @user }
+
+ Then "Login in as #{username} with password #{username}"
+
+ assert_not_contain "Invalid user or password"
+end
+
+Given /^I am not logged in$/ do
+ visit "http://localhost:3000/logout"
+ @user = User.anonymous
+end
+
+Given /^I am(\snot)? an administrator$/ do |not_an_adminstrator|
+ is_admin = not_an_adminstrator.nil? or not_an_adminstrator
+ @user.admin = is_admin
+ @user.save!
+end
+
+Given /^Login in as ([^\"]*) with password ([^\"]*)$/ do |username, password|
+ visit "http://localhost:3000/login"
+ fill_in "username", :with => username
+ fill_in "password", :with => password
+ click_button "login"
+end
+
+When /^I go to Browse Bettermeans$/ do
+ visit "http://localhost:3000/projects"
+ @view = BrowseBettermeansView.new webrat_session
+end
+
+When /^I go to dash data$/ do
+ the_project = projects.last
+ visit "http://localhost:3000/projects/#{the_project.id}/new_dashdata?include_subworkstreams=true"
+end
+
+When /^I wait until/ do
+ @view.wait_until_loaded
+end
+
+Then /^I do not see an error screen/ do
+ webrat_session.response_body.should_not contain "Action Controller: Exception caught"
+end
+
+def ensure_account(username, password)
+ result = User.find_by_login(username)
+
+ result = create_account(username, password) unless result
+
+ result
+end
+
+def create_account(username, password)
+ new_user = User.new
+ new_user.login = username
+ new_user.firstname = username
+ new_user.lastname = username
+ new_user.password = password
+ new_user.admin = false
+ new_user.mail = "#{username}@xxx.com"
+
+ new_user.save!
+
+ new_user
+end
View
108 features/step_definitions/workstream_steps.rb
@@ -0,0 +1,108 @@
+Given /^I belong to a public workstream$/ do
+ Given "a public workstream that I do not belong to"
+ add_me_as_a_member_of projects.last
+end
+
+Given /^a public workstream that I do not belong to$/ do
+ projects << project = new_public_project("[#{Time.now.to_i}] Any public workstream")
+end
+
+Given /^there are more than (\d+) workstreams available$/ do |count|
+ Given "there are #{count.to_i + 1} workstreams available"
+end
+
+Given /^there are (\d+) workstreams available$/ do |count|
+ Project.delete_all
+
+ for i in 1..(count.to_i) do
+ projects << new_public_project("[#{Time.now.to_i}] Workstream (#{i})")
+ end
+end
+
+Given /a public workstream that is a child of another public workstream/ do
+ projects << parent = new_public_project("[#{Time.now.to_i}] Parent")
+ projects << child = new_public_project("[#{Time.now.to_i}] Child")
+
+ child.move_to_child_of parent
+ child.parent_id.should(eql(parent.id),
+ "Failed to add project <#{child.name}> as child of <#{parent.name}>"
+ )
+end
+
+Given /^I belong to a private workstream$/ do
+ projects << new_private_project("[#{Time.now.to_i}] Someone else's private")
+
+ add_me_as_a_member_of projects.last
+end
+
+Given /^a private workstream that I do not belong to$/ do
+ projects << new_private_project("[#{Time.now.to_i}] Someone else's private")
+end
+
+Given /^the anonymous user is a member$/ do
+ fail("No project yet, can't add anonymous as a member") unless projects.last
+ add_as_member User.anonymous, projects.last
+end
+
+When /I load more/ do
+ @view.load_more_latest_public_workstreams
+ @view.load_more_most_active_public_workstreams
+end
+
+Then /^I see it$/ do; Then "it is visible"; end
+
+Then /^I do not see it$/ do; Then "it is not visible"; end
+
+Then /^it is(\snot)? visible$/ do |not_visible|
+ show_or_not = not_visible ? "does not show" : "shows"
+ Then "it #{show_or_not} in the Latest Public Workstreams list"
+ Then "it #{show_or_not} in the Most Active Public Workstreams list"
+end
+
+Then /^it shows in the Latest Public Workstreams list$/ do
+ @view.latest_public_workstreams.should include @projects.last.name
+end
+
+Then /^it does not show in the Latest Public Workstreams list$/ do
+ @view.latest_public_workstreams.should_not include @projects.last.name
+end
+
+Then /^it shows in the Most Active Public Workstreams list$/ do
+ @view.most_active_public_workstreams.should include @projects.last.name
+end
+
+Then /^it does not show in the Most Active Public Workstreams list$/ do
+ @view.most_active_public_workstreams.should_not include @projects.last.name
+end
+
+Then /I(\sonly)? see (\d+)/ do |_,expected_count|
+ @view.latest_public_workstreams.size.should eql expected_count.to_i
+ @view.most_active_public_workstreams.size.should eql expected_count.to_i
+end
+
+def new_public_project(name); new_project name, true; end
+
+def new_private_project(name); new_project name, false; end
+
+def new_project(name, _public=false)
+ result = Project.new
+ result.name = name
+ result.is_public = _public
+ result.save!
+ result
+end
+
+def add_me_as_a_member_of(project); add_as_member @user, project; end
+
+def add_as_member(user, project)
+ project.members << Member.new(:user => user, :roles => [Role.administrator])
+end
+
+def projects
+ unless @projects
+ @projects = []
+ teardown { @projects.each {|project| project.delete} }
+ end
+
+ @projects
+end
View
61 features/support/env.rb
@@ -0,0 +1,61 @@
+require 'rubygems'
+require 'spork'
+
+Spork.prefork do
+
+ ENV["RAILS_ENV"] ||= "cucumber"
+ require File.expand_path(File.dirname(__FILE__) + '/../../config/environment')
+ require 'cucumber/rails/world'
+
+ dir = File.expand_path File.dirname(__FILE__)
+
+ Dir.glob(File.join dir, "views","*.rb").each { |file| require file }
+
+ Cucumber::Rails::World.use_transactional_fixtures = false
+
+ ActionController::Base.allow_rescue = false
+
+ require 'cucumber'
+ require 'cucumber/formatter/unicode'
+ require 'cucumber/rails/rspec'
+
+ require 'webrat'
+ require 'webrat/core/matchers'
+
+ require "features/support/webkit_session"
+ require "features/extensions/webrat.rb"
+ require "features/extensions/capybara-webkit.rb"
+
+ Webrat.configure do |config|
+ config.mode = :rails
+ config.open_error_files = true
+ end
+
+ Cucumber::Rails::World.class_eval do
+ def skip_teardown?; ENV.include? "SKIP_TEARDOWN"; end
+ def teardown(&block)
+ (@teardowns ||= []) << block
+ end
+ end
+
+ Before do |scenario|
+ default_mode = :rails
+
+ Webrat.configure do |config|
+ config.mode = scenario.source_tag_names.include?("@ajax") ? :webkit : default_mode
+ config.open_error_files = true
+ end
+ end
+
+ After do
+ unless skip_teardown?
+ @teardowns.each {|proc| proc.call} unless @teardowns.nil?
+ end
+ end
+
+end
+
+Spork.each_run do
+
+end
+
View
41 features/support/garcon_dsl.rb
@@ -0,0 +1,41 @@
+module GarconDsl
+ def wait; GarconBuilder.new; end
+
+ class GarconBuilder
+ def for(timeout = 10)
+ @timeout = timeout
+ self
+ end
+
+ def until(&block)
+ Garcon.new(1, @timeout).wait &block
+ end
+ end
+
+ class Garcon
+ def initialize(polling_period, timeout)
+ @polling_period = polling_period
+ @timeout = timeout
+ end
+
+ def wait(&block)
+ fail("Missing block") unless block_given?
+
+ started_at = Time.now
+ done = false
+
+ while !done do
+ elapsed = (Time.now-started_at).seconds
+ timeout elapsed
+ done = block.call
+ sleep @polling_period
+ end
+ end
+
+ private
+
+ def timeout(elapsed)
+ fail("Timed out after waiting for <#{elapsed}>.") if elapsed > @timeout
+ end
+ end
+end
View
47 features/support/views/browse_bettermeans_view.rb
@@ -0,0 +1,47 @@
+require File.join(File.dirname(__FILE__), "view")
+
+class BrowseBettermeansView < View
+ def initialize(session)
+ @xpath = ".//div[@class='gt-content-box']/table/tbody/tr/td/" +
+ "div[@class='project-summary']"
+
+ @title_xpath = "#{@xpath}/h4/a/text()"
+
+ super session
+ end
+
+ def latest_public_workstreams
+ session.within "div.splitcontentright" do |scope|
+ xpath(scope.dom, @title_xpath).map {|_|_.content}
+ end
+ end
+
+ def most_active_public_workstreams
+ session.within "div.splitcontentleft" do |scope|
+ xpath(scope.dom, @title_xpath).map {|_|_.content}
+ end
+ end
+
+ def load_more_latest_public_workstreams
+ session.click_link "latest_load_more"
+ end
+
+ def load_more_most_active_public_workstreams
+ session.click_link "active_load_more"
+ end
+
+ require 'features/support/garcon_dsl'
+ include GarconDsl
+
+ def wait_until_loaded
+ wait.for(5.seconds).until { is_hidden? loading_screen }
+ end
+
+ def loading_screen
+ xpath(session.current_dom, "//*[@id='ajax-indicator']").first
+ end
+
+ private
+
+ def is_hidden?(element); element["style"] =~ /display\: none/; end
+end
View
9 features/support/views/view.rb
@@ -0,0 +1,9 @@
+class View
+ def initialize(session); @session = session; end
+
+ protected
+
+ attr_reader :session
+
+ def xpath(dom, xpath); dom.xpath(xpath); end
+end
View
108 features/support/webkit_session.rb
@@ -0,0 +1,108 @@
+class WebkitSession
+ require 'capybara-webkit'
+
+ def initialize(driver=Capybara::Driver::Webkit.new(nil)) #todo: inject without default
+ @driver = driver
+ @scope_factory = WebratScopeFactory
+ end
+
+ %w[link button].each do |name|
+ define_method "click_#{name}".to_sym do |what|
+ click what
+ end
+ end
+
+ def click(what)
+ the_thing = find_first(what)
+
+ the_thing.click
+ end
+
+ def get(url)
+ driver.reset!
+ clear_scope
+ driver.visit url
+ end
+
+ alias visit :get
+
+ def response_body; driver.body; end
+
+ def fill_in(what, options = {:with => ""})
+ field = find what
+
+ fail("Could not find text field with id \"#{what}\"") unless field.size == 1
+
+ field.first.set options[:with]
+ end
+
+ def find_first(what)
+ result = find what
+
+ fail "Unable to locate element <#{what}>" unless result
+ fail "Too many elements found. Expected <1>. Got <#{result.size}>." unless
+ result.size === 1
+
+ result.first
+ end
+
+ def find(what)
+ result = find_by_id_or_name what
+ return result if result.size > 0
+
+ result = find_by "value", what
+ return result if result.size > 0
+
+ fail "Unable to locate element <#{what}>" if result.nil?
+ end
+
+ def find_by_id_or_name(what)
+ result = find_by "id", what
+ return result if result.size > 0
+ find_by "name", what
+ end
+
+ def url; driver.current_url; end
+
+ def select; end
+
+ def within(selector)
+ scopes.push(@scope_factory.from_scope(self, current_scope, selector))
+ ret = yield(current_scope)
+ scopes.pop
+ return ret
+ end
+
+ def xml_content_type?; false; end
+
+ def current_dom; current_scope.dom; end
+
+ private
+
+ def driver; @driver end
+
+ def find_by(attribute, value)
+ driver.find("//*[@#{attribute}='#{value}']");
+ end
+
+ def current_scope; scopes.last || page_scope; end
+ def clear_scope; clear_page_scope; clear_dom_scope; end
+ def clear_page_scope; @_page_scope = nil; end
+ def clear_dom_scope; @scopes = nil; end
+
+ def page_scope
+ @scope_factory.from_page(self, response_body)
+ end
+
+ def scopes; @scopes ||= []; end
+end
+
+class WebratScopeFactory
+ def self.from_page(session, response_body)
+ Webrat::Scope.from_page(session, Object.new, response_body)
+ end
+
+ def self.from_scope(session, scope, selector)
+ Webrat::Scope.from_scope(session, scope, selector)
+ end
+end
View
84 spec/webkit_session_example_spec.rb
@@ -0,0 +1,84 @@
+require "spec_helper"
+
+require "features/support/webkit_session.rb"
+
+describe WebkitSession,"#click" do
+ before :each do
+ @driver = stub("A fake driver")
+ end
+
+ it "fails if the element cannot be found" do
+ session = WebkitSession.new @driver
+
+ driver.stub(:find).once.and_return []
+
+ lambda{session.click "xxx"}.should raise_error "Unable to locate element <xxx>"
+ end
+
+ it "fails if there are multiple elements found" do
+ session = WebkitSession.new @driver
+
+ driver.stub(:find).once.and_return [Object.new,Object.new]
+
+ lambda{session.click "xxx"}.should raise_error "Too many elements found. Expected <1>. Got <2>."
+ end
+
+ it "you can click anything"
+
+ private
+
+ attr_reader :driver
+end
+
+describe WebkitSession,"#find" do
+ before :each do
+ @driver = stub("A fake driver")
+ end
+
+ it "tries to find elements by id, name and value" do
+ element_identifier = "xxx"
+
+ driver.should_receive(:find).with("//*[@id='#{element_identifier}']").and_return []
+ driver.should_receive(:find).with("//*[@name='#{element_identifier}']").and_return []
+ driver.should_receive(:find).with("//*[@value='#{element_identifier}']").and_return []
+
+ session.find element_identifier
+ end
+
+ it "returns nil if element cannot be found by id, name or value" do
+ element_identifier = "xxx"
+
+ driver.should_receive(:find).with("//*[@id='#{element_identifier}']").and_return []
+ driver.should_receive(:find).with("//*[@name='#{element_identifier}']").and_return []
+ driver.should_receive(:find).with("//*[@value='#{element_identifier}']").and_return []
+
+ result = session.find element_identifier
+ result.should be_nil
+ end
+
+ private
+ attr_reader :driver
+ def session; @session ||= WebkitSession.new @driver; end
+end
+
+describe WebkitSession,"#get" do
+ before :each do
+ @driver = stub("A fake driver")
+ end
+
+ it "resets its driver when get is called" do
+ driver.should_receive(:reset!).once
+ driver.stub(:visit)
+ session.get "http://xxx.com"
+ end
+
+ private
+
+ attr_reader :driver
+ def session; @session ||= WebkitSession.new @driver; end
+end
+
+describe WebkitSession do
+ it "clears all scope when get is called"
+ it "supplies a dummy 'response' argument (not nil) when invoking Webrat::Scope.from_page to stop response caching error"
+end
Please sign in to comment.
Something went wrong with that request. Please try again.