mechanical-cuke 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -2,18 +2,25 @@ h1. Mechanical Cuke
2
2
 
3
3
  mechanical-cuke re-implements the Cucumber step definitions provided by cucumber-rails' web_steps.rb in Mechanize. This allows Cucumber features to be written for any site by running the tests over HTTP.
4
4
 
5
+ mechanical-cuke also provides a driver for Capybara with enough support to run the cucumber-rails web_steps.rb. This allows you use Mechanize in conjunction with Capybara other drivers (handy if you need to do some Javascript testing).
6
+
5
7
  h2. Rational
6
8
 
7
9
  Webrat and Capybara both can drive tests over HTML. However, Webrat's Mechanize support is limited (doesn't work with multipart forms, can't submit empty form fields, no support for basic auth). Capybara drives tests over HTTP using browsers, excellent for testing Javascript, but slow for test that only involve HTML.
8
10
 
9
11
  h2. Usage
10
12
 
11
- Add:
13
+ To use the standalone version of Mechanical Cuke add:
12
14
 
13
- require 'mechanical-cuke'
15
+ bc. require 'mechanical-cuke'
14
16
 
15
17
  to features/support/env.rb
16
18
 
19
+ To use Mechanical Cuke with Capybara add:
20
+
21
+ bc. require 'mechanical-cuke/capybara'
22
+ Capybara.default_driver = :mechanical_cuke
23
+
17
24
  In features/support/paths.rb you will need to make sure you are returning the full URL. The simplest way to do this is to add 'URL' + before the case statement in the path_to function e.g.:
18
25
 
19
26
  bc. def path_to(page_name)
@@ -25,7 +32,7 @@ bc. def path_to(page_name)
25
32
  'http://localhost:3000' +
26
33
  case page_name
27
34
 
28
- h2. Steps Provided
35
+ h2. Steps Provided by the Standalone Version
29
36
 
30
37
  bc. Given am on path
31
38
  When I go to path
@@ -116,6 +123,8 @@ bc. When I press "Submit" within "#login_form"
116
123
 
117
124
  Make Rspec support actually work.
118
125
 
126
+ Make Capybara driver complete.
127
+
119
128
  h2. Author
120
129
 
121
130
  Spike Ilacqua
data/Rakefile CHANGED
@@ -17,6 +17,7 @@ begin
17
17
  gem.add_development_dependency "cucumber-rails", ">= 0.2.4"
18
18
  gem.add_development_dependency "mocha", ">= 0.9.8"
19
19
  gem.add_development_dependency "sinatra", ">= 1.0"
20
+ gem.add_development_dependency "capybara", "0.3.9"
20
21
  end
21
22
  Jeweler::GemcutterTasks.new
22
23
  rescue LoadError
@@ -54,6 +55,15 @@ begin
54
55
  Cucumber::Rake::Task.new(:wip, 'Run features that are in progress') do |t|
55
56
  t.cucumber_opts = "--tags @wip:3 --wip features"
56
57
  end
58
+
59
+ Cucumber::Rake::Task.new(:capybara, 'Run features against Capybara') do |t|
60
+ t.cucumber_opts = "CAPYBARA=yes"
61
+ end
62
+
63
+ Cucumber::Rake::Task.new('capybara:wip', 'Run features @wip against Capybara') do |t|
64
+ t.cucumber_opts = "CAPYBARA=yes --tags @wip:3 --wip features"
65
+ end
66
+
57
67
  rescue LoadError
58
68
  task :cucumber do
59
69
  abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.3
1
+ 0.5.0
@@ -3,7 +3,13 @@ Given /^I have no basic auth credentials$/ do
3
3
  end
4
4
 
5
5
  Then /^I should not be able to access (.+)$/ do |page_name|
6
- assert_raise(Mechanize::ResponseCodeError) { get path_to(page_name) }
6
+ assert_raise(Mechanize::ResponseCodeError) do
7
+ if respond_to? :visit
8
+ visit path_to(page_name)
9
+ else
10
+ get path_to(page_name)
11
+ end
12
+ end
7
13
  end
8
14
 
9
15
  Given /^I have basic auth credentials "([^\"]*)"$/ do |credentials|
@@ -0,0 +1,213 @@
1
+ if ENV['CAPYBARA']
2
+
3
+ module WithinHelpers
4
+ def with_scope(locator)
5
+ locator ? within(locator) { yield } : yield
6
+ end
7
+ end
8
+ World(WithinHelpers)
9
+
10
+ Given /^(?:|I )am on (.+)$/ do |page_name|
11
+ visit path_to(page_name)
12
+ end
13
+
14
+ When /^(?:|I )go to (.+)$/ do |page_name|
15
+ visit path_to(page_name)
16
+ end
17
+
18
+ When /^(?:|I )press "([^"]*)"(?: within "([^"]*)")?$/ do |button, selector|
19
+ with_scope(selector) do
20
+ click_button(button)
21
+ end
22
+ end
23
+
24
+ When /^(?:|I )follow "([^\"]*)"(?: within "([^\"]*)")?$/ do |link, selector|
25
+ with_scope(selector) do
26
+ click_link(link)
27
+ end
28
+ end
29
+
30
+ When /^(?:|I )fill in "([^\"]*)" with "([^\"]*)"(?: within "([^\"]*)")?$/ do |field, value, selector|
31
+ with_scope(selector) do
32
+ fill_in(field, :with => value)
33
+ end
34
+ end
35
+
36
+ When /^(?:|I )fill in "([^\"]*)" for "([^\"]*)"(?: within "([^\"]*)")?$/ do |value, field, selector|
37
+ with_scope(selector) do
38
+ fill_in(field, :with => value)
39
+ end
40
+ end
41
+
42
+ # Use this to fill in an entire form with data from a table. Example:
43
+ #
44
+ # When I fill in the following:
45
+ # | Account Number | 5002 |
46
+ # | Expiry date | 2009-11-01 |
47
+ # | Note | Nice guy |
48
+ # | Wants Email? | |
49
+ #
50
+ # TODO: Add support for checkbox, select og option
51
+ # based on naming conventions.
52
+ #
53
+ When /^(?:|I )fill in the following(?: within "([^\"]*)")?:$/ do |selector, fields|
54
+ with_scope(selector) do
55
+ fields.rows_hash.each do |name, value|
56
+ When %{I fill in "#{name}" with "#{value}"}
57
+ end
58
+ end
59
+ end
60
+
61
+ When /^(?:|I )select "([^\"]*)" from "([^\"]*)"(?: within "([^\"]*)")?$/ do |value, field, selector|
62
+ with_scope(selector) do
63
+ select(value, :from => field)
64
+ end
65
+ end
66
+
67
+ When /^(?:|I )check "([^\"]*)"(?: within "([^\"]*)")?$/ do |field, selector|
68
+ with_scope(selector) do
69
+ check(field)
70
+ end
71
+ end
72
+
73
+ When /^(?:|I )uncheck "([^\"]*)"(?: within "([^\"]*)")?$/ do |field, selector|
74
+ with_scope(selector) do
75
+ uncheck(field)
76
+ end
77
+ end
78
+
79
+ When /^(?:|I )choose "([^\"]*)"(?: within "([^\"]*)")?$/ do |field, selector|
80
+ with_scope(selector) do
81
+ choose(field)
82
+ end
83
+ end
84
+
85
+ When /^(?:|I )attach the file "([^\"]*)" to "([^\"]*)"(?: within "([^\"]*)")?$/ do |path, field, selector|
86
+ with_scope(selector) do
87
+ attach_file(field, path)
88
+ end
89
+ end
90
+
91
+ Then /^(?:|I )should see JSON:$/ do |expected_json|
92
+ require 'json'
93
+ expected = JSON.pretty_generate(JSON.parse(expected_json))
94
+ actual = JSON.pretty_generate(JSON.parse(response.body))
95
+ expected.should == actual
96
+ end
97
+
98
+ Then /^(?:|I )should see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, selector|
99
+ with_scope(selector) do
100
+ if page.respond_to? :should
101
+ page.should have_content(text)
102
+ else
103
+ assert page.has_content?(text)
104
+ end
105
+ end
106
+ end
107
+
108
+ Then /^(?:|I )should see \/([^\/]*)\/(?: within "([^\"]*)")?$/ do |regexp, selector|
109
+ regexp = Regexp.new(regexp)
110
+ with_scope(selector) do
111
+ if page.respond_to? :should
112
+ page.should have_xpath('//*', :text => regexp)
113
+ else
114
+ assert page.has_xpath?('//*', :text => regexp)
115
+ end
116
+ end
117
+ end
118
+
119
+ Then /^(?:|I )should not see "([^\"]*)"(?: within "([^\"]*)")?$/ do |text, selector|
120
+ with_scope(selector) do
121
+ if page.respond_to? :should
122
+ page.should have_no_content(text)
123
+ else
124
+ assert page.has_no_content?(text)
125
+ end
126
+ end
127
+ end
128
+
129
+ Then /^(?:|I )should not see \/([^\/]*)\/(?: within "([^\"]*)")?$/ do |regexp, selector|
130
+ regexp = Regexp.new(regexp)
131
+ with_scope(selector) do
132
+ if page.respond_to? :should
133
+ page.should have_no_xpath('//*', :text => regexp)
134
+ else
135
+ assert page.has_no_xpath?('//*', :text => regexp)
136
+ end
137
+ end
138
+ end
139
+
140
+ Then /^the "([^\"]*)" field(?: within "([^\"]*)")? should contain "([^\"]*)"$/ do |field, selector, value|
141
+ with_scope(selector) do
142
+ field = find_field(field)
143
+ field_value = (field.tag_name == 'textarea') ? field.text : field.value
144
+ if field_value.respond_to? :should
145
+ field_value.should =~ /#{value}/
146
+ else
147
+ assert_match(/#{value}/, field_value)
148
+ end
149
+ end
150
+ end
151
+
152
+ Then /^the "([^\"]*)" field(?: within "([^\"]*)")? should not contain "([^\"]*)"$/ do |field, selector, value|
153
+ with_scope(selector) do
154
+ field = find_field(field)
155
+ field_value = (field.tag_name == 'textarea') ? field.text : field.value
156
+ if field_value.respond_to? :should_not
157
+ field_value.should_not =~ /#{value}/
158
+ else
159
+ assert_no_match(/#{value}/, field_value)
160
+ end
161
+ end
162
+ end
163
+
164
+ Then /^the "([^\"]*)" checkbox(?: within "([^\"]*)")? should be checked$/ do |label, selector|
165
+ with_scope(selector) do
166
+ field_checked = find_field(label)['checked']
167
+ if field_checked.respond_to? :should
168
+ field_checked.should be_true
169
+ else
170
+ assert field_checked
171
+ end
172
+ end
173
+ end
174
+
175
+ Then /^the "([^\"]*)" checkbox(?: within "([^\"]*)")? should not be checked$/ do |label, selector|
176
+ with_scope(selector) do
177
+ field_checked = find_field(label)['checked']
178
+ if field_checked.respond_to? :should
179
+ field_checked.should be_false
180
+ else
181
+ assert !field_checked
182
+ end
183
+ end
184
+ end
185
+
186
+ Then /^(?:|I )should be on (.+)$/ do |page_name|
187
+ # current_path = URI.parse(current_url).path # FIX ME
188
+ current_path = current_url
189
+ if current_path.respond_to? :should
190
+ current_path.should == path_to(page_name)
191
+ else
192
+ assert_equal path_to(page_name), current_path
193
+ end
194
+ end
195
+
196
+ Then /^(?:|I )should have the following query string:$/ do |expected_pairs|
197
+ query = URI.parse(current_url).query
198
+ actual_params = query ? CGI.parse(query) : {}
199
+ expected_params = {}
200
+ expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
201
+
202
+ if actual_params.respond_to? :should
203
+ actual_params.should == expected_params
204
+ else
205
+ assert_equal expected_params, actual_params
206
+ end
207
+ end
208
+
209
+ Then /^show me the page$/ do
210
+ save_and_open_page
211
+ end
212
+
213
+ end
@@ -1,24 +1,26 @@
1
+ require 'capybara'
2
+
1
3
  When /^I (?:fill in|select|choose|check|press) a nonexistent (.+) an error should be raised$/ do |type|
2
4
 
3
5
  case type
4
6
  when "text field" then
5
- assert_raise(RuntimeError) do
7
+ assert_raise(RuntimeError,Capybara::ElementNotFound) do
6
8
  When %{I fill in "nonexistent" with "anything"}
7
9
  end
8
10
  when "select field" then
9
- assert_raise(RuntimeError) do
11
+ assert_raise(RuntimeError,Capybara::ElementNotFound) do
10
12
  When %{I select "anything" from "nonexistent"}
11
13
  end
12
14
  when "radio button" then
13
- assert_raise(RuntimeError) do
15
+ assert_raise(RuntimeError,Capybara::ElementNotFound) do
14
16
  When %{I choose "nonexistent"}
15
17
  end
16
18
  when "checkbox" then
17
- assert_raise(RuntimeError) do
19
+ assert_raise(RuntimeError,Capybara::ElementNotFound) do
18
20
  When %{I check "nonexistent"}
19
21
  end
20
22
  when "button" then
21
- assert_raise(RuntimeError) do
23
+ assert_raise(RuntimeError,Capybara::ElementNotFound) do
22
24
  When %{I press "nonexistent"}
23
25
  end
24
26
  else assert false
@@ -26,33 +28,33 @@ When /^I (?:fill in|select|choose|check|press) a nonexistent (.+) an error shoul
26
28
  end
27
29
 
28
30
  When /^I follow a nonexistent link an error should be raised$/ do
29
- assert_raise(RuntimeError) do
31
+ assert_raise(RuntimeError,Capybara::ElementNotFound) do
30
32
  When %{I follow "nonexistent"}
31
33
  end
32
34
  end
33
35
 
34
36
  When /^I select a missing option from an existing select an error should be raised$/ do
35
- assert_raise(RuntimeError) do
37
+ assert_raise(RuntimeError,Capybara::OptionNotFound) do
36
38
  When %{I select "nonexistent" from "Exists"}
37
39
  end
38
40
  end
39
41
 
40
42
  When /^I test the value of a nonexistent field contains an error should be raised$/ do
41
- assert_raise(RuntimeError) do
43
+ assert_raise(RuntimeError,NoMethodError) do
42
44
  When %{the "nonexistent" field should contain "Anything"}
43
45
  end
44
46
 
45
- assert_raise(RuntimeError) do
47
+ assert_raise(RuntimeError,NoMethodError) do
46
48
  When %{the "nonexistent" field should not contain "Anything"}
47
49
  end
48
50
  end
49
51
 
50
52
  When /^I test state of a nonexistent checkbox contains an error should be raised$/ do
51
- assert_raise(RuntimeError) do
53
+ assert_raise(RuntimeError,NoMethodError) do
52
54
  When %{the "nonexistent" checkbox should be checked}
53
55
  end
54
56
 
55
- assert_raise(RuntimeError) do
57
+ assert_raise(RuntimeError,NoMethodError) do
56
58
  When %{the "nonexistent" checkbox should not be checked}
57
59
  end
58
60
  end
@@ -1,11 +1,17 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'open4'
2
3
 
3
- require 'mechanical-cuke'
4
+ if ENV['CAPYBARA']
5
+ require 'capybara/cucumber'
6
+ require 'mechanical-cuke/capybara'
7
+ Capybara.default_driver = :mechanical_cuke
8
+ Capybara.save_and_open_page_path = File.dirname(__FILE__) + '/../../tmp'
9
+ else
10
+ require 'mechanical-cuke'
11
+ end
4
12
 
5
13
  require 'test/unit/assertions'
6
14
 
7
- require 'open4'
8
-
9
15
  World(Test::Unit::Assertions)
10
16
 
11
17
  Before do
@@ -1,5 +1,4 @@
1
1
  require 'mechanize'
2
- require 'mechanical-cuke/web_steps'
3
2
  require 'mechanical-cuke/save_and_open'
4
3
 
5
4
  module MechanicalCuke
@@ -26,18 +25,21 @@ module MechanicalCuke
26
25
  current_page.body
27
26
  end
28
27
 
28
+ def body
29
+ current_page.body
30
+ end
31
+
32
+ def form
33
+ current_page.forms.first
34
+ end
35
+
29
36
  def basic_auth(username,password)
30
37
  mechanize.basic_auth(username,password)
31
38
  end
32
39
  end
33
40
 
34
- World(MechanicalCuke)
35
-
36
41
  private
37
42
 
38
- def form
39
- current_page.forms.first
40
- end
41
43
 
42
44
  def find_by_id(id)
43
45
  node = current_page.search("##{id}")
@@ -100,3 +102,8 @@ def find_checkbox(field)
100
102
 
101
103
  return nil
102
104
  end
105
+
106
+ unless defined?(Capybara)
107
+ require 'mechanical-cuke/web_steps'
108
+ World(MechanicalCuke)
109
+ end
@@ -0,0 +1,7 @@
1
+ module MechanicalCuke
2
+ module BasicAuth
3
+ def basic_auth(username,password)
4
+ page.driver.basic_auth(username, password)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,98 @@
1
+ require 'mechanize'
2
+ require 'capybara'
3
+ require 'capybara/driver/base'
4
+ require 'capybara/node'
5
+ require 'mechanical-cuke'
6
+ require 'mechanical-cuke/basic_auth'
7
+
8
+ World(MechanicalCuke::BasicAuth)
9
+
10
+ class Capybara::Driver::MechanicalCuke < Capybara::Driver::Base
11
+ include MechanicalCuke
12
+ class Node < Capybara::Node
13
+
14
+ def text
15
+ node.text
16
+ end
17
+
18
+ def [](name)
19
+ if name == :value
20
+ node.value
21
+ else
22
+ node.attribute(name.to_s)
23
+ end
24
+ end
25
+
26
+ def value
27
+ driver.form.field_with(:node => node).value
28
+ end
29
+
30
+ def set(value)
31
+ case self.node['type']
32
+ when 'radio'
33
+ radio = driver.form.radiobutton_with(:node => node)
34
+ if (value)
35
+ radio.check
36
+ else
37
+ radio.uncheck
38
+ end
39
+ when 'checkbox'
40
+ driver.form.checkbox_with(:node => node).checked = value
41
+ when 'file'
42
+ driver.form.file_upload_with(:node => node).file_name = value
43
+ else
44
+ driver.form.field_with(:node => node).value = value
45
+ end
46
+ end
47
+
48
+ def select(option)
49
+ field = driver.form.field_with(:node => node)
50
+ if field_option = field.option_with(:value => option)
51
+ field_option.select
52
+ else
53
+ raise Capybara::OptionNotFound, "No such option '#{option}' in this select box. Available options: TODO"
54
+ end
55
+ end
56
+
57
+ def click
58
+ if tag_name == 'a'
59
+ link = driver.current_page.link_with(:node => self.node)
60
+ link.click
61
+ elsif self.node['type'] == 'submit'
62
+ button = driver.form.button_with(:node => self.node)
63
+ driver.form.click_button(button)
64
+ else
65
+ nil
66
+ end
67
+ end
68
+
69
+ def tag_name
70
+ node.node_name
71
+ end
72
+ end
73
+
74
+ def visit(path)
75
+ get path
76
+ end
77
+
78
+ def body
79
+ current_page.body
80
+ end
81
+
82
+ alias_method :source, :body
83
+
84
+ def current_url
85
+ current_page.uri.to_s
86
+ end
87
+
88
+ def initialize(app)
89
+ end
90
+
91
+ def find(locator)
92
+ current_page.search(locator).map { |node| Node.new(self, node) }
93
+ end
94
+
95
+ def form
96
+ current_page.forms.first
97
+ end
98
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mechanical-cuke
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Spike Ilacqua
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-08-23 00:00:00 -06:00
12
+ date: 2010-08-24 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -82,6 +82,16 @@ dependencies:
82
82
  - !ruby/object:Gem::Version
83
83
  version: "1.0"
84
84
  version:
85
+ - !ruby/object:Gem::Dependency
86
+ name: capybara
87
+ type: :development
88
+ version_requirement:
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "="
92
+ - !ruby/object:Gem::Version
93
+ version: 0.3.9
94
+ version:
85
95
  description: A Mechanize driver for Cucumber. Provides step definitions for driving web applications using Mechanize.
86
96
  email: spike@indra.com
87
97
  executables: []
@@ -100,6 +110,7 @@ files:
100
110
  - VERSION
101
111
  - features/missing_fields.feature
102
112
  - features/step_definitions/basic_auth_steps.rb
113
+ - features/step_definitions/capybara-web_steps.rb
103
114
  - features/step_definitions/mechanical-cuke_steps.rb
104
115
  - features/step_definitions/missing_field_steps.rb
105
116
  - features/step_definitions/table_steps.rb
@@ -109,6 +120,8 @@ files:
109
120
  - features/table_steps.feature
110
121
  - features/web_steps.feature
111
122
  - lib/mechanical-cuke.rb
123
+ - lib/mechanical-cuke/basic_auth.rb
124
+ - lib/mechanical-cuke/capybara.rb
112
125
  - lib/mechanical-cuke/save_and_open.rb
113
126
  - lib/mechanical-cuke/web_steps.rb
114
127
  - test/fixtures/hello.txt