saki 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.markdown +45 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/lib/saki.rb +127 -0
- data/test/helper.rb +10 -0
- data/test/test_saki.rb +7 -0
- metadata +90 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Nate Kidwell
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Saki - For times when you can't swallow Cucumber
|
2
|
+
|
3
|
+
Saki lets you do acceptance testing on top of RSpec with considerably more terseness than cucumber, but without sacrificing readability. Are you tired of having DRY code, but tests that seem to babble on "for the length of a bible"? Me too. How about RSpec code that is hard to follow, while Ruby itself is as "human" as a programming language can get? I hate it too.
|
4
|
+
|
5
|
+
Enter Saki stage left.
|
6
|
+
|
7
|
+
## How terse is it?
|
8
|
+
|
9
|
+
Well, here's a sample that assumes a user exists and visits an edit path for that user. Me like.
|
10
|
+
|
11
|
+
with_existing :user do
|
12
|
+
on_visiting edit_path_for(:user) do
|
13
|
+
it { should yadda.yadda }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
This code basically injects some before blocks behind the scene, so it would look like this in vanilla RSpec:
|
18
|
+
|
19
|
+
context "when a user exists" do
|
20
|
+
before { @user = Factory :user }
|
21
|
+
context "when I visit the page for editing that user" do
|
22
|
+
before { visit edit_user_path(:user) }
|
23
|
+
it {should yadda.yadda}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Much more expressive don't you think? And smooth to follow, no?
|
28
|
+
|
29
|
+
## What assumptions does it make?
|
30
|
+
|
31
|
+
It assumes that you are using factory_girl and capybara, though it probably would work fine with other test factories and webrat. If you need another factory in the mix, just redefine the default_factory method to behave how you want.
|
32
|
+
|
33
|
+
## Note on Patches/Pull Requests
|
34
|
+
|
35
|
+
* Fork the project.
|
36
|
+
* Make your feature addition or bug fix.
|
37
|
+
* Add tests for it. This is important so I don't break it in a
|
38
|
+
future version unintentionally.
|
39
|
+
* Commit, do not mess with rakefile, version, or history.
|
40
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
41
|
+
* Send me a pull request. Bonus points for topic branches.
|
42
|
+
|
43
|
+
## Copyright
|
44
|
+
|
45
|
+
MIT License
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "saki"
|
8
|
+
gem.summary = %Q{Allows terse acceptance testing}
|
9
|
+
gem.description = %Q{Cucumber scenarios are lond and confusing sometimes. Release yourself from the tyranny of client-centered specing!}
|
10
|
+
gem.email = "nate@ludicast.com"
|
11
|
+
gem.homepage = "http://github.com/ludicast/saki"
|
12
|
+
gem.authors = ["Nate Kidwell"]
|
13
|
+
gem.add_development_dependency "rspec"
|
14
|
+
end
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake/testtask'
|
21
|
+
Rake::TestTask.new(:test) do |test|
|
22
|
+
test.libs << 'lib' << 'test'
|
23
|
+
test.pattern = 'test/**/test_*.rb'
|
24
|
+
test.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
begin
|
28
|
+
require 'rcov/rcovtask'
|
29
|
+
Rcov::RcovTask.new do |test|
|
30
|
+
test.libs << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
rescue LoadError
|
35
|
+
task :rcov do
|
36
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
task :test => :check_dependencies
|
41
|
+
|
42
|
+
task :default => :test
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
47
|
+
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
49
|
+
rdoc.title = "saki #{version}"
|
50
|
+
rdoc.rdoc_files.include('README*')
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
52
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/lib/saki.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
module Saki
|
2
|
+
module AcceptanceHelpers
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def default_factory(name)
|
6
|
+
Factory name
|
7
|
+
end
|
8
|
+
def has_link_for(model, opts = {})
|
9
|
+
href = "/#{model.class.to_s.tableize}/#{model.id}"
|
10
|
+
if opts[:parent]
|
11
|
+
href = "/#{opts[:parent].class.to_s.tableize}/#{opts[:parent].id}" + href
|
12
|
+
end
|
13
|
+
page.should have_xpath("//a[@href='#{href}' and not(@rel)]")
|
14
|
+
end
|
15
|
+
|
16
|
+
def has_link_for_editing(model, opts = {})
|
17
|
+
href = "/#{model.class.to_s.tableize}/#{model.id}/edit"
|
18
|
+
if opts[:parent]
|
19
|
+
href = "/#{opts[:parent].class.to_s.tableize}/#{opts[:parent].id}" + href
|
20
|
+
end
|
21
|
+
page.should have_xpath("//a[@href='#{href}']")
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_link_for_deleting(model, opts = {})
|
25
|
+
href = "/#{model.class.to_s.tableize}/#{model.id}"
|
26
|
+
if opts[:parent]
|
27
|
+
href = "/#{opts[:parent].class.to_s.tableize}/#{opts[:parent].id}" + href
|
28
|
+
end
|
29
|
+
page.should have_xpath("//a[@href='#{href}' and @data-method='delete']")
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_link_for_creating(model_type, opts = {})
|
33
|
+
href = "/#{model_type.to_s.tableize}/new"
|
34
|
+
if opts[:parent]
|
35
|
+
href = "/#{opts[:parent].class.to_s.tableize}/#{opts[:parent].id}" + href
|
36
|
+
end
|
37
|
+
page.should have_xpath("//a[@href='#{href}']")
|
38
|
+
end
|
39
|
+
|
40
|
+
def has_link_for_indexing(model_type, opts = {})
|
41
|
+
href = "/#{model_type.to_s.tableize}"
|
42
|
+
if opts[:parent]
|
43
|
+
href = "/#{opts[:parent].class.to_s.tableize}/#{opts[:parent].id}" + href
|
44
|
+
end
|
45
|
+
page.should have_xpath("//a[@href='#{href}']")
|
46
|
+
end
|
47
|
+
|
48
|
+
module ClassMethods
|
49
|
+
def with_existing resource, &block
|
50
|
+
context "with exisiting #{resource}" do
|
51
|
+
before { eval "@#{resource} = default_factory :#{resource}" }
|
52
|
+
module_eval &block
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_following_link_to path, &block
|
57
|
+
context "on following link" do
|
58
|
+
before do
|
59
|
+
if path.is_a? String
|
60
|
+
path = path
|
61
|
+
else
|
62
|
+
path = path.call(self)
|
63
|
+
end
|
64
|
+
has_link(path)
|
65
|
+
visit path
|
66
|
+
end
|
67
|
+
module_eval &block
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def on_visiting path, &block
|
72
|
+
context "on visiting" do
|
73
|
+
before do
|
74
|
+
if path.is_a? String
|
75
|
+
visit path
|
76
|
+
else
|
77
|
+
visit path.call(self)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
module_eval &block
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_opts(link, opts, context)
|
85
|
+
if opts[:parent]
|
86
|
+
"/#{opts[:parent].to_s.pluralize}/#{(context.instance_variable_get('@' + opts[:parent].to_s)).id}" + link
|
87
|
+
else
|
88
|
+
link
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def edit_path_for(resource, opts = {})
|
93
|
+
lambda do |context|
|
94
|
+
add_opts "/#{resource.to_s.pluralize}/#{(context.instance_variable_get('@' + resource.to_s)).id}/edit", opts, context
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def show_path_for(resource, opts = {})
|
99
|
+
lambda do |context|
|
100
|
+
add_opts "/#{resource.to_s.pluralize}/#{(context.instance_variable_get('@' + resource.to_s)).id}", opts, context
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def create_path_for(resource, opts = {})
|
105
|
+
lambda do |context|
|
106
|
+
add_opts "/#{resource.to_s.pluralize}/new", opts, context
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def index_path_for(resource, opts = {})
|
111
|
+
lambda do |context|
|
112
|
+
add_opts "/#{resource.to_s.pluralize}", opts, context
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def where(closure, &block)
|
117
|
+
context "anonymous closure" do
|
118
|
+
before { instance_eval &closure }
|
119
|
+
module_eval &block
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
RSpec.configuration.include Saki::AcceptanceHelpers, :type => :acceptance
|
data/test/helper.rb
ADDED
data/test/test_saki.rb
ADDED
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: saki
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 0.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Nate Kidwell
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-08-30 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
description: Cucumber scenarios are lond and confusing sometimes. Release yourself from the tyranny of client-centered specing!
|
36
|
+
email: nate@ludicast.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.markdown
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.markdown
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- lib/saki.rb
|
52
|
+
- test/helper.rb
|
53
|
+
- test/test_saki.rb
|
54
|
+
has_rdoc: true
|
55
|
+
homepage: http://github.com/ludicast/saki
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options:
|
60
|
+
- --charset=UTF-8
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
hash: 3
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
version: "0"
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.3.7
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: Allows terse acceptance testing
|
88
|
+
test_files:
|
89
|
+
- test/helper.rb
|
90
|
+
- test/test_saki.rb
|