butternut 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,288 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module Butternut
4
+ describe Formatter do
5
+ extend SpecHelperDsl
6
+ include SpecHelper
7
+
8
+ Spec::Matchers.define :have_css_node do |css, regexp|
9
+ match do |doc|
10
+ nodes = doc.css(css)
11
+ nodes.detect{ |node| node.text =~ regexp }
12
+ end
13
+ end
14
+
15
+ def setup_formatter(options = {})
16
+ @out = StringIO.new
17
+ @formatter = Butternut::Formatter.new(step_mother, @out, options)
18
+ end
19
+
20
+ def most_recent_html_file(dir)
21
+ path = Pathname.new(dir)
22
+ files = path.entries.collect { |file|
23
+ path+file
24
+ }.sort { |file1,file2|
25
+ file2.mtime <=> file1.mtime
26
+ }
27
+ files.detect { |f| f.to_s =~ /\.html$/ }
28
+ end
29
+
30
+ describe "visiting blank feature name" do
31
+ before(:each) do
32
+ setup_formatter
33
+ end
34
+
35
+ it "should not raise an error when visiting a blank feature name" do
36
+ lambda { @formatter.feature_name("") }.should_not raise_error
37
+ end
38
+ end
39
+
40
+ describe "given a single feature" do
41
+ before(:each) do
42
+ setup_formatter
43
+ run_defined_feature
44
+ @doc = Nokogiri.HTML(@out.string)
45
+ end
46
+
47
+ describe "with a comment" do
48
+ define_feature <<-FEATURE
49
+ # Healthy
50
+ FEATURE
51
+
52
+ it { @out.string.should =~ /^\<!DOCTYPE/ }
53
+ it { @out.string.should =~ /\<\/html\>$/ }
54
+ it { @doc.should have_css_node('.feature .comment', /Healthy/) }
55
+ end
56
+
57
+ describe "with a tag" do
58
+ define_feature <<-FEATURE
59
+ @foo
60
+ FEATURE
61
+
62
+ it { @doc.should have_css_node('.feature .tag', /foo/) }
63
+ end
64
+
65
+ describe "with a narrative" do
66
+ define_feature <<-FEATURE
67
+ Feature: Bananas
68
+ In order to find my inner monkey
69
+ As a human
70
+ I must eat bananas
71
+ FEATURE
72
+
73
+ it { @doc.should have_css_node('.feature h2', /Bananas/) }
74
+ it { @doc.should have_css_node('.feature .narrative', /must eat bananas/) }
75
+ end
76
+
77
+ describe "with a background" do
78
+ define_feature <<-FEATURE
79
+ Feature: Bananas
80
+
81
+ Background:
82
+ Given there are bananas
83
+ FEATURE
84
+
85
+ it { @doc.should have_css_node('.feature .background', /there are bananas/) }
86
+ end
87
+
88
+ describe "with a scenario" do
89
+ define_feature <<-FEATURE
90
+ Scenario: Monkey eats banana
91
+ Given there are bananas
92
+ FEATURE
93
+
94
+ it { @doc.should have_css_node('.feature h3', /Monkey eats banana/) }
95
+ it { @doc.should have_css_node('.feature .scenario .step', /there are bananas/) }
96
+ end
97
+
98
+ describe "with a scenario outline" do
99
+ define_feature <<-FEATURE
100
+ Scenario Outline: Monkey eats a balanced diet
101
+ Given there are <Things>
102
+
103
+ Examples: Fruit
104
+ | Things |
105
+ | apples |
106
+ | bananas |
107
+ Examples: Vegetables
108
+ | Things |
109
+ | broccoli |
110
+ | carrots |
111
+ FEATURE
112
+
113
+ it { @doc.should have_css_node('.feature .scenario.outline h4', /Fruit/) }
114
+ it { @doc.should have_css_node('.feature .scenario.outline h4', /Vegetables/) }
115
+ it { @doc.css('.feature .scenario.outline h4').length.should == 2}
116
+ it { @doc.should have_css_node('.feature .scenario.outline table', //) }
117
+ it { @doc.should have_css_node('.feature .scenario.outline table td', /carrots/) }
118
+ end
119
+
120
+ describe "with a step with a py string" do
121
+ define_feature <<-FEATURE
122
+ Scenario: Monkey goes to town
123
+ Given there is a monkey called:
124
+ """
125
+ foo
126
+ """
127
+ FEATURE
128
+
129
+ it { @doc.should have_css_node('.feature .scenario .val', /foo/) }
130
+ end
131
+
132
+ describe "with a multiline step arg" do
133
+ define_feature <<-FEATURE
134
+ Scenario: Monkey goes to town
135
+ Given there are monkeys:
136
+ | name |
137
+ | foo |
138
+ | bar |
139
+ FEATURE
140
+
141
+ it { @doc.should have_css_node('.feature .scenario table td', /foo/) }
142
+ end
143
+
144
+ describe "with a table in the background and the scenario" do
145
+ define_feature <<-FEATURE
146
+ Background:
147
+ Given table:
148
+ | a | b |
149
+ | c | d |
150
+ Scenario:
151
+ Given another table:
152
+ | e | f |
153
+ | g | h |
154
+ FEATURE
155
+
156
+ it { @doc.css('td').length.should == 8 }
157
+ end
158
+
159
+ describe "with a py string in the background and the scenario" do
160
+ define_feature <<-FEATURE
161
+ Background:
162
+ Given stuff:
163
+ """
164
+ foo
165
+ """
166
+ Scenario:
167
+ Given more stuff:
168
+ """
169
+ bar
170
+ """
171
+ FEATURE
172
+
173
+ it { @doc.css('.feature .background pre.val').length.should == 1 }
174
+ it { @doc.css('.feature .scenario pre.val').length.should == 1 }
175
+ end
176
+
177
+ describe "with a step that fails in the scenario" do
178
+ define_steps do
179
+ Given(/boo/) { raise 'eek' }
180
+ end
181
+
182
+ define_feature(<<-FEATURE)
183
+ Scenario: Monkey gets a fright
184
+ Given boo
185
+ FEATURE
186
+
187
+ it { @doc.should have_css_node('.feature .scenario .step.failed', /eek/) }
188
+ end
189
+
190
+ describe "with a step that fails in the backgound" do
191
+ define_steps do
192
+ Given(/boo/) { raise 'eek' }
193
+ end
194
+
195
+ define_feature(<<-FEATURE)
196
+ Background:
197
+ Given boo
198
+ Scenario:
199
+ Given yay
200
+ FEATURE
201
+
202
+ it { @doc.should have_css_node('.feature .background .step.failed', /eek/) }
203
+ it { @doc.should_not have_css_node('.feature .scenario .step.failed', //) }
204
+ it { @doc.should have_css_node('.feature .scenario .step.undefined', /yay/) }
205
+ end
206
+ end
207
+
208
+ describe "displaying page source to stdout" do
209
+ before(:each) do
210
+ setup_formatter
211
+ run_defined_feature
212
+ @doc = Nokogiri.HTML(@out.string)
213
+ end
214
+
215
+ define_steps do
216
+ Given(/foo/) do
217
+ visit("file://" + File.expand_path(File.dirname(__FILE__) + "/../fixtures/foo.html"))
218
+ end
219
+ end
220
+
221
+ define_feature(<<-FEATURE)
222
+ Scenario: Monkey goes to the zoo
223
+ Given foo
224
+ FEATURE
225
+
226
+ it do
227
+ step = @doc.at('.feature .scenario .step.passed')
228
+ link = step.at('a[href^="file:///tmp/"]')
229
+ link.should_not be_nil
230
+ end
231
+ end
232
+
233
+ describe "displaying page source to file" do
234
+ before(:each) do
235
+ @tmpdir = File.join(File.dirname(__FILE__), "..", "..", "tmp")
236
+ setup_formatter({:formats => [
237
+ ['Butternut::Formatter', File.join(@tmpdir, "main", "huge.html")]
238
+ ]})
239
+ run_defined_feature
240
+ @doc = Nokogiri.HTML(@out.string)
241
+
242
+ dir = File.join(@tmpdir, "features", Date.today.to_s)
243
+ file = most_recent_html_file(dir)
244
+ @page_doc = Nokogiri.HTML(open(file).read)
245
+ end
246
+
247
+ define_steps do
248
+ Given(/foo/) do
249
+ visit("file://" + File.expand_path(File.dirname(__FILE__) + "/../fixtures/foo.html"))
250
+ end
251
+ end
252
+
253
+ define_feature(<<-FEATURE)
254
+ Scenario: Monkey goes to the zoo
255
+ Given foo
256
+ FEATURE
257
+
258
+ it "links to the page source" do
259
+ step = @doc.at('.feature .scenario .step.passed')
260
+ link = step.at("a")
261
+ link.should_not be_nil
262
+ file = link['href']
263
+ file.should match(%r{^/features/#{Date.today.to_s}/butternut.+\.html})
264
+ end
265
+
266
+ it "saves images and stylesheets and rewrites urls in page source" do
267
+ @page_doc.at('img')['src'].should == "picard.jpg"
268
+ @page_doc.at('link[rel="stylesheet"]')['href'].should == "foo.css"
269
+ end
270
+
271
+ it "turns off links" do
272
+ @page_doc.css('a').each do |link|
273
+ link['href'].should == "#"
274
+ end
275
+ end
276
+
277
+ it "turns off scripts" do
278
+ @page_doc.css('script').length.should == 0
279
+ end
280
+
281
+ it "disables form elements" do
282
+ @page_doc.css('input, select, textarea').each do |elt|
283
+ elt['disabled'].should == "disabled"
284
+ end
285
+ end
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,128 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module Butternut
4
+ describe Helpers do
5
+ include Helpers
6
+
7
+ def define_stub_chain
8
+ # This is what I hate about RSpec.
9
+ @stub_request_url = stub("fake request url", :toString => "http://example.com")
10
+ @stub_response = stub("fake web response", :getRequestUrl => @stub_request_url)
11
+ @stub_page = stub("fake html page", {
12
+ :as_xml => "<cheese>pepperjack</cheese>",
13
+ :getWebResponse => @stub_response
14
+ })
15
+ @stub_element = stub("fake element", :value= => nil, :select => nil, :click => nil, :exist? => true)
16
+ @stub_empty = stub("fake empty element", :exist? => false)
17
+
18
+ @stub_browser = stub("fake celerity browser", {
19
+ :goto => @stub_page, :page => @stub_page,
20
+ :text_field => @stub_element, :select_list => @stub_element,
21
+ :button => @stub_element
22
+ })
23
+ stub!(:browser).and_return(@stub_browser)
24
+ end
25
+
26
+ describe "#browser" do
27
+ it { browser.should be_a(Celerity::Browser) }
28
+ end
29
+
30
+ describe "#page_changed?" do
31
+ it { page_changed?.should_not be_true }
32
+ end
33
+
34
+ describe "#visit" do
35
+ before(:each) { define_stub_chain }
36
+
37
+ it "should go to the page" do
38
+ @stub_browser.should_receive(:goto).with("http://google.com")
39
+ visit("http://google.com")
40
+ end
41
+
42
+ it "should flag page as changed" do
43
+ visit("http://google.com")
44
+ page_changed?.should be_true
45
+ end
46
+ end
47
+
48
+ describe "#current_url" do
49
+ before(:each) { define_stub_chain }
50
+ it do
51
+ @stub_request_url.should_receive(:toString).and_return("http://google.com")
52
+ current_url.should == "http://google.com"
53
+ end
54
+ end
55
+
56
+ describe "#current_page_source" do
57
+ before(:each) { define_stub_chain }
58
+
59
+ it "returns the current page's source" do
60
+ @stub_page.should_receive(:as_xml).and_return("pants")
61
+ current_page_source.should == "pants"
62
+ end
63
+
64
+ it "returns nil if page is nil" do
65
+ @stub_browser.stub!(:page).and_return(nil)
66
+ current_page_source.should be_nil
67
+ end
68
+ end
69
+
70
+ describe "#fill_in" do
71
+ before(:each) { define_stub_chain }
72
+
73
+ it "should find by label" do
74
+ @stub_browser.should_receive(:text_field).with(:label, "pants").and_return(@stub_element)
75
+ @stub_element.should_receive(:value=).with("khakis")
76
+ fill_in("pants", :with => "khakis")
77
+ end
78
+
79
+ it "should find by name" do
80
+ @stub_browser.should_receive(:text_field).with(:label, "pants").and_return(@stub_empty)
81
+ @stub_browser.should_receive(:text_field).with(:name, "pants").and_return(@stub_element)
82
+ @stub_element.should_receive(:value=).with("khakis")
83
+ fill_in("pants", :with => "khakis")
84
+ end
85
+
86
+ it "should flag page as changed" do
87
+ fill_in("pants", :with => "khakis")
88
+ page_changed?.should be_true
89
+ end
90
+ end
91
+
92
+ describe "#select" do
93
+ before(:each) { define_stub_chain }
94
+
95
+ it "should find by label" do
96
+ @stub_browser.should_receive(:select_list).with(:label, "pants").and_return(@stub_element)
97
+ @stub_element.should_receive(:select).with("khakis")
98
+ select("khakis", :from => "pants")
99
+ end
100
+
101
+ it "should find by name" do
102
+ @stub_browser.should_receive(:select_list).with(:label, "pants").and_return(@stub_empty)
103
+ @stub_browser.should_receive(:select_list).with(:name, "pants").and_return(@stub_element)
104
+ @stub_element.should_receive(:select).with("khakis")
105
+ select("khakis", :from => "pants")
106
+ end
107
+
108
+ it "should flag page as changed" do
109
+ select("khakis", :from => "pants")
110
+ page_changed?.should be_true
111
+ end
112
+ end
113
+
114
+ describe "#click_button" do
115
+ before(:each) { define_stub_chain }
116
+ it do
117
+ @stub_browser.should_receive(:button).with("pants").and_return(@stub_element)
118
+ @stub_element.should_receive(:click)
119
+ click_button("pants")
120
+ end
121
+
122
+ it "should flag page as changed" do
123
+ click_button("pants")
124
+ page_changed?.should be_true
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Butternut do
4
+ describe "running a scenario" do
5
+ extend SpecHelperDsl
6
+ include SpecHelper
7
+
8
+ describe "saving last page info" do
9
+ define_steps do
10
+ Given('waffles') do
11
+ visit("file://" + File.expand_path(File.dirname(__FILE__) + "/fixtures/foo.html"))
12
+ end
13
+ AfterStep do |scenario|
14
+ begin
15
+ scenario.last_page_source.should match(/Foo/)
16
+ scenario.last_page_url.should match(/foo\.html/)
17
+ rescue Exception => e
18
+ p e
19
+ end
20
+ end
21
+ end
22
+
23
+ define_feature <<-FEATURE
24
+ Scenario: Roffle waffles
25
+ Given waffles
26
+ FEATURE
27
+
28
+ it { run_defined_feature }
29
+ end
30
+
31
+ describe "resetting page_changed" do
32
+ define_steps do
33
+ Given('waffles') do
34
+ visit("file://" + File.expand_path(File.dirname(__FILE__) + "/fixtures/foo.txt"))
35
+ end
36
+ AfterStep do |scenario|
37
+ begin
38
+ page_changed?.should be_false
39
+ rescue Exception => e
40
+ p e
41
+ end
42
+ end
43
+ end
44
+
45
+ define_feature <<-FEATURE
46
+ Scenario: Roffle waffles
47
+ Given waffles
48
+ FEATURE
49
+
50
+ it { run_defined_feature }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ body {
2
+ font-family: Verdana;
3
+ }
@@ -0,0 +1,20 @@
1
+ <html>
2
+ <head>
3
+ <title>Foo</title>
4
+ <link rel="stylesheet" href="foo.css" type="text/css"/>
5
+ <script type="text/javascript" src="foo.js"></script>
6
+ </head>
7
+ <body>
8
+ Foo
9
+ <img src="picard.jpg"/>
10
+ <a href="http://picard.ytmnd.com/">Picard song</a>
11
+ <form action="foo.html" method="post">
12
+ <input type="text" name="foo" />
13
+ <select name="bar">
14
+ <option>pants</option>
15
+ </select>
16
+ <textarea name="yar"></textarea>
17
+ <input type="submit" value="Submit" />
18
+ </form>
19
+ </body>
20
+ </html>
@@ -0,0 +1,3 @@
1
+ function picard() {
2
+ alert('Make it so!');
3
+ }
Binary file
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,78 @@
1
+ require 'rubygems'
2
+ gem 'rspec'
3
+ require 'spec'
4
+ require 'spec/autorun'
5
+ require 'ruby-debug'
6
+
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
+ require 'butternut'
10
+
11
+ require 'cucumber/rb_support/rb_language'
12
+ require 'nokogiri'
13
+
14
+ module SpecHelperDsl
15
+ attr_reader :feature_content, :step_defs
16
+
17
+ def define_feature(string)
18
+ @feature_content = string
19
+ end
20
+
21
+ def define_steps(&block)
22
+ @step_defs = block
23
+ end
24
+ end
25
+
26
+ module SpecHelper
27
+ def run_defined_feature
28
+ setup_world
29
+ define_steps
30
+ features = load_features(self.class.feature_content || raise("No feature content defined!"))
31
+ run(features)
32
+ end
33
+
34
+ def step_mother
35
+ @step_mother ||= Cucumber::StepMother.new
36
+ end
37
+
38
+ def load_features(content)
39
+ feature_file = Cucumber::FeatureFile.new('spec.feature', content)
40
+ features = Cucumber::Ast::Features.new
41
+ features.add_feature feature_file.parse(step_mother, {})
42
+ features
43
+ end
44
+
45
+ def run(features)
46
+ # options = { :verbose => true }
47
+ options = {}
48
+ tree_walker = Cucumber::Ast::TreeWalker.new(step_mother, @formatter ? [@formatter] : [], options, STDOUT)
49
+ tree_walker.visit_features(features)
50
+ end
51
+
52
+ def dsl
53
+ unless @dsl
54
+ rb = step_mother.load_programming_language('rb')
55
+ @dsl = Object.new
56
+ @dsl.extend Cucumber::RbSupport::RbDsl
57
+ end
58
+ @dsl
59
+ end
60
+
61
+ def define_steps
62
+ return unless step_defs = self.class.step_defs
63
+ dsl.instance_exec &step_defs
64
+ end
65
+
66
+ def setup_world
67
+ dsl.instance_exec do
68
+ Butternut.setup_hooks(self)
69
+ World(Butternut::Helpers)
70
+ end
71
+ end
72
+ end
73
+
74
+ Spec::Runner.configure do |config|
75
+ config.before(:each) do
76
+ Cucumber::Parser::NaturalLanguage.instance_variable_set(:@languages, nil)
77
+ end
78
+ end
@@ -0,0 +1,2 @@
1
+ *
2
+ !.gitignore
@@ -0,0 +1,2 @@
1
+ *
2
+ !.gitignore