adva-core 0.0.9 → 0.0.13

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.
Files changed (50) hide show
  1. data/app/models/section.rb +0 -6
  2. data/app/views/admin/sites/index.html.rb +2 -2
  3. data/config/redirects.rb +2 -1
  4. data/lib/adva.rb +41 -0
  5. data/lib/adva/controller/internal_redirect.rb +2 -1
  6. data/lib/adva/core.rb +8 -0
  7. data/lib/adva/engine.rb +1 -0
  8. data/lib/adva/generators/app.rb +7 -8
  9. data/lib/adva/generators/templates/app/Gemfile +4 -4
  10. data/lib/adva/generators/templates/app/Thorfile +9 -0
  11. data/lib/adva/generators/templates/app/app_template.rb +4 -2
  12. data/lib/adva/generators/templates/engine/Gemfile.erb +15 -0
  13. data/lib/adva/testing.rb +9 -2
  14. data/lib/adva/testing/engine.rb +1 -0
  15. data/lib/adva/view/form.rb +4 -1
  16. data/lib/adva_core/version.rb +1 -1
  17. data/lib/bundler/repository.rb +117 -0
  18. data/lib/patches/inherited_resources.rb +4 -3
  19. data/lib/patches/rails/integretion_runner_respond_to.rb +1 -1
  20. data/lib/patches/rails/polymorphic_url_for.rb +3 -1
  21. data/lib/patches/rails/recognize_path_env.rb +33 -29
  22. data/lib/patches/rails/route_set_to_param.rb +19 -17
  23. data/lib/patches/rails/route_set_trailing_segment.rb +1 -1
  24. data/lib/patches/rails/sti_associations.rb +10 -4
  25. data/lib/patches/rails/translation_helper.rb +2 -1
  26. data/lib/patches/responders/flash_responder.rb +1 -0
  27. data/lib/patches/simple_form.rb +2 -2
  28. data/lib/testing/env.rb +19 -13
  29. data/lib/testing/factories.rb +5 -1
  30. data/lib/testing/paths.rb +4 -4
  31. data/lib/testing/selectors.rb +72 -0
  32. data/lib/testing/step_definitions/capybara_steps.rb +211 -0
  33. data/lib/testing/step_definitions/common_steps.rb +87 -98
  34. data/lib/testing/step_definitions/debug_steps.rb +11 -4
  35. data/lib/testing/step_definitions/email_steps.rb +195 -0
  36. data/lib/testing/step_definitions/menu_steps.rb +7 -2
  37. data/lib/testing/step_definitions/more_web_steps.rb +4 -0
  38. data/lib/testing/step_definitions/pickle_steps.rb +104 -0
  39. data/lib/testing/step_definitions/transforms.rb +10 -1
  40. data/lib/testing/support/pickle.rb +24 -0
  41. data/public/javascripts/adva-core/jquery/jquery.table_tree.js +5 -1
  42. metadata +340 -305
  43. data/lib/patches/rails/asset_expansion_multiple_registrations.rb +0 -21
  44. data/lib/patches/rails/template_resolver_caching.rb +0 -9
  45. data/lib/patches/webrat/links-data-method.rb +0 -15
  46. data/lib/patches/webrat/logger.rb +0 -14
  47. data/lib/patches/webrat/upload_file.rb +0 -23
  48. data/lib/patches/webrat/within_xpath.rb +0 -13
  49. data/lib/testing/step_definitions/webrat_steps.rb +0 -284
  50. data/lib/testing/step_definitions/within_steps.rb +0 -16
@@ -1,3 +1,11 @@
1
+ Then /^the "([^\"]*)" field should be empty$/ do |field|
2
+ if defined?(Spec::Rails::Matchers)
3
+ field_labeled(field).value.should be_blank
4
+ else
5
+ assert field_labeled(field).value.blank?
6
+ end
7
+ end
8
+
1
9
  Given 'a site' do
2
10
  @site = Factory(:site)
3
11
  end
@@ -79,35 +87,26 @@ When /^(.+) that link$/ do |step|
79
87
  end
80
88
 
81
89
  When /^I (press|click|follow) "(.*)" in the row (of the ([a-z ]+) table )?where "(.*)" is "(.*)"$/ do |action, target, _, table_id, header, content|
82
- body = Nokogiri::HTML(response.body)
83
- table_xpath = table_id.nil? ? 'table' : "table[@id='#{table_id.gsub(/ /, '_')}']"
84
- headers = body.xpath("//#{table_xpath}/descendant::th[normalize-space(text())='#{header}']/@id")
90
+ table_id = table_id.gsub(/ /, '_') unless table_id.nil?
91
+ table_xpath = table_id.nil? ? 'table' : "table[@id='#{table_id}']"
92
+ headers = page.all(:xpath, "//#{table_xpath}/descendant::th[normalize-space(text())='#{header}']")
85
93
  assert !headers.empty?, "could not find table header cell #{header.inspect}"
86
94
 
87
- header_id = headers.first.value
95
+ header_id = headers.first['id']
88
96
  cell_path = "//#{table_xpath}/descendant::td[@headers='#{header_id}']"
89
97
  content = "normalize-space(text())='#{content}'"
90
- tag_path = "#{cell_path}[#{content}]/ancestor::tr/@id"
91
- nested_tag_path = "#{cell_path}/descendant::*[#{content}]/ancestor::tr/@id"
98
+ tag_path = "#{cell_path}[#{content}]/ancestor::tr"
99
+ nested_tag_path = "#{cell_path}/descendant::*[#{content}]/ancestor::tr"
92
100
 
93
- rows = body.xpath([tag_path, nested_tag_path].join('|'))
101
+ rows = page.all(:xpath, [tag_path, nested_tag_path].join('|'))
94
102
  assert !rows.empty?, "could not find table row where a cell has the header id #{header_id.inspect} and the content #{content.inspect}"
95
103
 
96
104
  map = { 'press' => 'click_button', 'click' => 'click_link' }
97
- within("##{rows.first.value}") { map[action] ? send(map[action], target) : When(%(I #{action} "#{target}")) }
98
- end
99
-
100
- When /^I order the (.*)s list by "([^"]*)"$/ do |model, order|
101
- When %(I select "#{order}" from "#{model}s_order")
102
- select = Webrat::Locators::FieldLocator.new(webrat, webrat.dom, "#{model}s_order", Webrat::SelectField).locate!
103
- select.send(:form).submit
104
- end
105
-
106
- When /^I visit the url from the email to (.*)$/ do |to|
107
- email = ::ActionMailer::Base.deliveries.detect { |email| email.to.include?(to) }
108
- assert email, "email to #{to} could not be found"
109
- url = email.body.to_s =~ %r((http://[^\s"]+)) && $1
110
- visit(url)
105
+ if table_id.nil?
106
+ within("##{rows.first['id']}") { map[action] ? send(map[action], target) : When(%(I #{action} "#{target}")) }
107
+ else
108
+ within("table##{table_id} ##{rows.first['id']}") { map[action] ? send(map[action], target) : When(%(I #{action} "#{target}")) }
109
+ end
111
110
  end
112
111
 
113
112
  # Examples:
@@ -115,25 +114,24 @@ end
115
114
  # I should not see a product row where "Name" is "Apple Powerbook"
116
115
  # I should see a row in the products table where "Name" is "Apple Powerbook"
117
116
  Then /^I should (not )?see a ([a-z ]+ )?row (?:of the ([a-z ]+) table )?where "(.*)" is "(.*)"$/ do |optional_not, row_classes, table_id, header, cell_content|
118
- body = Nokogiri::HTML(response.body)
119
- table_xpath = table_id.nil? ? 'table' : "table[@id='#{table_id.gsub(/ /, '_')}']"
120
- table_header_cells = body.xpath("//#{table_xpath}/descendant::th[normalize-space(text())='#{header}']/@id")
117
+ table_xpath = table_id.nil? ? 'table' : "table[@id='#{table_id.gsub(/ /, '_')}' or @id='#{table_id.gsub(/ /, '-')}']"
118
+ table_header_cells = page.all(:xpath, "//#{table_xpath}/descendant::th[normalize-space(text())='#{header}']")
121
119
 
122
120
  unless optional_not.present?
123
121
  assert !table_header_cells.empty?, "could not find table header cell '#{header}'"
124
122
  end
125
- header_id = body.xpath("//#{table_xpath}/descendant::th[normalize-space(text())='#{header}']/@id").first.try(:value)
123
+ header_id = table_header_cells.first['id']
126
124
 
127
125
  class_condition = row_classes.to_s.split(' ').map do |row_class|
128
126
  "contains(concat(' ', normalize-space(@class), ' '), ' #{row_class} ')"
129
127
  end.join(' and ')
130
128
  tr_xpath = class_condition.empty? ? 'ancestor::tr' : "ancestor::tr[#{class_condition}]"
131
- xpath_result = body.xpath("//#{table_xpath}/descendant::td[@headers='#{header_id}'][normalize-space(text())='#{cell_content}']/#{tr_xpath}")
129
+ final_path = "//#{table_xpath}/descendant::td[@headers='#{header_id}'][normalize-space(text())='#{cell_content}']/#{tr_xpath}"
132
130
 
133
131
  if optional_not.present?
134
- assert xpath_result.empty?, "Expected not find a row where #{header.inspect} is #{cell_content}."
132
+ assert page.has_no_xpath?(final_path), "Expected not find a row where #{header.inspect} is #{cell_content}."
135
133
  else
136
- assert xpath_result.any?, "Expected to find at least one row where #{header.inspect} is #{cell_content}."
134
+ assert page.has_xpath?(final_path), "Expected to find at least one row where #{header.inspect} is #{cell_content}."
137
135
  end
138
136
  end
139
137
 
@@ -172,62 +170,52 @@ Then /^that (\w+) should have (\w+)s with the following attributes:$/ do |last,
172
170
  end
173
171
 
174
172
  Then /^the title should be "([^"]+)"$/ do |title|
175
- assert_select('title', title)
173
+ Then %Q{I should see "#{title}" within "title"}
176
174
  end
177
175
 
178
176
  # TODO: This is an almost duplicate step
179
177
  # Use the one with un-quoted 'thing' expression
180
178
  Then /^I should see (an?|the) "([^"]+)"$/ do |kind, thing|
181
179
  kind = { 'a' => '.', 'the' => '#' }[kind]
182
- assert_select("#{kind}#{thing}")
180
+ assert page.has_css?("#{kind}#{thing}")
183
181
  end
184
182
 
185
183
  Then /^I should see a link "([^"]+)"$/ do |link|
186
184
  @last_link = link
187
- assert_select('a', link)
185
+ assert page.has_css?('a', :text => link)
188
186
  end
189
187
 
190
188
  Then /^I should not see any ([a-z_ ]+)$/ do |type|
191
- assert_select(".#{type.gsub(' ', '_').singularize}", :count => 0)
189
+ assert page.has_no_css?(".#{type.gsub(' ', '_').singularize}")
192
190
  end
193
191
 
192
+ # FIXME: this step and the ones above do not deal with use perception
193
+ # for example: "I should see a fn0rd" looks nice, but users cannot see elements, only text
194
194
  Then /^I should see an? (\w+)$/ do |type|
195
- assert_select(".#{type}")
195
+ assert page.has_css?(".#{type}")
196
196
  end
197
197
 
198
198
  Then /^I should see a "([^"]*)" select box with the following options:$/ do |name, options|
199
- select = Webrat::Locators::FieldLocator.new(webrat, webrat.dom, 'products_order', Webrat::SelectField).locate!
200
- actual = select.options.map(&:inner_text).uniq
199
+ field = find_field(name)
200
+ actual = field.all(:css, 'option').map {|o| o.text }
201
201
  expected = options.raw.flatten[1..-1] # ignores the first row
202
202
  assert_equal expected, actual
203
203
  end
204
204
 
205
- Then /^I should see an? (\w+) (?:titled|named) "([^"]+)"$/ do |type, text|
206
- assert_select(".#{type} h2", text)
205
+ Then /^I should see an? (\w+) (?:titled|named) "([^"]+)"$/ do |thingy, text|
206
+ Then %Q~I should see "#{text}" within ".#{thingy} h2"~
207
207
  end
208
208
 
209
- Then /^I should see an? (\w+) containing "([^"]+)"$/ do |type, text|
210
- assert_select(".#{type}", /#{text}/)
211
- end
212
-
213
- # TODO: the sinature of this step should really be:
214
- # I should see 'foo' within 'bar'
215
- # However, the generic "within 'bar'" meta step uses 'within' which doesn't currently work with assertions
216
- # only with navigation ('click', 'press')
217
- Then /^the ([^"]+) should(?: (not))? contain "([^"]+)"$/ do |container_name, optional_negation, text|
218
- container_id = container_name.gsub(' ', '_')
219
- # 'within' doesn't currently work with assertions, so we need to resort to xpath
220
- # within('#' + container_id) { assert_contain text }
221
- assert(parsed_html.xpath("//*[@id=\"#{container_id}\"]").any?, "Could not find the #{container_name}")
222
- assert(parsed_html.xpath("//*[@id=\"#{container_id}\"]/descendant::*[contains(normalize-space(text()), \"#{text}\")]").send(optional_negation ? :'none?' : :'any?'), "Could not see '#{text}' in the #{container_name}")
209
+ Then /^I should see an? (\w+) containing "([^"]+)"$/ do |thingy, text|
210
+ Then %Q~I should see "#{text}" within ".#{thingy}"~
223
211
  end
224
212
 
225
213
  Then /^I should see an? (\w+) list$/ do |type|
226
- assert_select(".#{type}.list")
214
+ assert page.has_css?(".#{type}.list")
227
215
  end
228
216
 
229
217
  Then /^I should see a list of (\w+)$/ do |type|
230
- assert_select(".#{type}.list")
218
+ assert page.has_css?(".#{type}.list")
231
219
  end
232
220
 
233
221
  Then /^the (.*) list should display (.*)s in the following order:$/ do |list, model, values|
@@ -244,32 +232,35 @@ Then /^I should see an? ([a-z ]+) form$/ do |type|
244
232
  tokens = type.split(' ')
245
233
  types = [tokens.join('_'), tokens.reverse.join('_')]
246
234
  selectors = types.map { |type| "form.#{type}, form##{type}" }
247
- assert_select(selectors.join(', '))
235
+ assert page.has_css?(selectors.join(', '))
248
236
  end
249
237
 
250
238
  Then /^I should not see an? ([a-z ]+) form$/ do |type|
251
239
  type = type.gsub(' ', '_') #.gsub(/edit_/, '')
252
- assert_select("form.#{type}, form##{type}", :count => 0)
240
+ assert page.has_no_css?("form.#{type}, form##{type}")
253
241
  end
254
242
 
255
- Then /^I should see an? ([a-z ]+) form with the following values:$/ do |type, table|
256
- type = type.gsub(' ', '_') #.gsub(/edit_/, '')
257
- assert_select("form.#{type}, form##{type}") do |form|
243
+ Then /^I should see an? ([a-z ]+) form with the following values:$/ do |kind, table|
244
+ with_scope("#{kind} form") do
258
245
  table.rows_hash.each do |name, value|
259
- assert_equal value, webrat.current_scope.field_labeled(name).value
246
+ Then %Q~the "#{name}" field should contain "#{value}"~
260
247
  end
261
248
  end
262
249
  end
263
250
 
264
- Then /^I should see a "(.+)" table with the following entries:$/ do |table_id, expected_table|
265
- actual_table = table(tableish("table##{table_id} tr", 'td,th'))
266
- begin
267
- diff_table = expected_table.dup
268
- diff_table.diff!(actual_table.dup)
269
- rescue
270
- puts tables_differ_message(actual_table, expected_table, diff_table)
271
- raise
251
+ Then /^I should see a "(.+)" table with the following entries:$/ do |dom_id, expected|
252
+ actual = table(tableish("table##{dom_id} tr", 'th,td'))
253
+ expected.diff! actual
254
+ end
255
+
256
+ Then /^I should see a "(.+)" list with the following entries:$/ do |dom_id, expected|
257
+ value_selector = expected.column_names.map {|n| '.' + n.downcase.gsub(/[ _]/, '-') }.join(',')
258
+ list = tableish("ul##{dom_id} li", value_selector)
259
+ actual = table( [expected.column_names] + list )
260
+ actual.column_names.each do |col|
261
+ actual.map_column!(col) { |text| text.sub(/\n/,' ') }
272
262
  end
263
+ expected.diff! actual
273
264
  end
274
265
 
275
266
  Then /^I should see a "(.+)" table with the following entries in no particular order:$/ do |table_id, expected_table|
@@ -286,7 +277,7 @@ def tables_differ_message(actual, expected, diff = nil)
286
277
  end
287
278
 
288
279
  Then /^I should see the "([^"]+)" page$/ do |name|
289
- assert_select('h2', name)
280
+ Then %Q~I should see "#{name}" within "h2"~
290
281
  end
291
282
 
292
283
  Then(/(?:\$|eval) (.*)$/) do |code|
@@ -302,13 +293,8 @@ Then /^I should not see a flash (error|notice) "(.+)"$/ do |message_type, messag
302
293
  end
303
294
 
304
295
  Then /^I should (see|not see) the error "([^"]+)" for attribute "([^"]+)" of the "([^"]+)"$/ do |should_see, error_msg, attribute, model|
305
- if should_see == 'see' # ugh ...
306
- assert_select "*[id*=#{model.downcase.gsub(' ', '_')}_#{attribute.downcase.gsub(' ', '_')}] + span.error",
307
- :text => error_msg
308
- elsif should_see == 'not see'
309
- assert_select "*[id*=#{model.downcase.gsub(' ', '_')}_#{attribute.downcase.gsub(' ', '_')}] + span.error",
310
- :text => error_msg, :count => 0
311
- end
296
+ selector = "*[id*=#{model.downcase.gsub(' ', '_')}_#{attribute.downcase.gsub(' ', '_')}] + span.error"
297
+ Then %Q~I should #{should_see} "#{error_msg}" within "#{selector}"~
312
298
  end
313
299
 
314
300
  Then /^the following emails should have been sent:$/ do |expected_emails|
@@ -322,34 +308,27 @@ Then /^no emails should have been sent$/ do
322
308
  end
323
309
 
324
310
  Then /^"([^"]*)" should be filled in with "([^"]*)"$/ do |field, value|
325
- field = webrat.field_labeled(field)
326
- assert_equal value, field.value
311
+ field = find_field(field)
312
+ field_value = (field.tag_name == 'textarea') ? field.text : field.value
313
+ assert_equal(value, field_value)
327
314
  end
328
315
 
329
- Then /^"([^"]*)" should be checked$/ do |label|
330
- field = webrat.field_labeled(label)
331
- assert field.checked?, "expected the checkbox #{label} to be checked"
332
- end
333
-
334
- Then /^"([^"]*)" should not be checked$/ do |label|
335
- field = webrat.field_labeled(label)
336
- assert !field.checked?, "expected the checkbox #{label} not to be checked"
316
+ Then /^"([^"]*)" should (be|not be) checked$/ do |label, be_or_not_to_be|
317
+ Then %Q{the "#{label}" checkbox should #{be_or_not_to_be} checked}
337
318
  end
338
319
 
339
320
  Then /^"([^"]*)" should be selected as "([^"]*)"$/ do |value, label|
340
- select = webrat.field_labeled(label)
341
- assert select, "count not find a select field labeled #{label}"
342
- selected = select.element.xpath(".//option[@selected = 'selected']").first
343
- assert selected, "could not find a selected option"
321
+ select_box = find_field(label)
322
+ selected = select_box.find(:xpath, ".//option[@selected = 'selected']")
344
323
  assert_equal value, selected.text
345
324
  end
346
325
 
347
326
  Then /^I should see "([^"]*)" formatted as a "([^"]*)" tag$/ do |value, tag|
348
- assert_select(tag, value)
327
+ Then %Q~I should see "#{value}" within "#{tag}"~
349
328
  end
350
329
 
351
- Then(/^I should see (\d+|no|one|two|three) ([a-z ]+?)(?: in the ([a-z ]+))?$/) do |amount, item_class, container_id|
352
- container_selector = container_id ? '#' + container_id.gsub(' ', '_') : nil
330
+ # TODO remove the manual (?: in..) to leverage cucumber selectors
331
+ Then(/^I should see (\d+|no|one|two|three) ([-a-z ]+?)(?: in (the [a-z -]+))?$/) do |amount, item_class, container|
353
332
  amount = case amount
354
333
  when 'no' then 0
355
334
  when 'one' then 1
@@ -358,13 +337,23 @@ Then(/^I should see (\d+|no|one|two|three) ([a-z ]+?)(?: in the ([a-z ]+))?$/) d
358
337
  else amount.to_i
359
338
  end
360
339
  item_selector = '.' + item_class.gsub(' ', '_').singularize
361
- # assertions do not work with 'within' yet, so we need to resort to cancatenating selectors:
362
- # container_selector ? within(container_selector) { assert_select(item_selector) } : assert_select(item_selector)
363
- if container_selector
364
- assert_select container_selector
365
- assert_select [container_selector, item_selector].join(' '), amount
340
+ with_scope container do
341
+ assert page.has_css?(item_selector,:count => amount)
342
+ end
343
+ end
344
+
345
+ Then /^the "([^"]*)" radio button should (be|not be) checked$/ do |label, be_or_not_to_be|
346
+ Then %Q~the "#{label}" checkbox should #{be_or_not_to_be} checked~
347
+ end
348
+
349
+ Then /^(?:|I )should not be on (.+)$/ do |page_name|
350
+ current_path = URI.parse(current_url).path
351
+ if current_path.respond_to? :should
352
+ current_path.should_not == path_to(page_name)
366
353
  else
367
- assert_select item_selector, amount
354
+ assert_not_equal path_to(page_name), current_path
368
355
  end
369
356
  end
370
357
 
358
+
359
+
@@ -12,11 +12,18 @@ Then 'debug' do
12
12
  true
13
13
  end
14
14
 
15
- Then /^show me the page$/ do
16
- save_and_open_page
15
+ Then /^(?:|I )output the page$/ do
16
+ puts page.body
17
17
  end
18
18
 
19
- Then /^(?:|I )output the page$/ do
20
- puts response.body
19
+ When /^I pause$/ do
20
+ STDERR.puts "pausing - press enter to continue"
21
+ STDIN.gets
21
22
  end
22
23
 
24
+ Then /^dump the table "([^"]*)"$/ do |table_name|
25
+ filename = Rails.root.join('tmp').join("dump-#{table_name}.csv").expand_path
26
+ sql = "COPY #{table_name} TO '#{filename}' WITH CSV HEADER"
27
+
28
+ ActiveRecord::Base.connection.execute sql
29
+ end
@@ -0,0 +1,195 @@
1
+ require 'email_spec/cucumber'
2
+ # Commonly used email steps
3
+ #
4
+ # To add your own steps make a custom_email_steps.rb
5
+ # The provided methods are:
6
+ #
7
+ # last_email_address
8
+ # reset_mailer
9
+ # open_last_email
10
+ # visit_in_email
11
+ # unread_emails_for
12
+ # mailbox_for
13
+ # current_email
14
+ # open_email
15
+ # read_emails_for
16
+ # find_email
17
+ #
18
+ # General form for email scenarios are:
19
+ # - clear the email queue (done automatically by email_spec)
20
+ # - execute steps that sends an email
21
+ # - check the user received an/no/[0-9] emails
22
+ # - open the email
23
+ # - inspect the email contents
24
+ # - interact with the email (e.g. click links)
25
+ #
26
+ # The Cucumber steps below are setup in this order.
27
+
28
+ module EmailHelpers
29
+ def current_email_address
30
+ # Replace with your a way to find your current email. e.g @current_user.email
31
+ # last_email_address will return the last email address used by email spec to find an email.
32
+ # Note that last_email_address will be reset after each Scenario.
33
+ last_email_address || "example@example.com"
34
+ end
35
+ end
36
+
37
+ World(EmailHelpers)
38
+
39
+ #
40
+ # Reset the e-mail queue within a scenario.
41
+ # This is done automatically before each scenario.
42
+ #
43
+
44
+ Given /^(?:a clear email queue|no emails have been sent)$/ do
45
+ reset_mailer
46
+ end
47
+
48
+ #
49
+ # Check how many emails have been sent/received
50
+ #
51
+
52
+ Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails?$/ do |address, amount|
53
+ unread_emails_for(address).size.should == parse_email_count(amount)
54
+ end
55
+
56
+ Then /^(?:I|they|"([^"]*?)") should have (an|no|\d+) emails?$/ do |address, amount|
57
+ mailbox_for(address).size.should == parse_email_count(amount)
58
+ end
59
+
60
+ Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails? with subject "([^"]*?)"$/ do |address, amount, subject|
61
+ unread_emails_for(address).select { |m| m.subject =~ Regexp.new(subject) }.size.should == parse_email_count(amount)
62
+ end
63
+
64
+ Then /^(?:I|they|"([^"]*?)") should receive an email with the following body:$/ do |address, expected_body|
65
+ open_email(address, :with_text => expected_body)
66
+ end
67
+
68
+ #
69
+ # Accessing emails
70
+ #
71
+
72
+ # Opens the most recently received email
73
+ When /^(?:I|they|"([^"]*?)") opens? the email$/ do |address|
74
+ open_email(address)
75
+ end
76
+
77
+ When /^(?:I|they|"([^"]*?)") opens? the email with subject "([^"]*?)"$/ do |address, subject|
78
+ open_email(address, :with_subject => subject)
79
+ end
80
+
81
+ When /^(?:I|they|"([^"]*?)") opens? the email with text "([^"]*?)"$/ do |address, text|
82
+ open_email(address, :with_text => text)
83
+ end
84
+
85
+ #
86
+ # Inspect the Email Contents
87
+ #
88
+
89
+ Then /^(?:I|they) should see "([^"]*?)" in the email subject$/ do |text|
90
+ current_email.should have_subject(text)
91
+ end
92
+
93
+ Then /^(?:I|they) should see \/([^"]*?)\/ in the email subject$/ do |text|
94
+ current_email.should have_subject(Regexp.new(text))
95
+ end
96
+
97
+ Then /^(?:I|they) should see "([^"]*?)" in the email body$/ do |text|
98
+ current_email.default_part_body.to_s.should include(text)
99
+ end
100
+
101
+ Then /^(?:I|they) should see \/([^"]*?)\/ in the email body$/ do |text|
102
+ current_email.default_part_body.to_s.should =~ Regexp.new(text)
103
+ end
104
+
105
+ Then /^(?:I|they) should see the email delivered from "([^"]*?)"$/ do |text|
106
+ current_email.should be_delivered_from(text)
107
+ end
108
+
109
+ Then /^(?:I|they) should see "([^\"]*)" in the email "([^"]*?)" header$/ do |text, name|
110
+ current_email.should have_header(name, text)
111
+ end
112
+
113
+ Then /^(?:I|they) should see \/([^\"]*)\/ in the email "([^"]*?)" header$/ do |text, name|
114
+ current_email.should have_header(name, Regexp.new(text))
115
+ end
116
+
117
+ Then /^I should see it is a multi\-part email$/ do
118
+ current_email.should be_multipart
119
+ end
120
+
121
+ Then /^(?:I|they) should see "([^"]*?)" in the email html part body$/ do |text|
122
+ current_email.html_part.body.to_s.should include(text)
123
+ end
124
+
125
+ Then /^(?:I|they) should see "([^"]*?)" in the email text part body$/ do |text|
126
+ current_email.text_part.body.to_s.should include(text)
127
+ end
128
+
129
+ #
130
+ # Inspect the Email Attachments
131
+ #
132
+
133
+ Then /^(?:I|they) should see (an|no|\d+) attachments? with the email$/ do |amount|
134
+ current_email_attachments.size.should == parse_email_count(amount)
135
+ end
136
+
137
+ Then /^there should be (an|no|\d+) attachments? named "([^"]*?)"$/ do |amount, filename|
138
+ current_email_attachments.select { |a| a.filename == filename }.size.should == parse_email_count(amount)
139
+ end
140
+
141
+ Then /^attachment (\d+) should be named "([^"]*?)"$/ do |index, filename|
142
+ current_email_attachments[(index.to_i - 1)].filename.should == filename
143
+ end
144
+
145
+ Then /^there should be (an|no|\d+) attachments? of type "([^"]*?)"$/ do |amount, content_type|
146
+ current_email_attachments.select { |a| a.content_type.include?(content_type) }.size.should == parse_email_count(amount)
147
+ end
148
+
149
+ Then /^attachment (\d+) should be of type "([^"]*?)"$/ do |index, content_type|
150
+ current_email_attachments[(index.to_i - 1)].content_type.should include(content_type)
151
+ end
152
+
153
+ Then /^all attachments should not be blank$/ do
154
+ current_email_attachments.each do |attachment|
155
+ attachment.read.size.should_not == 0
156
+ end
157
+ end
158
+
159
+ Then /^show me a list of email attachments$/ do
160
+ EmailSpec::EmailViewer::save_and_open_email_attachments_list(current_email)
161
+ end
162
+
163
+ #
164
+ # Interact with Email Contents
165
+ #
166
+
167
+ When /^(?:I|they) follow "([^"]*?)" in the email$/ do |link|
168
+ visit_in_email(link)
169
+ end
170
+
171
+ When /^(?:I|they) click the first link in the email$/ do
172
+ click_first_link_in_email
173
+ end
174
+
175
+ #
176
+ # Debugging
177
+ # These only work with Rails and OSx ATM since EmailViewer uses RAILS_ROOT and OSx's 'open' command.
178
+ # Patches accepted. ;)
179
+ #
180
+
181
+ Then /^save and open current email$/ do
182
+ EmailSpec::EmailViewer::save_and_open_email(current_email)
183
+ end
184
+
185
+ Then /^save and open all text emails$/ do
186
+ EmailSpec::EmailViewer::save_and_open_all_text_emails
187
+ end
188
+
189
+ Then /^save and open all html emails$/ do
190
+ EmailSpec::EmailViewer::save_and_open_all_html_emails
191
+ end
192
+
193
+ Then /^save and open all raw emails$/ do
194
+ EmailSpec::EmailViewer::save_and_open_all_raw_emails
195
+ end