saki 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +20 -4
- data/VERSION +1 -1
- data/lib/generators/saki/integration_generator.rb +19 -0
- data/lib/generators/saki/templates/full_integration_spec.rb +35 -0
- data/lib/saki.rb +111 -4
- data/saki.gemspec +4 -2
- metadata +5 -3
data/README.markdown
CHANGED
@@ -41,6 +41,10 @@ The only assumption is that you are using factories instead of fixtures. You al
|
|
41
41
|
|
42
42
|
with_existing :user, :state => "happy" do...
|
43
43
|
|
44
|
+
`with_signed_in` is similar to `with_existing` but after creating the object it passes it into a `sign_in` method:
|
45
|
+
|
46
|
+
with_signed_in :admin do...
|
47
|
+
|
44
48
|
`on_visiting` preferably uses some dynamic functions for establishing a path: `new_X_path`, `Xs_path`, `edit_X_path`, `X_path` and `new_X_path`. In these cases, substitute X for the resource name (e.g. `new_user_path`).
|
45
49
|
|
46
50
|
Note that for examples like `edit_user_path`, it behaves with a slight difference from the rails route helpers, because it assumes that there already exists an instance variable named `@user`. Since the `edit_user_path` call occurs when there is no `@user`, we can't mention it explicitly.
|
@@ -49,9 +53,9 @@ For cases where the resource is nested, these path helpers have a :parent => par
|
|
49
53
|
|
50
54
|
on_visiting auctions_path(:parent => :user) do ...
|
51
55
|
|
52
|
-
`on_visiting` also takes a path as a string, or a
|
56
|
+
`on_visiting` also takes a path as a string, or a proc that executes within a before block to set up the path. It also takes a symbol which is the name of a method name. This is useful when the code is dependent on an instance variable for path creation.
|
53
57
|
|
54
|
-
path_for_user =
|
58
|
+
path_for_user = proc { user_path(@user) }
|
55
59
|
|
56
60
|
on_visiting path_for_user do ...
|
57
61
|
|
@@ -65,10 +69,10 @@ or you can do
|
|
65
69
|
|
66
70
|
`on_following_link_to` works the same as on_visiting, but it first validates that the link exists, and then follows it.
|
67
71
|
|
68
|
-
`where` is a function taking as a parameter a
|
72
|
+
`where` is a function taking as a parameter a proc to execute in the before block.
|
69
73
|
|
70
74
|
def self.creating_a_user
|
71
|
-
|
75
|
+
proc {
|
72
76
|
@user = Factory.build @user
|
73
77
|
fill_in "user[email]", :with => @user.email
|
74
78
|
click_button "Create"
|
@@ -118,6 +122,14 @@ You can generate new acceptance tests with `rails generate saki:spec SPEC_NAME`.
|
|
118
122
|
end
|
119
123
|
end
|
120
124
|
|
125
|
+
## Saki as your default integration testing library
|
126
|
+
|
127
|
+
If you want to use Saki for generating integration tests for your scaffolding, simply add to your development.rb file
|
128
|
+
|
129
|
+
require "generators/saki/integration_generator"
|
130
|
+
|
131
|
+
Then, provided that your integration library is set to :rspec, Saki will create integration tests for your scaffolding for complete test coverage. Note that these cases are left simple for now, but can be built up upon feedback. Also you might need to implement additional functions depending on your use case.
|
132
|
+
|
121
133
|
## Why no specs/tests for Saki, oh test guy?
|
122
134
|
|
123
135
|
They'll get there :). Saki is extracted from some spec helpers I used in moving from Cucumber to Steak. Once I realized they also work as helpers for vanilla RSpec acceptance testing I made them a separate gem.
|
@@ -130,6 +142,10 @@ I haven't pimped that up yet, but will at some point. Personally I'm a "green-d
|
|
130
142
|
|
131
143
|
The motivation behind my migration from Cucumber and to Saki, are described in blog posts [Encumbered by Cucumber](http://ludicast.com/articles/1), [Introducing Saki](http://ludicast.com/articles/2).
|
132
144
|
|
145
|
+
## Ruby 1.9.2
|
146
|
+
|
147
|
+
To work with Ruby 1.9.2 the `where` function takes procs but not lambdas.
|
148
|
+
|
133
149
|
## Thanks
|
134
150
|
|
135
151
|
The generators are stolen directly from Steak with some adjustments.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'generators/rspec/integration/integration_generator'
|
2
|
+
|
3
|
+
module Rspec
|
4
|
+
module Generators
|
5
|
+
class IntegrationGenerator < Base
|
6
|
+
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
|
7
|
+
|
8
|
+
source_paths << File.join(File.dirname(__FILE__), 'templates')
|
9
|
+
|
10
|
+
def create_integration_file
|
11
|
+
template 'full_integration_spec.rb',
|
12
|
+
File.join('spec/acceptance', class_path, "#{table_name}_spec.rb")
|
13
|
+
end
|
14
|
+
def resource_name
|
15
|
+
file_name.tableize.singularize
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/acceptance_helper'
|
2
|
+
|
3
|
+
integrate "<%= resource_name %> resource" do
|
4
|
+
|
5
|
+
def fill_in_<%= resource_name %>_details<%-
|
6
|
+
attributes.each do |attribute|
|
7
|
+
%>
|
8
|
+
fill_in "<%= resource_name %>[<%= attribute.name %>]", :with => @<%= resource_name %>.<%= attribute.name %><%-
|
9
|
+
end
|
10
|
+
%>
|
11
|
+
end
|
12
|
+
|
13
|
+
def has_<%= resource_name %>_details<%-
|
14
|
+
attributes.each do |attribute|
|
15
|
+
%>
|
16
|
+
page.should have_content(@<%= resource_name %>.<%= attribute.name %>)<%-
|
17
|
+
end
|
18
|
+
%>
|
19
|
+
end
|
20
|
+
|
21
|
+
on_visiting new_<%= resource_name %>_path do
|
22
|
+
it { lets_me_create_the(:<%= resource_name %>) }
|
23
|
+
it { shows_failure_on_invalid_create }
|
24
|
+
end
|
25
|
+
|
26
|
+
with_existing :<%= resource_name %> do
|
27
|
+
it { shows_in_list(:<%= resource_name %>) }
|
28
|
+
|
29
|
+
on_visiting edit_<%= resource_name %>_path do
|
30
|
+
it { lets_me_edit_the(:<%= resource_name %>) }
|
31
|
+
it { shows_failure_on_invalid_update_of(:<%= resource_name %>) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/saki.rb
CHANGED
@@ -1,8 +1,104 @@
|
|
1
1
|
require 'rspec/core'
|
2
2
|
|
3
3
|
module Saki
|
4
|
+
module RestfulPathwayHelpers
|
5
|
+
def shows_in_list(resource, attrs = nil)
|
6
|
+
visit "/#{resource.to_s.pluralize}"
|
7
|
+
resource_instance = eval "@#{resource}"
|
8
|
+
if attrs
|
9
|
+
attrs.each do |attr|
|
10
|
+
page.should have_content(resource_instance.send(attr))
|
11
|
+
end
|
12
|
+
elsif respond_to?("displays_#{resource}")
|
13
|
+
send "displays_#{resource}"
|
14
|
+
else
|
15
|
+
page.should have_content(resource_instance.name)
|
16
|
+
end
|
17
|
+
has_index_link_list(resource_instance)
|
18
|
+
end
|
19
|
+
|
20
|
+
def has_index_link_list(item, opts = {})
|
21
|
+
has_link_for item, opts
|
22
|
+
has_link_for_editing item, opts
|
23
|
+
has_link_for_deleting item, opts
|
24
|
+
has_link_for_creating item.class.to_s.tableize.singularize, opts
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_show_link_list(item, opts = {})
|
28
|
+
has_link_for_editing item, opts
|
29
|
+
has_link_for_deleting item, opts
|
30
|
+
has_link_for_indexing item.class.to_s.tableize.singularize, opts
|
31
|
+
end
|
32
|
+
|
33
|
+
def shows_failure_on_invalid_update_of(model)
|
34
|
+
if respond_to?("invalidate_#{model}_form")
|
35
|
+
send("invalidate_#{model}_form")
|
36
|
+
else
|
37
|
+
fill_in "#{model}[name]", :with => ""
|
38
|
+
end
|
39
|
+
click_button "Update"
|
40
|
+
page.should have_xpath("//input[@type='submit' and starts-with(@value, 'Update')]")
|
41
|
+
page.should have_content("error")
|
42
|
+
end
|
43
|
+
|
44
|
+
def shows_failure_on_invalid_create
|
45
|
+
click_button "Create"
|
46
|
+
page.should have_xpath("//input[@type='submit' and starts-with(@value, 'Create')]")
|
47
|
+
page.should have_content("error")
|
48
|
+
end
|
49
|
+
|
50
|
+
def lets_me_edit_the(item_name)
|
51
|
+
eval %{
|
52
|
+
@#{item_name} = factory_build item_name
|
53
|
+
fill_in_#{item_name}_details
|
54
|
+
click_button "Update"
|
55
|
+
refetch(item_name)
|
56
|
+
has_#{item_name}_details
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def create(item_name)
|
61
|
+
eval %{
|
62
|
+
@#{item_name} = factory_build :#{item_name}
|
63
|
+
if respond_to? :before_#{item_name}_create
|
64
|
+
before_#{item_name}_create
|
65
|
+
end
|
66
|
+
fill_in_#{item_name}_details
|
67
|
+
click_button "Create"
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def refetch
|
72
|
+
|
73
|
+
|
74
|
+
def lets_me_create_the(item_name)
|
75
|
+
eval %{
|
76
|
+
create(:#{item_name})
|
77
|
+
refetch(item_name)
|
78
|
+
if respond_to? :after_#{item_name}_create
|
79
|
+
after_#{item_name}_create
|
80
|
+
end
|
81
|
+
has_#{item_name}_details
|
82
|
+
has_show_link_list(@#{item_name})
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
def refetch(item_name)
|
87
|
+
eval "@#{item_name} = respond_to?(:refetch_#{item_name}_func) ? refetch_#{item_name}_func : @#{item_name}.class.where(:name => @#{item_name}.name).first"
|
88
|
+
end
|
89
|
+
|
90
|
+
def factory_build(name, hash = {})
|
91
|
+
Factory.build name, hash
|
92
|
+
end
|
93
|
+
|
94
|
+
def factory(name, hash = {})
|
95
|
+
Factory name, hash
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
4
100
|
module GeneralHelpers
|
5
|
-
extend ActiveSupport::Concern
|
101
|
+
extend ActiveSupport::Concern
|
6
102
|
def default_factory(name, opts = {})
|
7
103
|
Factory name, opts
|
8
104
|
end
|
@@ -17,12 +113,22 @@ module Saki
|
|
17
113
|
end
|
18
114
|
end
|
19
115
|
|
116
|
+
def with_signed_in resource, opts={}, &block
|
117
|
+
context "with signed in #{resource}" do
|
118
|
+
before do
|
119
|
+
instance_variable_set "@#{resource}", default_factory(resource, opts)
|
120
|
+
eval "sign_in @#{resource}"
|
121
|
+
end
|
122
|
+
module_eval &block
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
20
126
|
def where(executable, *opts, &block)
|
21
127
|
context "anonymous closure" do
|
22
128
|
before { instance_eval &executable }
|
23
129
|
module_eval &block
|
24
130
|
end
|
25
|
-
end
|
131
|
+
end
|
26
132
|
end
|
27
133
|
|
28
134
|
end
|
@@ -78,7 +184,7 @@ module Saki
|
|
78
184
|
def has_link_for_indexing(model_type, opts = {})
|
79
185
|
href = add_opts "/#{model_type.to_s.tableize}", opts
|
80
186
|
has_link href
|
81
|
-
end
|
187
|
+
end
|
82
188
|
|
83
189
|
def should_be_on(page_name)
|
84
190
|
current_path = URI.parse(current_url).path
|
@@ -195,4 +301,5 @@ module RSpec::Core::ObjectExtensions
|
|
195
301
|
end
|
196
302
|
|
197
303
|
RSpec.configuration.include Saki::GeneralHelpers
|
198
|
-
RSpec.configuration.include Saki::AcceptanceHelpers, :type => :acceptance
|
304
|
+
RSpec.configuration.include Saki::AcceptanceHelpers, :type => :acceptance
|
305
|
+
RSpec.configuration.include Saki::RestfulPathwayHelpers, :type => :acceptance
|
data/saki.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{saki}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nate Kidwell"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-10-15}
|
13
13
|
s.description = %q{Cucumber scenarios are long and confusing sometimes. Release yourself from the tyranny of client-centered specing!}
|
14
14
|
s.email = %q{nate@ludicast.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -24,9 +24,11 @@ Gem::Specification.new do |s|
|
|
24
24
|
"Rakefile",
|
25
25
|
"VERSION",
|
26
26
|
"lib/generators/saki/install_generator.rb",
|
27
|
+
"lib/generators/saki/integration_generator.rb",
|
27
28
|
"lib/generators/saki/spec_generator.rb",
|
28
29
|
"lib/generators/saki/templates/acceptance_helper.rb",
|
29
30
|
"lib/generators/saki/templates/acceptance_spec.rb",
|
31
|
+
"lib/generators/saki/templates/full_integration_spec.rb",
|
30
32
|
"lib/generators/saki/templates/helpers.rb",
|
31
33
|
"lib/saki.rb",
|
32
34
|
"saki.gemspec",
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 2
|
9
|
+
version: 0.1.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Nate Kidwell
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-10-15 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -47,9 +47,11 @@ files:
|
|
47
47
|
- Rakefile
|
48
48
|
- VERSION
|
49
49
|
- lib/generators/saki/install_generator.rb
|
50
|
+
- lib/generators/saki/integration_generator.rb
|
50
51
|
- lib/generators/saki/spec_generator.rb
|
51
52
|
- lib/generators/saki/templates/acceptance_helper.rb
|
52
53
|
- lib/generators/saki/templates/acceptance_spec.rb
|
54
|
+
- lib/generators/saki/templates/full_integration_spec.rb
|
53
55
|
- lib/generators/saki/templates/helpers.rb
|
54
56
|
- lib/saki.rb
|
55
57
|
- saki.gemspec
|