butternut 0.0.0

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,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