cucumber_tree 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .rvmrc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cucumber_tree.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Gabriel Reis
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,83 @@
1
+ # Cucumber Tree
2
+
3
+ Organize your features in a tree directory and don't waste your cpu time running the same steps over and over.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ group :test do
10
+ gem 'cucumber_tree', require: false
11
+ end
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ If you already have installed cucumber-rails, go to the next step. Otherwise execute:
18
+
19
+ $ rails g cucumber:install
20
+
21
+ Add the option "--require features" to the std_opts in config/cucumber.yml:
22
+
23
+ std_opts = "--require features --format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
24
+
25
+ Change the file "features/support/env.rb" to require 'cucumber_tree'. It should be after the 'cucumber/rails' line:
26
+
27
+ require 'cucumber/rails'
28
+ require 'cucumber_tree'
29
+
30
+ This gem depends on database_cleaner and overrides the default strategy to :truncation, so you could remove all the references to DatabaseCleaner inside features/support/env.rb
31
+
32
+ ## Usage
33
+
34
+ Given an application to manage products and the following scenarios:
35
+
36
+ 1. User signs in
37
+ 2. User adds a new product
38
+ 3. User edits a product
39
+
40
+ Using cucumber_tree your tests should be organized in a tree directory:
41
+
42
+ ```
43
+ |-- features
44
+ ` |-- sign_in.feature
45
+ `-- sign_in
46
+ |-- add_product.feature
47
+ `-- add_product
48
+ `-- edit_product.feature
49
+ ```
50
+
51
+ Each feature contains only the necessary steps:
52
+
53
+ features/sign_in.feature
54
+ Feature:
55
+ Scenario:
56
+ Given I am signed in
57
+ Then I should see a welcome message
58
+
59
+ features/sign_in/add_product.feature
60
+ Feature:
61
+ Scenario:
62
+ When I click to add a new product
63
+ And I create a new product
64
+ Then I should see a message for product creation
65
+
66
+ features/sign_in/add_product/edit_product.feature
67
+ Feature:
68
+ Scenario:
69
+ When I click to edit the product
70
+ And I update the product
71
+ Then I should see a message for product update
72
+
73
+ When you execute `$ cucumber` the file sign_in.feature is the first to run. When it's done, then a snapshot of the current state (database, cookies, current page) is taken. This snapshot is loaded and the file add_product.feature runs. Another snapshot and finally the file edit_product.feature runs.
74
+
75
+ If you execute `$ cucumber features/sign_in/add_product/edit_product.feature` then all the parent features will be executed before it.
76
+
77
+ ## Contributing
78
+
79
+ 1. Fork it
80
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
81
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
82
+ 4. Push to the branch (`git push origin my-new-feature`)
83
+ 5. Create new Pull Request
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+
3
+ task :default do
4
+ ["rspec", "cucumber"].each do |cmd|
5
+ puts "Starting to run #{cmd}..."
6
+ system(cmd)
7
+ raise "#{cmd} failed!" unless $?.exitstatus == 0
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/cucumber_tree/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Gabriel Reis"]
6
+ gem.email = ["gabriel.oreis@gmail.com"]
7
+ gem.description = %q{Organize your features in a tree directory and don't waste your CPU time running the same steps over and over.}
8
+ gem.summary = %q{Better way to organize your features}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "cucumber_tree"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = CucumberTree::VERSION
17
+
18
+ gem.add_runtime_dependency 'cucumber-rails', '>= 1.3.0'
19
+ gem.add_runtime_dependency 'database_cleaner', '>= 0.7.2'
20
+ gem.add_runtime_dependency 'rspec', '>= 2.9.0'
21
+
22
+ gem.add_development_dependency 'aruba', '>= 0.5.0'
23
+ gem.add_development_dependency 'bundler', '>= 1.1.0'
24
+ gem.add_development_dependency 'rails', '>= 3.2.8'
25
+ gem.add_development_dependency 'sqlite3', '>= 1.3.6'
26
+ gem.add_development_dependency 'pg', '>= 0.14.1'
27
+
28
+ # Dependencies that Rails puts inside apps.
29
+ gem.add_development_dependency 'sass-rails', '>= 3.2.5'
30
+ gem.add_development_dependency 'coffee-rails', '>= 3.2.2'
31
+ gem.add_development_dependency 'uglifier', '>= 1.2.4'
32
+ gem.add_development_dependency 'jquery-rails', '>= 2.0.2'
33
+ end
@@ -0,0 +1,57 @@
1
+ Feature: Cookies Snapshot
2
+ Scenario:
3
+ Given I have created a new rails app
4
+ And I write to "app/controllers/cookies_controller.rb" with:
5
+ """
6
+ class CookiesController < ApplicationController
7
+ def index
8
+ render text: cookies[:page]
9
+ end
10
+
11
+ def new
12
+ cookies[:page] = 'new cookie'
13
+ render nothing: true
14
+ end
15
+ end
16
+ """
17
+ And I write to "config/routes.rb" with:
18
+ """
19
+ TestApp::Application.routes.draw do
20
+ resources :cookies
21
+ end
22
+ """
23
+ And I write to "features/parent.feature" with:
24
+ """
25
+ Feature:
26
+ Scenario:
27
+ Given I go to the new cookie page
28
+ """
29
+ And I write to "features/parent/child.feature" with:
30
+ """
31
+ Feature:
32
+ Scenario:
33
+ When I go to the cookies display page
34
+ Then I should see "new cookie"
35
+ """
36
+ And I write to "features/step_definitions/all_steps.rb" with:
37
+ """
38
+ When /^I go to the new cookie page$/ do
39
+ visit '/cookies/new'
40
+ end
41
+
42
+ When /^I go to the cookies display page$/ do
43
+ visit '/cookies'
44
+ end
45
+
46
+ Then /^I should see "(.*)"$/ do |content|
47
+ page.should have_content(content)
48
+ end
49
+ """
50
+ And I run `bundle exec rake db:migrate`
51
+
52
+ When I run `bundle exec cucumber`
53
+ Then it should pass with:
54
+ """
55
+ 2 scenarios (2 passed)
56
+ 3 steps (3 passed)
57
+ """
@@ -0,0 +1,66 @@
1
+ Feature: Current Url Snapshot
2
+ Scenario:
3
+ Given I have created a new rails app
4
+ And I write to "app/controllers/users_controller.rb" with:
5
+ """
6
+ class UsersController < ApplicationController
7
+ def index
8
+ render text: 'Users Index'
9
+ end
10
+ end
11
+ """
12
+ And I write to "config/routes.rb" with:
13
+ """
14
+ TestApp::Application.routes.draw do
15
+ resources :users
16
+ end
17
+ """
18
+ And I write to "features/parent.feature" with:
19
+ """
20
+ Feature:
21
+ Scenario:
22
+ Given I go to the users page
23
+ """
24
+ And I write to "features/parent/child.feature" with:
25
+ """
26
+ Feature:
27
+ Scenario:
28
+ Then I should be on the users page
29
+ """
30
+ And I write to "features/another.feature" with:
31
+ """
32
+ Feature:
33
+ Scenario:
34
+ Given I go to the index page
35
+ """
36
+ And I write to "features/step_definitions/all_steps.rb" with:
37
+ """
38
+ When /^I go to the users page$/ do
39
+ visit '/users'
40
+ end
41
+
42
+ When /^I go to the index page$/ do
43
+ visit '/'
44
+ end
45
+
46
+ Then /^I should be on the users page$/ do
47
+ page.current_path.should == '/users'
48
+ end
49
+ """
50
+ And I run `bundle exec rake db:migrate`
51
+
52
+ # Running only child feature
53
+ When I run `bundle exec cucumber features/parent/child.feature`
54
+ Then it should pass with:
55
+ """
56
+ 2 scenarios (2 passed)
57
+ 2 steps (2 passed)
58
+ """
59
+
60
+ #Running entire suite test
61
+ When I run `bundle exec cucumber`
62
+ Then it should pass with:
63
+ """
64
+ 3 scenarios (3 passed)
65
+ 3 steps (3 passed)
66
+ """
@@ -0,0 +1,80 @@
1
+ Feature: Database Snapshot
2
+ Scenario: Sqlite
3
+ Given I have created a new rails app
4
+ And I write to "features/parent.feature" with:
5
+ """
6
+ Feature:
7
+ Scenario:
8
+ Given 1 user
9
+ """
10
+ And I write to "features/parent/child.feature" with:
11
+ """
12
+ Feature:
13
+ Scenario:
14
+ Then 1 user should be created
15
+ """
16
+ And I write to "features/step_definitions/all_steps.rb" with:
17
+ """
18
+ When /^(\d+) users?$/ do |count|
19
+ User.create
20
+ end
21
+
22
+ Then /^(\d+) users? should be created$/ do |count|
23
+ User.count.should == count.to_i
24
+ end
25
+ """
26
+ And I write to "features/z-last-feature-to-run.feature" with:
27
+ """
28
+ Feature:
29
+ Scenario: Testing truncation
30
+ Then 0 users should be created
31
+ """
32
+ And I run `rails g model user`
33
+ And I run `bundle exec rake db:migrate db:test:prepare`
34
+
35
+ When I run `bundle exec cucumber`
36
+ Then it should pass with:
37
+ """
38
+ 3 scenarios (3 passed)
39
+ 3 steps (3 passed)
40
+ """
41
+
42
+ Scenario: Postgresql
43
+ Given I have created a new rails app with postgresql
44
+ And I write to "features/parent.feature" with:
45
+ """
46
+ Feature:
47
+ Scenario:
48
+ Given 1 user
49
+ """
50
+ And I write to "features/parent/child.feature" with:
51
+ """
52
+ Feature:
53
+ Scenario:
54
+ Then 1 user should be created
55
+ """
56
+ And I write to "features/step_definitions/all_steps.rb" with:
57
+ """
58
+ When /^(\d+) users?$/ do |count|
59
+ User.create
60
+ end
61
+
62
+ Then /^(\d+) users? should be created$/ do |count|
63
+ User.count.should == count.to_i
64
+ end
65
+ """
66
+ And I write to "features/z-last-feature-to-run.feature" with:
67
+ """
68
+ Feature:
69
+ Scenario: Testing truncation
70
+ Then 0 users should be created
71
+ """
72
+ And I run `rails g model user`
73
+ And I run `bundle exec rake db:drop db:create db:migrate db:test:prepare`
74
+
75
+ When I run `bundle exec cucumber`
76
+ Then it should pass with:
77
+ """
78
+ 3 scenarios (3 passed)
79
+ 3 steps (3 passed)
80
+ """
@@ -0,0 +1,43 @@
1
+ Feature: Make sure DatabaseCleaner works with javascript tags
2
+ Scenario:
3
+ Given I have created a new rails app
4
+ And I write to "features/parent.feature" with:
5
+ """
6
+ Feature:
7
+ @javascript
8
+ Scenario:
9
+ Given 1 user
10
+ """
11
+ And I write to "features/parent/child.feature" with:
12
+ """
13
+ Feature:
14
+ @javascript
15
+ Scenario:
16
+ Then 1 user should be created
17
+ """
18
+ And I write to "features/step_definitions/all_steps.rb" with:
19
+ """
20
+ When /^(\d+) users?$/ do |count|
21
+ User.create
22
+ end
23
+
24
+ Then /^(\d+) users? should be created$/ do |count|
25
+ User.count.should == count.to_i
26
+ end
27
+ """
28
+ And I write to "features/z-last-feature-to-run.feature" with:
29
+ """
30
+ Feature:
31
+ @javascript
32
+ Scenario: Testing truncation
33
+ Then 0 users should be created
34
+ """
35
+ And I run `rails g model user`
36
+ And I run `bundle exec rake db:migrate db:test:prepare`
37
+
38
+ When I run `bundle exec cucumber`
39
+ Then it should pass with:
40
+ """
41
+ 3 scenarios (3 passed)
42
+ 3 steps (3 passed)
43
+ """
@@ -0,0 +1,38 @@
1
+ module CucumberTreeHelper
2
+ def rails_new(options={})
3
+ options[:name] ||= 'test_app'
4
+ run_simple "rails new #{options[:name]} --skip-bundle --skip-test-unit #{options[:args]}"
5
+ assert_passing_with('README')
6
+ cd options[:name]
7
+ end
8
+
9
+ def install_cucumber_tree(*options)
10
+ gem "cucumber_tree", group: :test, path: "#{File.expand_path('.')}", require: false
11
+ run_simple 'bundle exec rails generate cucumber:install'
12
+ replace_content('config/cucumber.yml', /std_opts = "/, 'std_opts = "--require features ')
13
+ append_to_file('features/support/env.rb', "require 'cucumber_tree'")
14
+ end
15
+
16
+ def replace_content(file, from_content, to_content)
17
+ content = with_file_content(file) { |content| content }
18
+ content = content.gsub(from_content, to_content)
19
+ overwrite_file(file, content)
20
+ end
21
+
22
+ def gem(name, options)
23
+ line = %{gem "#{name}", #{options.inspect}\n}
24
+ append_to_file('Gemfile', line)
25
+ end
26
+ end
27
+ World(CucumberTreeHelper)
28
+
29
+ Given /^I have created a new rails app$/ do
30
+ rails_new
31
+ install_cucumber_tree
32
+ end
33
+
34
+ Given /^I have created a new rails app with postgresql$/ do
35
+ `createuser --superuser test_app`
36
+ rails_new(args: '--database=postgresql')
37
+ install_cucumber_tree
38
+ end
@@ -0,0 +1,5 @@
1
+ require 'aruba/cucumber'
2
+
3
+ Before do
4
+ @aruba_timeout_seconds = 120
5
+ end
@@ -0,0 +1,33 @@
1
+ Feature: Variables Snapshot
2
+ Scenario:
3
+ Given I have created a new rails app
4
+ And I write to "features/parent.feature" with:
5
+ """
6
+ Feature:
7
+ Scenario:
8
+ Given one user
9
+ """
10
+ And I write to "features/parent/child.feature" with:
11
+ """
12
+ Feature:
13
+ Scenario:
14
+ Then that user should be present
15
+ """
16
+ And I write to "features/step_definitions/all_steps.rb" with:
17
+ """
18
+ When /^one user$/ do
19
+ @user = "Jack"
20
+ end
21
+
22
+ Then /^that user should be present$/ do
23
+ @user.should == "Jack"
24
+ end
25
+ """
26
+ And I run `bundle exec rake db:migrate db:test:prepare`
27
+
28
+ When I run `bundle exec cucumber`
29
+ Then it should pass with:
30
+ """
31
+ 2 scenarios (2 passed)
32
+ 2 steps (2 passed)
33
+ """
@@ -0,0 +1,75 @@
1
+ env_caller = caller.detect{|f| f =~ /\/env\.rb:/} && !caller.detect{|f| f =~ /\/environment\.rb:/}
2
+ if env_caller
3
+ require "cucumber_tree/version"
4
+ require "cucumber_tree/hooks"
5
+ require "cucumber_tree/configuration"
6
+ require "cucumber_tree/handlers"
7
+ require "cucumber_tree/temp_dir"
8
+ require "cucumber_tree/temp_dir"
9
+ require "cucumber_tree/database_cleaner_hook"
10
+
11
+ module CucumberTree
12
+
13
+ class << self
14
+
15
+ attr_accessor :handler_instances
16
+ attr_accessor :handler_classes
17
+
18
+ def load_snapshot(world, scenario)
19
+ parent_feature = scenario.feature.file.gsub(/\A(.*)\/.*(\.feature)\z/, '\1\2')
20
+ snapshot = snapshots[parent_feature]
21
+ instantiate_handlers(world, scenario)
22
+ if snapshot.present?
23
+ handler_instances.each do |handler|
24
+ handler.load(snapshot)
25
+ end
26
+ end
27
+ end
28
+
29
+ def save_snapshot(world, scenario)
30
+ feature_file = scenario.feature.file
31
+ if is_parent_feature?(feature_file)
32
+ snapshots[feature_file] = {}.tap do |snapshot|
33
+ handler_instances.each do |handler|
34
+ handler.save(snapshot)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def setup
41
+ TempDir.clear!
42
+ end
43
+
44
+ def register_handler(*handlers)
45
+ self.handler_classes ||= []
46
+ self.handler_classes += handlers
47
+ end
48
+
49
+ private
50
+
51
+ def is_parent_feature?(file)
52
+ dir_name = file.gsub(/\A(.*)(\.feature)\z/, '\1')
53
+ File.directory?(dir_name)
54
+ end
55
+
56
+ def instantiate_handlers(world, scenario)
57
+ self.handler_instances = handler_classes.map do |class_name|
58
+ class_name.new(world, scenario)
59
+ end
60
+ end
61
+
62
+ def snapshots
63
+ @snapshots ||= {}
64
+ end
65
+
66
+ end
67
+
68
+ # Handler::Url should always be the last
69
+ register_handler(Handler::Database.get_handler, Handler::Cookies, Handler::Variables, Handler::Url)
70
+
71
+ end
72
+ else
73
+ warn "WARNING: cucumber_tree required outside of env.rb. The rest of loading is being defered until env.rb is called.
74
+ To avoid this warning, move 'gem cucumber_tree' under only group :test in your Gemfile"
75
+ end
@@ -0,0 +1,17 @@
1
+ class Cucumber::Cli::Configuration
2
+ alias __cucumber_orig_feature_files__ feature_files
3
+
4
+ def feature_files
5
+ files = __cucumber_orig_feature_files__
6
+ missing_files = []
7
+
8
+ files.each do |file|
9
+ (file.count('/') - 1).times do
10
+ file = file.gsub(/\A(.*)\/.*(\.feature)(:\d+)?\z/, '\1\2')
11
+ missing_files << file if File.file?(file)
12
+ end
13
+ end
14
+
15
+ (missing_files + files).uniq.sort!
16
+ end
17
+ end
@@ -0,0 +1,2 @@
1
+ DatabaseCleaner.strategy = :truncation
2
+ Cucumber::Rails::Database.javascript_strategy = :truncation
@@ -0,0 +1,4 @@
1
+ require "cucumber_tree/handlers/database"
2
+ require "cucumber_tree/handlers/cookies"
3
+ require "cucumber_tree/handlers/variables"
4
+ require "cucumber_tree/handlers/url"
@@ -0,0 +1,11 @@
1
+ module CucumberTree
2
+ module Handler
3
+ class Base < Struct.new(:world, :scenario)
4
+
5
+ def page
6
+ world.page
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ require "cucumber_tree/handlers/base"
2
+
3
+ module CucumberTree
4
+ module Handler
5
+ class Cookies < Base
6
+
7
+ def load(snapshot)
8
+ snapshot[:cookies].each do |name, value|
9
+ page.cookies[name] = value
10
+ end
11
+ end
12
+
13
+ def save(snapshot)
14
+ snapshot[:cookies] = {}.tap do |hash|
15
+ page.cookies.each do |name, value|
16
+ hash[name.to_sym] = value
17
+ end
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ require "cucumber_tree/handlers/base"
2
+ require "cucumber_tree/handlers/databases/sqlite"
3
+ require "cucumber_tree/handlers/databases/postgresql"
4
+
5
+ module CucumberTree
6
+ module Handler
7
+ module Database
8
+
9
+ def self.get_handler
10
+ @get_handler ||= begin
11
+ adapter = Rails.configuration.database_configuration[Rails.env]["adapter"]
12
+ case adapter
13
+ when /sqlite/
14
+ Sqlite
15
+ when /postgresql/
16
+ Postgresql
17
+ else
18
+ raise "Database not supported: #{adapter}"
19
+ end
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ require "cucumber_tree/handlers/base"
2
+
3
+ module CucumberTree
4
+ module Handler
5
+ module Database
6
+ class Postgresql < Base
7
+ def load(snapshot)
8
+ dump_file = snapshot[:postgres_file]
9
+ options = []
10
+ options << "-U #{db_config['username']}" if db_config['username'].present?
11
+ options << "-d #{db_config['database']}"
12
+ options << "-f #{dump_file}"
13
+ `psql #{options.join(' ')}`
14
+ end
15
+
16
+ def save(snapshot)
17
+ dump_file = ::CucumberTree::TempDir.file_name("postgres.dump")
18
+ options = []
19
+ options << "-f #{dump_file}"
20
+ options << "-U #{db_config['username']}" if db_config['username'].present?
21
+ options << "--exclude-table=schema_migrations"
22
+ options << "-a #{db_config['database']}"
23
+ `pg_dump #{options.join(' ')}`
24
+ snapshot[:postgres_file] = dump_file
25
+ end
26
+
27
+ private
28
+
29
+ def db_config
30
+ Rails.configuration.database_configuration[Rails.env]
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,26 @@
1
+ require "cucumber_tree/handlers/base"
2
+
3
+ module CucumberTree
4
+ module Handler
5
+ module Database
6
+ class Sqlite < Base
7
+ def load(snapshot)
8
+ FileUtils.cp(snapshot[:sqlite_file], db_file)
9
+ end
10
+
11
+ def save(snapshot)
12
+ dump_file = ::CucumberTree::TempDir.file_name("dbfile.sqlite")
13
+ FileUtils.cp(db_file, dump_file)
14
+ snapshot[:sqlite_file] = dump_file
15
+ end
16
+
17
+ private
18
+
19
+ def db_file
20
+ Rails.root.join(Rails.configuration.database_configuration[Rails.env]["database"])
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ require "cucumber_tree/handlers/base"
2
+
3
+ module CucumberTree
4
+ module Handler
5
+ class Url < Base
6
+
7
+ def load(snapshot)
8
+ url = snapshot[:url]
9
+ page.visit url unless url.nil?
10
+ end
11
+
12
+ def save(snapshot)
13
+ snapshot[:url] = page.current_path
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ require "cucumber_tree/handlers/base"
2
+
3
+ module CucumberTree
4
+ module Handler
5
+ class Variables < Base
6
+
7
+ EXCLUDED_VARIABLES = %w(@__cucumber_step_mother @__natural_language @integration_session @app @controller @response @request)
8
+
9
+ def load(snapshot)
10
+ snapshot[:variables].each do |name, value|
11
+ world.instance_variable_set(name, value)
12
+ end
13
+ end
14
+
15
+ def save(snapshot)
16
+ names = world.instance_variables.map { |var| var.to_s } - EXCLUDED_VARIABLES
17
+ snapshot[:variables] = {}.tap do |hash|
18
+ names.each do |name|
19
+ hash[name] = world.instance_variable_get(name)
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ require "cucumber/rspec/doubles"
2
+
3
+ module Capybara
4
+ class Session
5
+ def cookies
6
+ @cookies ||= begin
7
+ secret = Rails.application.config.secret_token
8
+ cookies = ActionDispatch::Cookies::CookieJar.new(secret)
9
+ cookies.stub(:close!)
10
+ cookies
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ Before do |scenario|
17
+ stub_cookies(page)
18
+ CucumberTree.load_snapshot(self, scenario)
19
+ end
20
+
21
+ After do |scenario|
22
+ CucumberTree.save_snapshot(self, scenario)
23
+ end
24
+
25
+ AfterConfiguration do
26
+ CucumberTree.setup
27
+ end
28
+
29
+ def stub_cookies(page)
30
+ request = ActionDispatch::Request.any_instance
31
+ request.stub(:cookie_jar).and_return{ page.cookies }
32
+ request.stub(:cookies).and_return{ page.cookies }
33
+ end
@@ -0,0 +1,26 @@
1
+ module CucumberTree
2
+ class TempDir
3
+
4
+ class << self
5
+
6
+ def clear!
7
+ tmp_path.children.each do |child|
8
+ child.rmtree
9
+ end
10
+ end
11
+
12
+ def file_name(name)
13
+ tmp_path.join(Time.now.to_f.to_s).tap(&:mkpath).join(name).to_path
14
+ end
15
+
16
+ private
17
+
18
+ def tmp_path
19
+ tmp_path = Rails.root.join('tmp','cucumber_tree')
20
+ tmp_path.mkpath unless tmp_path.exist?
21
+ tmp_path
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ module CucumberTree
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,31 @@
1
+ require 'cucumber_tree/handlers/cookies'
2
+
3
+ describe CucumberTree::Handler::Cookies do
4
+
5
+ let(:world) { stub(:world, page: page) }
6
+ let(:page) { stub(:page, cookies: cookies) }
7
+ let(:handler) { described_class.new(world) }
8
+
9
+ describe "#load" do
10
+ let(:cookies) { {} }
11
+ let(:snapshot) { {cookies: {a: 1} } }
12
+
13
+ before { handler.load(snapshot) }
14
+
15
+ it "sets the cookies in the page" do
16
+ page.cookies.should == {a: 1}
17
+ end
18
+ end
19
+
20
+ describe "#save" do
21
+ let(:cookies) { {a: 1} }
22
+ let(:snapshot) { {} }
23
+
24
+ before { handler.save(snapshot) }
25
+
26
+ it "sets the cookies in the snapshot" do
27
+ snapshot[:cookies].should == {a: 1}
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ require 'cucumber_tree/handlers/url'
2
+
3
+ describe CucumberTree::Handler::Url do
4
+
5
+ let(:world) { stub(:world, page: page) }
6
+ let(:handler) { described_class.new(world) }
7
+
8
+ describe "#load" do
9
+ let(:page) { stub(:page) }
10
+ let(:snapshot) { {url: '/url'} }
11
+
12
+ it "visits the url" do
13
+ page.should_receive(:visit).with('/url')
14
+ handler.load(snapshot)
15
+ end
16
+ end
17
+
18
+ describe "#save" do
19
+ let(:page) { stub(:page, current_path: '/url' ) }
20
+ let(:snapshot) { {} }
21
+
22
+ before { handler.save(snapshot) }
23
+
24
+ it "sets the current url in the snapshot" do
25
+ snapshot[:url].should == '/url'
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ require 'cucumber_tree/handlers/variables'
2
+
3
+ describe CucumberTree::Handler::Variables do
4
+
5
+ let(:world) { Object.new }
6
+ let(:handler) { described_class.new(world) }
7
+
8
+ describe "#load" do
9
+ let(:snapshot) { {variables: {'@num' => 1} } }
10
+
11
+ before { handler.load(snapshot) }
12
+
13
+ it "sets the instance variables in the world" do
14
+ world.instance_variable_get('@num').should == 1
15
+ end
16
+ end
17
+
18
+ describe "#save" do
19
+ let(:snapshot) { {} }
20
+ let(:instance_variable_name) { "@num" }
21
+
22
+ before do
23
+ world.instance_variable_set(instance_variable_name, 1)
24
+ handler.save(snapshot)
25
+ end
26
+
27
+ it "sets the variables in the snapshot" do
28
+ snapshot[:variables].should == {'@num' => 1}
29
+ end
30
+
31
+ context "with excluded instance variable name" do
32
+ let(:instance_variable_name) { "@app" }
33
+
34
+ it "does not set the variable in the snapshot" do
35
+ snapshot[:variables].should == {}
36
+ end
37
+ end
38
+ end
39
+ end
metadata ADDED
@@ -0,0 +1,220 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cucumber_tree
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Gabriel Reis
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cucumber-rails
16
+ requirement: &70234007700840 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.3.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70234007700840
25
+ - !ruby/object:Gem::Dependency
26
+ name: database_cleaner
27
+ requirement: &70234007700360 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.7.2
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70234007700360
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70234007699900 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 2.9.0
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70234007699900
47
+ - !ruby/object:Gem::Dependency
48
+ name: aruba
49
+ requirement: &70234007699440 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.5.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70234007699440
58
+ - !ruby/object:Gem::Dependency
59
+ name: bundler
60
+ requirement: &70234007698980 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: 1.1.0
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70234007698980
69
+ - !ruby/object:Gem::Dependency
70
+ name: rails
71
+ requirement: &70234007698520 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: 3.2.8
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70234007698520
80
+ - !ruby/object:Gem::Dependency
81
+ name: sqlite3
82
+ requirement: &70234007698060 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: 1.3.6
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70234007698060
91
+ - !ruby/object:Gem::Dependency
92
+ name: pg
93
+ requirement: &70234007697600 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: 0.14.1
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *70234007697600
102
+ - !ruby/object:Gem::Dependency
103
+ name: sass-rails
104
+ requirement: &70234007697140 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: 3.2.5
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: *70234007697140
113
+ - !ruby/object:Gem::Dependency
114
+ name: coffee-rails
115
+ requirement: &70234007696680 !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: 3.2.2
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: *70234007696680
124
+ - !ruby/object:Gem::Dependency
125
+ name: uglifier
126
+ requirement: &70234007696220 !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: 1.2.4
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: *70234007696220
135
+ - !ruby/object:Gem::Dependency
136
+ name: jquery-rails
137
+ requirement: &70234006532320 !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: 2.0.2
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: *70234006532320
146
+ description: Organize your features in a tree directory and don't waste your CPU time
147
+ running the same steps over and over.
148
+ email:
149
+ - gabriel.oreis@gmail.com
150
+ executables: []
151
+ extensions: []
152
+ extra_rdoc_files: []
153
+ files:
154
+ - .gitignore
155
+ - .rspec
156
+ - Gemfile
157
+ - LICENSE
158
+ - README.md
159
+ - Rakefile
160
+ - cucumber_tree.gemspec
161
+ - features/cookies_snapshot.feature
162
+ - features/current_url_snapshot.feature
163
+ - features/database_snapshot.feature
164
+ - features/javascript.feature
165
+ - features/step_definitions/cucumber_tree_steps.rb
166
+ - features/support/env.rb
167
+ - features/variables_snapshot.feature
168
+ - lib/cucumber_tree.rb
169
+ - lib/cucumber_tree/configuration.rb
170
+ - lib/cucumber_tree/database_cleaner_hook.rb
171
+ - lib/cucumber_tree/handlers.rb
172
+ - lib/cucumber_tree/handlers/base.rb
173
+ - lib/cucumber_tree/handlers/cookies.rb
174
+ - lib/cucumber_tree/handlers/database.rb
175
+ - lib/cucumber_tree/handlers/databases/postgresql.rb
176
+ - lib/cucumber_tree/handlers/databases/sqlite.rb
177
+ - lib/cucumber_tree/handlers/url.rb
178
+ - lib/cucumber_tree/handlers/variables.rb
179
+ - lib/cucumber_tree/hooks.rb
180
+ - lib/cucumber_tree/temp_dir.rb
181
+ - lib/cucumber_tree/version.rb
182
+ - spec/cucumber_tree/handlers/cookies_spec.rb
183
+ - spec/cucumber_tree/handlers/url_spec.rb
184
+ - spec/cucumber_tree/handlers/variables_spec.rb
185
+ homepage: ''
186
+ licenses: []
187
+ post_install_message:
188
+ rdoc_options: []
189
+ require_paths:
190
+ - lib
191
+ required_ruby_version: !ruby/object:Gem::Requirement
192
+ none: false
193
+ requirements:
194
+ - - ! '>='
195
+ - !ruby/object:Gem::Version
196
+ version: '0'
197
+ required_rubygems_version: !ruby/object:Gem::Requirement
198
+ none: false
199
+ requirements:
200
+ - - ! '>='
201
+ - !ruby/object:Gem::Version
202
+ version: '0'
203
+ requirements: []
204
+ rubyforge_project:
205
+ rubygems_version: 1.8.17
206
+ signing_key:
207
+ specification_version: 3
208
+ summary: Better way to organize your features
209
+ test_files:
210
+ - features/cookies_snapshot.feature
211
+ - features/current_url_snapshot.feature
212
+ - features/database_snapshot.feature
213
+ - features/javascript.feature
214
+ - features/step_definitions/cucumber_tree_steps.rb
215
+ - features/support/env.rb
216
+ - features/variables_snapshot.feature
217
+ - spec/cucumber_tree/handlers/cookies_spec.rb
218
+ - spec/cucumber_tree/handlers/url_spec.rb
219
+ - spec/cucumber_tree/handlers/variables_spec.rb
220
+ has_rdoc: