kelp 0.1.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,14 +24,30 @@ When /^I run cucumber on "(.+)"$/ do |feature|
24
24
  end
25
25
 
26
26
 
27
- Then /^the results should include:$/ do |expected_results|
28
- # Remove leading whitespace before comparison
29
- got = @output.gsub(/^\s*/, '')
30
- want = expected_results.gsub(/^\s*/, '')
31
- if !got.include?(want)
32
- got = @output.collect {|line| " #{line}"}.join
33
- want = expected_results.collect {|line| " #{line}"}.join
34
- raise("Expected:\n#{want}\nGot:\n#{got}")
27
+ # Ensure that the results include the expected lines, in the same order.
28
+ # Extra lines in the results are ignored.
29
+ Then /^the results should include:$/ do |expected_lines|
30
+ # Full actual output, for error reporting
31
+ got = @output.collect {|line| " #{line}"}.join
32
+ # Remove leading whitespace and split into lines
33
+ got_lines = @output.gsub(/^\s*/, '').split("\n")
34
+ want_lines = expected_lines.gsub(/^\s*/, '').split("\n")
35
+ last_index = -1
36
+ # Ensure that each wanted line is present in the output,
37
+ # and that it comes after any preceding expected lines.
38
+ want_lines.each do |want|
39
+ if !want.empty?
40
+ index = got_lines.index(want)
41
+ # Not found?
42
+ if index.nil?
43
+ raise("Got:\n#{got}\nExpected line not found:\n #{want}")
44
+ # Not in order?
45
+ elsif index < last_index
46
+ raise("Got:\n#{got}\nExpected line found, but out of order:\n #{want}")
47
+ else
48
+ last_index = index
49
+ end
50
+ end
35
51
  end
36
52
  end
37
53
 
data/kelp.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "kelp"
3
- s.version = "0.1.9"
3
+ s.version = "0.2.0"
4
4
  s.summary = "Cucumber helper methods"
5
5
  s.description = <<-EOS
6
6
  Kelp is a collection of helper methods for Cucumber to ease the process of
data/lib/kelp.rb CHANGED
@@ -7,20 +7,5 @@ require 'kelp/scoping'
7
7
  require 'kelp/visibility'
8
8
 
9
9
  module Kelp
10
- class << self
11
- attr_writer :driver
12
-
13
- # @return [Symbol]
14
- # Name of the default driver used by Kelp
15
- def default_driver
16
- :capybara
17
- end
18
-
19
- # @return [Symbol]
20
- # Name of the current driver used by Kelp (:capybara or :webrat)
21
- def driver
22
- @driver || default_driver
23
- end
24
- end
25
10
  end
26
11
 
@@ -9,9 +9,20 @@ module Kelp
9
9
  # @param [String] element_id
10
10
  # HTML `id` attribute of the element that should be disabled
11
11
  #
12
+ # @raise [Kelp::Unexpected]
13
+ # If the given element id is not found, or the element is not disabled
14
+ #
12
15
  def should_be_disabled(element_id)
13
- page.should have_xpath("//*[@id='#{element_id}']")
14
- page.should have_xpath("//*[@id='#{element_id}' and @disabled]")
16
+ if page.has_xpath?("//*[@id='#{element_id}']")
17
+ if !page.has_xpath?("//*[@id='#{element_id}' and @disabled]")
18
+ raise Kelp::Unexpected,
19
+ "Expected element with id='#{element_id}' to be disabled," + \
20
+ " but the 'disabled' attribute is not present."
21
+ end
22
+ else
23
+ raise Kelp::Unexpected,
24
+ "Element with id='#{element_id}' not found."
25
+ end
15
26
  end
16
27
 
17
28
 
@@ -21,9 +32,20 @@ module Kelp
21
32
  # @param [String] element_id
22
33
  # HTML `id` attribute of the element that should be enabled
23
34
  #
35
+ # @raise [Kelp::Unexpected]
36
+ # If the given element id is not found, or the element is not enabled
37
+ #
24
38
  def should_be_enabled(element_id)
25
- page.should have_xpath("//*[@id='#{element_id}']")
26
- page.should have_no_xpath("//*[@id='#{element_id}' and @disabled]")
39
+ if page.has_xpath?("//*[@id='#{element_id}']")
40
+ if page.has_xpath?("//*[@id='#{element_id}' and @disabled]")
41
+ raise Kelp::Unexpected,
42
+ "Expected element with id='#{element_id}' to be enabled," + \
43
+ " but the 'disabled' attribute is present."
44
+ end
45
+ else
46
+ raise Kelp::Unexpected,
47
+ "Element with id='#{element_id}' not found."
48
+ end
27
49
  end
28
50
 
29
51
  end
data/lib/kelp/checkbox.rb CHANGED
@@ -1,29 +1,54 @@
1
1
  require 'kelp/helper'
2
2
  require 'kelp/scoping'
3
+ require 'kelp/exceptions'
3
4
 
4
5
  module Kelp
5
6
  module Checkbox
6
7
  include Scoping
7
8
  include Helper
8
9
 
10
+ # Verify that the given checkbox is checked.
11
+ #
12
+ # @param [String] checkbox
13
+ # Capybara locator for the checkbox
14
+ # @param [Hash] scope
15
+ # Scoping keywords as understood by {#in_scope}
16
+ #
17
+ # @raise [Kelp::Unexpected]
18
+ # If the given checkbox is not checked
19
+ #
20
+ # @since 0.1.2
21
+ #
9
22
  def checkbox_should_be_checked(checkbox, scope={})
10
23
  in_scope(scope) do
11
24
  field_checked = find_field(checkbox)['checked']
12
- if field_checked.respond_to? :should
13
- field_checked.should be_true
14
- else
15
- assert field_checked
25
+ puts field_checked.inspect
26
+ if !field_checked
27
+ raise Kelp::Unexpected,
28
+ "Expected '#{checkbox}' to be checked, but it is unchecked."
16
29
  end
17
30
  end
18
31
  end
19
32
 
33
+
34
+ # Verify that the given checkbox is not checked.
35
+ #
36
+ # @param [String] checkbox
37
+ # Capybara locator for the checkbox
38
+ # @param [Hash] scope
39
+ # Scoping keywords as understood by {#in_scope}
40
+ #
41
+ # @raise [Kelp::Unexpected]
42
+ # If the given checkbox is checked
43
+ #
44
+ # @since 0.1.2
45
+ #
20
46
  def checkbox_should_not_be_checked(checkbox, scope={})
21
47
  in_scope(scope) do
22
48
  field_checked = find_field(checkbox)['checked']
23
- if field_checked.respond_to? :should
24
- field_checked.should be_false
25
- else
26
- assert !field_checked
49
+ if field_checked
50
+ raise Kelp::Unexpected,
51
+ "Expected '#{checkbox}' to be unchecked, but it is checked."
27
52
  end
28
53
  end
29
54
  end
data/lib/kelp/dropdown.rb CHANGED
@@ -22,6 +22,9 @@ module Kelp
22
22
  # @param [Hash] scope
23
23
  # Scoping keywords as understood by {#in_scope}
24
24
  #
25
+ # @raise [Kelp::Unexpected]
26
+ # If the given dropdown does not equal `value`
27
+ #
25
28
  def dropdown_should_equal(dropdown, value, scope={})
26
29
  in_scope(scope) do
27
30
  field = nice_find_field(dropdown)
@@ -37,7 +40,10 @@ module Kelp
37
40
  field_value = xpath_sanitize(field.value)
38
41
  selected = field.find(:xpath, ".//option[@value=#{field_value}]")
39
42
  end
40
- selected.text.should =~ /#{value}/
43
+ if selected.text != value
44
+ raise Kelp::Unexpected,
45
+ "Expected '#{dropdown}' dropdown to equal '#{value}'\nGot '#{selected.text}' instead"
46
+ end
41
47
  end
42
48
  end
43
49
 
@@ -57,15 +63,22 @@ module Kelp
57
63
  # @param [Hash] scope
58
64
  # Scoping keywords as understood by {#in_scope}
59
65
  #
66
+ # @raise [Kelp::Unexpected]
67
+ # If the given dropdown does not include all `values`
68
+ #
60
69
  def dropdown_should_include(dropdown, values, scope={})
61
70
  in_scope(scope) do
62
71
  # If values is a String, convert it to an Array
63
72
  values = [values] if values.class == String
64
-
65
73
  field = nice_find_field(dropdown)
66
- # Look for each value
67
- values.each do |value|
68
- page.should have_xpath(".//option[text()=#{xpath_sanitize(value)}]")
74
+ # Select all expected values that don't appear in the dropdown
75
+ unexpected = values.select do |value|
76
+ !page.has_xpath?(".//option[text()=#{xpath_sanitize(value)}]")
77
+ end
78
+ if !unexpected.empty?
79
+ raise Kelp::Unexpected,
80
+ "Expected '#{dropdown}' dropdown to include: #{values.inspect}" + \
81
+ "\nMissing: #{unexpected.inspect}"
69
82
  end
70
83
  end
71
84
  end
@@ -82,17 +95,24 @@ module Kelp
82
95
  # @param [Hash] scope
83
96
  # Scoping keywords as understood by {#in_scope}
84
97
  #
98
+ # @raise [Kelp::Unexpected]
99
+ # If the given dropdown includes any value in `values`
100
+ #
85
101
  # @since 0.1.2
86
102
  #
87
103
  def dropdown_should_not_include(dropdown, values, scope={})
88
104
  in_scope(scope) do
89
105
  # If values is a String, convert it to an Array
90
106
  values = [values] if values.class == String
91
-
92
107
  field = nice_find_field(dropdown)
93
- # Look for each value
94
- values.each do |value|
95
- page.should have_no_xpath(".//option[text()=#{xpath_sanitize(value)}]")
108
+ # Select all not-expected values that do appear in the dropdown
109
+ unexpected = values.select do |value|
110
+ page.has_xpath?(".//option[text()=#{xpath_sanitize(value)}]")
111
+ end
112
+ if !unexpected.empty?
113
+ raise Kelp::Unexpected,
114
+ "Expected '#{dropdown}' dropdown to not include: #{values.inspect}" + \
115
+ "\nDid include: #{unexpected.inspect}"
96
116
  end
97
117
  end
98
118
  end
@@ -108,10 +128,16 @@ module Kelp
108
128
  # @param [String] value
109
129
  # Expected `value` attribute of the selected `option`
110
130
  #
131
+ # @raise [Kelp::Unexpected]
132
+ # If the given dropdown's 'value' attribute is not equal to `value`
133
+ #
111
134
  def dropdown_value_should_equal(dropdown, value)
112
- # FIXME: When this returns False, does that fail the step?
113
135
  field = find_field(dropdown)
114
- field.value.should include(value)
136
+ if field.value != value
137
+ raise Kelp::Unexpected,
138
+ "Expected '#{dropdown}' dropdown's value to equal '#{value}'" + \
139
+ "\nGot '#{field.value}' instead"
140
+ end
115
141
  end
116
142
 
117
143
  end
@@ -1,5 +1,7 @@
1
1
  module Kelp
2
- class Unexpected < RuntimeError
3
- end
2
+ class KelpError < StandardError; end
3
+ class Unexpected < KelpError; end
4
+ class FieldNotFound < KelpError; end
5
+ class OptionNotFound < KelpError; end
4
6
  end
5
7
 
data/lib/kelp/field.rb CHANGED
@@ -19,13 +19,35 @@ module Kelp
19
19
  # @param [String] value
20
20
  # Text to select from a dropdown or enter in a text box
21
21
  #
22
+ # @raise [Kelp::FieldNotFound]
23
+ # If no field matching `field` is found
24
+ # @raise [Kelp::OptionNotFound]
25
+ # If a dropdown matching `field` is found, but it has no
26
+ # option matching `value`
27
+ #
22
28
  # @since 0.1.9
23
29
  #
24
30
  def select_or_fill(field, value)
25
31
  begin
26
32
  select(value, :from => field)
27
- rescue
28
- fill_in(field, :with => value)
33
+ rescue Capybara::ElementNotFound => err
34
+ # The select method may raise ElementNotFound in two cases:
35
+ # (1) The given field does not exist, in which case try a text field
36
+ if err.message =~ /no select box with id, name, or label/
37
+ begin
38
+ fill_in(field, :with => value)
39
+ rescue Capybara::ElementNotFound
40
+ raise Kelp::FieldNotFound,
41
+ "No field with id, name, or label '#{field}' found"
42
+ end
43
+ # (2) The field exists, but the value does not
44
+ elsif err.message =~ /no option with text/
45
+ raise Kelp::OptionNotFound,
46
+ "Field '#{field}' has no option '#{value}'"
47
+ # And just in case...
48
+ else
49
+ raise
50
+ end
29
51
  end
30
52
  end
31
53
 
@@ -41,70 +63,77 @@ module Kelp
41
63
  # Text to select from a dropdown or enter in a text box, or
42
64
  # `checked` or `unchecked` to operate on a checkbox
43
65
  #
66
+ # @raise [Kelp::Nonexistent]
67
+ # If no checkbox, dropdown, or text box is found with the given
68
+ # identifier
69
+ #
44
70
  # @since 0.1.9
45
71
  #
46
72
  def check_or_select_or_fill(field, value)
47
73
  # If value is "checked" or "unchecked", assume
48
74
  # field is a checkbox
49
- if value == "checked"
50
- begin
75
+ begin
76
+ if value == "checked"
51
77
  check(field)
52
- rescue
53
- select_or_fill(field, value)
54
- end
55
- elsif value == "unchecked"
56
- begin
78
+ elsif value == "unchecked"
57
79
  uncheck(field)
58
- rescue
80
+ else
59
81
  select_or_fill(field, value)
60
82
  end
61
- else
83
+ rescue Capybara::ElementNotFound
62
84
  select_or_fill(field, value)
63
85
  end
64
86
  end
65
87
 
66
88
 
67
- # Fill in multiple fields according to values in a `Hash`.
68
- # Fields may be text boxes, dropdowns/listboxes, or checkboxes.
89
+ # Fill in a single field within the scope of a given selector.
90
+ # The field may be a text box, dropdown/listbox, or checkbox.
69
91
  # See {#check_or_select_or_fill} for details.
70
92
  #
71
93
  # @example
72
- # fill_in_fields "First name" => "Otto", "Last name" => "Scratchansniff"
73
- # fill_in_fields "phone" => "303-224-7428", :within => "#home"
94
+ # fill_in_field "Email", "otto@scratchansniff.wb"
95
+ # fill_in_field "Send me junk email", "unchecked"
74
96
  #
75
- # @param [Hash] field_values
76
- # "field" => "value" for each field to fill in, select, or check/uncheck
97
+ # @param [String] field
98
+ # Capybara locator for the field (name, id, or label text)
99
+ # @param [String] value
100
+ # Text to select from a dropdown or enter in a text box, or
101
+ # `checked` or `unchecked` to operate on a checkbox
77
102
  # @param [Hash] scope
78
103
  # Scoping keywords as understood by {#in_scope}
79
104
  #
80
- def fill_in_fields(field_values, scope={})
105
+ # @raise [Kelp::FieldNotFound]
106
+ # If no field is found matching the given identifier
107
+ #
108
+ def fill_in_field(field, value, scope={})
81
109
  in_scope(scope) do
82
- field_values.each do |field, value|
83
- check_or_select_or_fill(field, value)
84
- end
110
+ check_or_select_or_fill(field, value)
85
111
  end
86
112
  end
87
113
 
88
114
 
89
- # Fill in a single field within the scope of a given selector.
90
- # The field may be a text box, dropdown/listbox, or checkbox.
115
+ # Fill in multiple fields according to values in a `Hash`.
116
+ # Fields may be text boxes, dropdowns/listboxes, or checkboxes.
91
117
  # See {#check_or_select_or_fill} for details.
92
118
  #
93
119
  # @example
94
- # fill_in_field "Email", "otto@scratchansniff.wb"
95
- # fill_in_field "Send me junk email", "unchecked"
120
+ # fill_in_fields "First name" => "Otto", "Last name" => "Scratchansniff"
121
+ # fill_in_fields "phone" => "303-224-7428", :within => "#home"
96
122
  #
97
- # @param [String] field
98
- # Capybara locator for the field (name, id, or label text)
99
- # @param [String] value
100
- # Text to select from a dropdown or enter in a text box, or
101
- # `checked` or `unchecked` to operate on a checkbox
123
+ # @param [Hash] field_values
124
+ # "field" => "value" for each field to fill in, select, or check/uncheck
102
125
  # @param [Hash] scope
103
126
  # Scoping keywords as understood by {#in_scope}
104
127
  #
105
- def fill_in_field(field, value, scope={})
106
- fields = {field => value}
107
- fill_in_fields fields, scope
128
+ # @raise [Kelp::Nonexistent]
129
+ # If any field could not be found
130
+ #
131
+ def fill_in_fields(field_values, scope={})
132
+ in_scope(scope) do
133
+ field_values.each do |field, value|
134
+ check_or_select_or_fill(field, value)
135
+ end
136
+ end
108
137
  end
109
138
 
110
139
 
@@ -135,11 +164,15 @@ module Kelp
135
164
  # @param [Hash] scope
136
165
  # Scoping keywords as understood by {#in_scope}
137
166
  #
167
+ # @raise [Kelp::Unexpected]
168
+ # If the given field is not empty or nil
169
+ #
138
170
  def field_should_be_empty(field, scope={})
139
171
  in_scope(scope) do
140
172
  _field = nice_find_field(field)
141
173
  if !(_field.nil? || _field.value.nil? || _field.value == '')
142
- raise RuntimeError, "Expected field '#{field}' to be empty, but value is '#{_field.value}'"
174
+ raise Kelp::Unexpected,
175
+ "Expected field '#{field}' to be empty, but value is '#{_field.value}'"
143
176
  end
144
177
  end
145
178
  end
@@ -154,12 +187,15 @@ module Kelp
154
187
  # @param [Hash] scope
155
188
  # Scoping keywords as understood by {#in_scope}
156
189
  #
190
+ # @raise [Kelp::Unexpected]
191
+ # If the given field does not contain `value`
192
+ #
157
193
  def field_should_contain(field, value, scope={})
158
194
  in_scope(scope) do
159
195
  # TODO: Make this work equally well with any kind of field
160
196
  # (text, single-select, multi-select)
161
- field = find_field(field)
162
- field_value = (field.tag_name == 'textarea') ? field.text : field.value
197
+ element = find_field(field)
198
+ field_value = (element.tag_name == 'textarea') ? element.text : element.value
163
199
  # If field value is an Array, take the first item
164
200
  if field_value.class == Array
165
201
  field_value = field_value.first
@@ -167,17 +203,17 @@ module Kelp
167
203
  # Escape any problematic characters in the expected value
168
204
  value = Regexp.escape(value)
169
205
  # Match actual to expected
170
- if field_value.respond_to? :should
171
- field_value.should =~ /#{value}/
172
- else
173
- assert_match(/#{value}/, field_value)
206
+ if !(field_value =~ /#{value}/)
207
+ raise Kelp::Unexpected,
208
+ "Expected '#{field}' to contain '#{value}'" + \
209
+ "\nGot '#{field_value}'"
174
210
  end
175
211
  end
176
212
  end
177
213
 
178
214
 
179
215
  def field_should_not_contain(field, value, scope={})
180
- raise "Not implemented yet"
216
+ raise NotImplementedError, "Not implemented yet"
181
217
  #with_scope(parent) do
182
218
  #field = find_field(field)
183
219
  #field_value = (field.tag_name == 'textarea') ? field.text : field.value
@@ -197,6 +233,9 @@ module Kelp
197
233
  # @param [Hash] scope
198
234
  # Scoping keywords as understood by {#in_scope}
199
235
  #
236
+ # @raise [Kelp::Unexpected]
237
+ # If any field does not contain the expected value
238
+ #
200
239
  def fields_should_contain(field_values, scope={})
201
240
  in_scope(scope) do
202
241
  field_values.each do |field, value|