spreewald 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in spreewald.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Tobias Kraze
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # Spreewald
2
+
3
+ Spreewald is a collection of useful steps for cucumber. Feel free to fork.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'spreewald'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install spreewald
18
+
19
+ ## Usage
20
+
21
+ Steps are grouped into a number of categories. You can pick and choose single categories by putting something like
22
+ require 'spreewald/email_steps'
23
+ into your `support/env.rb`
24
+
25
+ Alternatively, you can require everything by doing
26
+ require 'spreewald/all_steps'
27
+
28
+ ## Steps
29
+
30
+ For a complete list of steps you have to take a look at the step definitions themselves. This is just a rough overview.
31
+
32
+ ### [development_steps](/makandra/spreewald/blob/master/lib/spreewald/development_steps.rb)
33
+
34
+ Some development steps. Supports
35
+
36
+ * `Then debugger`
37
+ * `Then it should work` (marks step as pending)
38
+ * `@slow-motion` (waits 2 seconds after each step)
39
+ * `@single-step` (waits for keyboard input after each step)
40
+
41
+
42
+ ### [email_steps](/makandra/spreewald/blob/master/lib/spreewald/email_steps.rb)
43
+
44
+ Check for the existance of an email with
45
+
46
+ Then an email should have been sent with:
47
+ """
48
+ From: max.mustermann@example.com
49
+ To: john.doe@example.com
50
+ Subject: Unter anderem der Betreff kann auch "Anführungszeichen" enthalten
51
+ Body: ...
52
+ Attachments: ...
53
+ """
54
+
55
+ You can obviously skip lines.
56
+
57
+ After you have used that step, you can also check for content with
58
+
59
+ And that mail should have the following lines in the body:
60
+ """
61
+ Jede dieser Text-Zeilen
62
+ muss irgendwo im Body vorhanden sein
63
+ """
64
+
65
+ ### [table_steps](/makandra/spreewald/blob/master/lib/spreewald/table_steps.rb)
66
+
67
+ Check the content of tables in your HTML.
68
+
69
+ See [this article](https://makandracards.com/makandra/763-cucumber-step-to-match-table-rows-with-capybara) for details.
70
+
71
+
72
+ ### [timecop_steps](/makandra/spreewald/blob/master/lib/spreewald/timecop_steps.rb)
73
+
74
+ Steps to travel through time using [Timecop](https://github.com/jtrupiano/timecop).
75
+
76
+ See [this article](https://makandracards.com/makandra/1222-useful-cucumber-steps-to-travel-through-time-with-timecop) for details.
77
+
78
+ ### [web_steps](/makandra/spreewald/blob/master/lib/spreewald/web_steps.rb)
79
+
80
+ Most of cucumber-rails' original websteps plus some of our own.
81
+
82
+ Note that cucumber-rails deprecated those a while ago (you can see the original deprecation notice at the top of [our web_steps](/makandra/spreewald/blob/master/lib/spreewald/web_steps.rb)). Make up your own mind whether you want to use them or not.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
data/examples/paths.rb ADDED
@@ -0,0 +1,30 @@
1
+ # Put this into features/support and require it in your env.rb
2
+ #
3
+ module NavigationHelpers
4
+ # Maps a name to a path. Used by the
5
+ #
6
+ # When /^I go to (.+)$/ do |page_name|
7
+ #
8
+ # step definition in web_steps.rb
9
+ #
10
+ def path_to(page_name)
11
+ case page_name
12
+
13
+ when /^the home\s?page$/
14
+ root_path
15
+
16
+ else
17
+ begin
18
+ page_name =~ /^the (.*) page$/
19
+ path_components = $1.split(/\s+/)
20
+ self.send(path_components.push('path').join('_').to_sym)
21
+ rescue NoMethodError, ArgumentError
22
+ raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
23
+ "Now, go and add a mapping in #{__FILE__}"
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ World(NavigationHelpers)
30
+
@@ -0,0 +1,41 @@
1
+ # Put this into features/support and require it in your env.rb
2
+ module HtmlSelectorsHelpers
3
+ # Maps a name to a selector. Used primarily by the
4
+ #
5
+ # When /^(.+) within (.+)$/ do |step, scope|
6
+ #
7
+ # step definitions in web_steps.rb
8
+ #
9
+ def selector_for(locator)
10
+ case locator
11
+
12
+ when "the page"
13
+ "html > body"
14
+
15
+ # Add more mappings here.
16
+ # Here is an example that pulls values out of the Regexp:
17
+ #
18
+ # when /^the (notice|error|info) flash$/
19
+ # ".flash.#{$1}"
20
+
21
+ # You can also return an array to use a different selector
22
+ # type, like:
23
+ #
24
+ # when /the header/
25
+ # [:xpath, "//header"]
26
+
27
+ # This allows you to provide a quoted selector as the scope
28
+ # for "within" steps as was previously the default for the
29
+ # web steps:
30
+ when /^"(.+)"$/
31
+ $1
32
+
33
+ else
34
+ raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
35
+ "Now, go and add a mapping in #{__FILE__}"
36
+ end
37
+ end
38
+ end
39
+
40
+ World(HtmlSelectorsHelpers)
41
+
data/lib/spreewald.rb ADDED
@@ -0,0 +1,2 @@
1
+ require "spreewald_support/version"
2
+ require "spreewald_support/github"
@@ -0,0 +1,6 @@
1
+ Dir[File.join(File.dirname(__FILE__), '*_steps.rb')].each do |f|
2
+ name = File.basename(f, '.rb')
3
+ unless name == 'all_steps'
4
+ require "spreewald/#{name}"
5
+ end
6
+ end
@@ -0,0 +1,16 @@
1
+ Then /^it should work$/ do
2
+ pending
3
+ end
4
+
5
+ Then /^debugger$/ do
6
+ debugger
7
+ end
8
+
9
+ AfterStep('@slow-motion') do
10
+ sleep 2
11
+ end
12
+
13
+ AfterStep('@single-step') do
14
+ print "Single Stepping. Hit enter to continue"
15
+ STDIN.getc
16
+ end
@@ -0,0 +1,64 @@
1
+ require 'spreewald_support/mail_finder'
2
+
3
+ Before do
4
+ ActionMailer::Base.deliveries.clear
5
+ end
6
+
7
+ Then /^(an|no) e?mail should have been sent((?: |and|with|from "[^"]+"|to "[^"]+"|the subject "[^"]+"|the body "[^"]+"|the attachments "[^"]+")+)$/ do |mode, query|
8
+ conditions = {}
9
+ conditions[:to] = $1 if query =~ /to "([^"]+)"/
10
+ conditions[:cc] = $1 if query =~ / cc "([^"]+)"/
11
+ conditions[:bcc] = $1 if query =~ /bcc "([^"]+)"/
12
+ conditions[:from] = $1 if query =~ /from "([^"]+)"/
13
+ conditions[:subject] = $1 if query =~ /the subject "([^"]+)"/
14
+ conditions[:body] = $1 if query =~ /the body "([^"]+)"/
15
+ conditions[:attachments] = $1 if query =~ /the attachments "([^"]+)"/
16
+ @mail = MailFinder.find(conditions)
17
+ expectation = mode == 'no' ? 'should_not' : 'should'
18
+ @mail.send(expectation, be_present)
19
+ end
20
+
21
+ When /^I follow the (first|second|third)? ?link in the e?mail$/ do |index_in_words|
22
+ mail = @mail || ActionMailer::Base.deliveries.last
23
+ index = { nil => 0, 'first' => 0, 'second' => 1, 'third' => 2 }[index_in_words]
24
+ visit mail.body.scan(Patterns::URL)[index][2]
25
+ end
26
+
27
+ Then /^no e?mail should have been sent$/ do
28
+ ActionMailer::Base.deliveries.should be_empty
29
+ end
30
+
31
+ Then /^I should see "([^\"]*)" in the e?mail$/ do |text|
32
+ ActionMailer::Base.deliveries.last.body.should include(text)
33
+ end
34
+
35
+ Then /^show me the e?mails$/ do
36
+ ActionMailer::Base.deliveries.each do |mail|
37
+ p [mail.from, mail.to, mail.subject]
38
+ end
39
+ end
40
+
41
+ Then /^(an|no) e?mail should have been sent with:$/ do |mode, raw_data|
42
+ raw_data.strip!
43
+ conditions = {}.tap do |hash|
44
+ raw_data.split("\n").each do |row|
45
+ if row.match(/^[a-z]+: /i)
46
+ key, value = row.split(": ", 2)
47
+ hash[key.downcase.to_sym] = value
48
+ end
49
+ end
50
+ end
51
+ @mail = MailFinder.find(conditions)
52
+ expectation = mode == 'no' ? 'should_not' : 'should'
53
+ @mail.send(expectation, be_present)
54
+ end
55
+
56
+ Then /^that e?mail should have the following lines in the body:$/ do |body|
57
+ body.each do |line|
58
+ @mail.body.should include(line.strip)
59
+ end
60
+ end
61
+
62
+ Then /^that e?mail should have the following body:$/ do |body|
63
+ @mail.body.should include(body.strip)
64
+ end
@@ -0,0 +1,102 @@
1
+ require 'spreewald_support/tolerance_for_selenium_sync_issues'
2
+
3
+ module TableStepsHelper
4
+ module ArrayMethods
5
+
6
+ def find_row(expected_row)
7
+ find_index do |row|
8
+ expected_row.all? do |expected_column|
9
+ first_column = row.find_index do |column|
10
+ content = normalize_content(column.content)
11
+ expected_content = normalize_content(expected_column)
12
+ matching_parts = expected_content.split('*', -1).collect { |part| Regexp.escape(part) }
13
+ matching_expression = /\A#{matching_parts.join(".*")}\z/
14
+ content =~ matching_expression
15
+ end
16
+ if first_column.nil?
17
+ false
18
+ else
19
+ row = row[(first_column + 1)..-1]
20
+ true
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ def normalize_content(content)
27
+ nbsp = 0xC2.chr + 0xA0.chr
28
+ content.gsub(/[\r\n\t]+/, ' ').gsub(nbsp, ' ').gsub(/ {2,}/, ' ').strip
29
+ end
30
+
31
+ end
32
+
33
+ rspec = defined?(RSpec) ? RSpec : Spec
34
+
35
+ rspec::Matchers.define :contain_table do |*args|
36
+ match do |tables|
37
+ @last_unmatched_row = nil
38
+ @best_rows_matched = -1
39
+ expected_table, unordered = args
40
+ tables.any? do |table|
41
+ rows_matched = 0
42
+ expected_table.all? do |expected_row|
43
+ if @best_rows_matched < rows_matched
44
+ @last_unmatched_row = expected_row
45
+ @best_rows_matched = rows_matched
46
+ end
47
+ table.extend ArrayMethods
48
+ first_row = table.find_row(expected_row)
49
+ if first_row.nil?
50
+ false
51
+ else
52
+ rows_matched += 1
53
+ if unordered
54
+ table.delete_at(first_row)
55
+ else
56
+ table = table[(first_row + 1)..-1]
57
+ end
58
+ true
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ failure_message_for_should do
65
+ "Could not find the following row: #{@last_unmatched_row.inspect}"
66
+ end
67
+
68
+ failure_message_for_should_not do
69
+ "Found the complete table: #{args.first.inspect}."
70
+ end
71
+ end
72
+
73
+ def parse_table(table)
74
+ if table.is_a?(String)
75
+ # multiline string. split it assuming a format like cucumber tables have.
76
+ table.split(/\n/).collect do |line|
77
+ line.sub!(/^\|/, '')
78
+ line.sub!(/\|$/, '')
79
+ line.split(/\s*\|\s*/)
80
+ end
81
+ else
82
+ # vanilla cucumber table.
83
+ table.raw
84
+ end
85
+ end
86
+ end
87
+ World(TableStepsHelper)
88
+
89
+
90
+ Then /^I should( not)? see a table with the following rows( in any order)?:?$/ do |negate, unordered, expected_table|
91
+ patiently do
92
+ document = Nokogiri::HTML(page.body)
93
+ tables = document.xpath('//table').collect { |table| table.xpath('.//tr').collect { |row| row.xpath('.//th|td') } }
94
+ parsed_table = parse_table(expected_table)
95
+
96
+ if negate
97
+ tables.should_not contain_table(parsed_table, unordered)
98
+ else
99
+ tables.should contain_table(parsed_table, unordered)
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,28 @@
1
+ if defined?(Timecop)
2
+
3
+ When /^the (?:date|time) is "(\d{4}-\d{2}-\d{2}(?: \d{1,2}:\d{2})?)"$/ do |time|
4
+ Timecop.travel Time.parse(time)
5
+ end
6
+
7
+ When /^the time is "(\d{1,2}:\d{2})"$/ do |time|
8
+ Timecop.travel Time.parse(time) # date will be today
9
+ end
10
+
11
+ When /^it is (\d+|a|some|a few) (seconds?|minutes?|hours?|days?|weeks?|months?|years?) (later|earlier)$/ do |amount, unit, direction|
12
+ amount = case amount
13
+ when 'a'
14
+ 1
15
+ when 'some', 'a few'
16
+ 10
17
+ else
18
+ amount.to_i
19
+ end
20
+ amount = -amount if direction == 'earlier'
21
+ Timecop.travel(Time.now + amount.send(unit))
22
+ end
23
+
24
+ After do
25
+ Timecop.return
26
+ end
27
+
28
+ end
@@ -0,0 +1,334 @@
1
+ # Deprecation notice from the original web-steps:
2
+ #
3
+ # This file was generated by Cucumber-Rails and is only here to get you a head start
4
+ # These step definitions are thin wrappers around the Capybara/Webrat API that lets you
5
+ # visit pages, interact with widgets and make assertions about page content.
6
+ #
7
+ # If you use these step definitions as basis for your features you will quickly end up
8
+ # with features that are:
9
+ #
10
+ # * Hard to maintain
11
+ # * Verbose to read
12
+ #
13
+ # A much better approach is to write your own higher level step definitions, following
14
+ # the advice in the following blog posts:
15
+ #
16
+ # * http://benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories.html
17
+ # * http://dannorth.net/2011/01/31/whose-domain-is-it-anyway/
18
+ # * http://elabs.se/blog/15-you-re-cuking-it-wrong
19
+ #
20
+
21
+ require 'spreewald_support/tolerance_for_selenium_sync_issues'
22
+ require 'spreewald_support/path_selector_fallbacks'
23
+ require 'uri'
24
+ require 'cgi'
25
+
26
+ # Single-line step scoper
27
+ When /^(.*) within (.*[^:])$/ do |nested_step, parent|
28
+ with_scope(parent) { step(nested_step) }
29
+ end
30
+
31
+ # Multi-line step scoper
32
+ When /^(.*) within (.*[^:]):$/ do |nested_step, parent, table_or_string|
33
+ with_scope(parent) { step("#{nested_step}:", table_or_string) }
34
+ end
35
+
36
+ Given /^(?:|I )am on (.+)$/ do |page_name|
37
+ visit _path_to(page_name)
38
+ end
39
+
40
+ When /^(?:|I )go to (.+)$/ do |page_name|
41
+ visit _path_to(page_name)
42
+ end
43
+
44
+ When /^(?:|I )press "([^"]*)"$/ do |button|
45
+ patiently do
46
+ click_button(button)
47
+ end
48
+ end
49
+
50
+ When /^(?:|I )follow "([^"]*)"$/ do |link|
51
+ patiently do
52
+ click_link(link)
53
+ end
54
+ end
55
+
56
+ When /^(?:|I )fill in "([^"]*)" with "([^"]*)"$/ do |field, value|
57
+ patiently do
58
+ fill_in(field, :with => value)
59
+ end
60
+ end
61
+
62
+ When /^(?:|I )fill in "([^"]*)" for "([^"]*)"$/ do |value, field|
63
+ patiently do
64
+ fill_in(field, :with => value)
65
+ end
66
+ end
67
+
68
+ When /^(?:|I )select "([^"]*)" from "([^"]*)"$/ do |value, field|
69
+ patiently do
70
+ select(value, :from => field)
71
+ end
72
+ end
73
+
74
+ When /^(?:|I )check "([^"]*)"$/ do |field|
75
+ patiently do
76
+ check(field)
77
+ end
78
+ end
79
+
80
+ When /^(?:|I )uncheck "([^"]*)"$/ do |field|
81
+ patiently do
82
+ uncheck(field)
83
+ end
84
+ end
85
+
86
+ When /^(?:|I )choose "([^"]*)"$/ do |field|
87
+ patiently do
88
+ choose(field)
89
+ end
90
+ end
91
+
92
+ When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"$/ do |path, field|
93
+ patiently do
94
+ attach_file(field, File.expand_path(path))
95
+ end
96
+ end
97
+
98
+ Then /^(?:|I )should see "([^"]*)"$/ do |text|
99
+ patiently do
100
+ page.should have_content(text)
101
+ end
102
+ end
103
+
104
+ Then /^(?:|I )should see \/([^\/]*)\/$/ do |regexp|
105
+ regexp = Regexp.new(regexp)
106
+ patiently do
107
+ page.should have_xpath('//*', :text => regexp)
108
+ end
109
+ end
110
+
111
+ Then /^(?:|I )should not see "([^"]*)"$/ do |text|
112
+ patiently do
113
+ page.should have_no_content(text)
114
+ end
115
+ end
116
+
117
+ Then /^(?:|I )should not see \/([^\/]*)\/$/ do |regexp|
118
+ patiently do
119
+ regexp = Regexp.new(regexp)
120
+ page.should have_no_xpath('//*', :text => regexp)
121
+ end
122
+ end
123
+
124
+ Then /^the "([^"]*)" field(?: within (.*))? should contain "([^"]*)"$/ do |field, parent, value|
125
+ patiently do
126
+ with_scope(parent) do
127
+ field = find_field(field)
128
+ field_value = (field.tag_name == 'textarea') ? field.text : field.value
129
+ field_value.should =~ /#{value}/
130
+ end
131
+ end
132
+ end
133
+
134
+ Then /^the "([^"]*)" field(?: within (.*))? should not contain "([^"]*)"$/ do |field, parent, value|
135
+ patiently do
136
+ with_scope(parent) do
137
+ field = find_field(field)
138
+ field_value = (field.tag_name == 'textarea') ? field.text : field.value
139
+ field_value.should_not =~ /#{value}/
140
+ end
141
+ end
142
+ end
143
+
144
+ Then /^the "([^"]*)" field should have the error "([^"]*)"$/ do |field, error_message|
145
+ patiently do
146
+ element = find_field(field)
147
+ classes = element.find(:xpath, '..')[:class].split(' ')
148
+
149
+ form_for_input = element.find(:xpath, 'ancestor::form[1]')
150
+ using_formtastic = form_for_input[:class].include?('formtastic')
151
+ error_class = using_formtastic ? 'error' : 'field_with_errors'
152
+
153
+ classes.should include(error_class)
154
+
155
+ if using_formtastic
156
+ error_paragraph = element.find(:xpath, '../*[@class="inline-errors"][1]')
157
+ error_paragraph.should have_content(error_message)
158
+ else
159
+ page.should have_content("#{field.titlecase} #{error_message}")
160
+ end
161
+ end
162
+ end
163
+
164
+ Then /^the "([^"]*)" field should have no error$/ do |field|
165
+ patiently do
166
+ element = find_field(field)
167
+ classes = element.find(:xpath, '..')[:class].split(' ')
168
+ classes.should_not include('field_with_errors')
169
+ classes.should_not include('error')
170
+ end
171
+ end
172
+
173
+ Then /^the "([^"]*)" checkbox(?: within (.*))? should be checked$/ do |label, parent|
174
+ patiently do
175
+ with_scope(parent) do
176
+ field_checked = find_field(label)['checked']
177
+ field_checked.should be_true
178
+ end
179
+ end
180
+ end
181
+
182
+ Then /^the "([^"]*)" checkbox(?: within (.*))? should not be checked$/ do |label, parent|
183
+ patiently do
184
+ with_scope(parent) do
185
+ field_checked = find_field(label)['checked']
186
+ field_checked.should be_false
187
+ end
188
+ end
189
+ end
190
+
191
+ Then /^(?:|I )should be on (.+)$/ do |page_name|
192
+ patiently do
193
+ current_path = URI.parse(current_url).path
194
+ current_path.should == _path_to(page_name)
195
+ end
196
+ end
197
+
198
+ Then /^(?:|I )should have the following query string:$/ do |expected_pairs|
199
+ patiently do
200
+ query = URI.parse(current_url).query
201
+ actual_params = query ? CGI.parse(query) : {}
202
+ expected_params = {}
203
+ expected_pairs.rows_hash.each_pair{|k,v| expected_params[k] = v.split(',')}
204
+
205
+ actual_params.should == expected_params
206
+ end
207
+ end
208
+
209
+ Then /^show me the page$/ do
210
+ save_and_open_page
211
+ end
212
+
213
+
214
+ Then /^I should( not)? see a field "([^"]*)"$/ do |negate, name|
215
+ expectation = negate ? :should_not : :should
216
+ patiently do
217
+ begin
218
+ field = find_field(name)
219
+ rescue Capybara::ElementNotFound
220
+ # In Capybara 0.4+ #find_field raises an error instead of returning nil
221
+ end
222
+ field.send(expectation, be_present)
223
+ end
224
+ end
225
+
226
+ Then /^I should( not)? see the (?:number|amount) ([\-\d,\.]+)(?: (.*?))?$/ do |negate, amount, unit|
227
+ no_minus = amount.starts_with?('-') ? '' : '[^\\-]'
228
+ nbsp = 0xC2.chr + 0xA0.chr
229
+ regexp = Regexp.new(no_minus + "\\b" + Regexp.quote(amount) + (unit ? "( |#{nbsp}|&nbsp;)(#{unit}|#{Regexp.quote(HTMLEntities.new.encode(unit, :named))})" :"\\b"))
230
+ expectation = negate ? :should_not : :should
231
+ patiently do
232
+ page.body.send(expectation, match(regexp))
233
+ end
234
+ end
235
+
236
+ Then /^I should get a response with content-type "([^\"]*)"$/ do |expected_content_type|
237
+ page.response_headers['Content-Type'].should =~ /\A#{Regexp.quote(expected_content_type)}($|;)/
238
+ end
239
+
240
+ Then /^I should get a download with filename "([^\"]*)"$/ do |filename|
241
+ page.response_headers['Content-Disposition'].should =~ /filename="#{filename}"$/
242
+ end
243
+
244
+
245
+ Then /^"([^"]*)" should be selected for "([^"]*)"(?: within "([^\"]*)")?$/ do |value, field, selector|
246
+ patiently do
247
+ with_scope(selector) do
248
+ field_labeled(field).find(:xpath, ".//option[@selected = 'selected'][text() = '#{value}']").should be_present
249
+ end
250
+ end
251
+ end
252
+
253
+ Then /^nothing should be selected for "([^"]*)"?$/ do |field|
254
+ patiently do
255
+ select = find_field(field)
256
+ select.should_not have_css('option[selected]')
257
+ end
258
+ end
259
+
260
+ Then /^"([^"]*)" should( not)? be an option for "([^"]*)"(?: within "([^\"]*)")?$/ do |value, negate, field, selector|
261
+ patiently do
262
+ with_scope(selector) do
263
+ expectation = negate ? :should_not : :should
264
+ field_labeled(field).first(:xpath, ".//option[text() = '#{value}']").send(expectation, be_present)
265
+ end
266
+ end
267
+ end
268
+
269
+ Then /^(?:|I )should see '([^']*)'(?: within '([^']*)')?$/ do |text, selector|
270
+ patiently do
271
+ with_scope(selector) do
272
+ page.should have_content(text)
273
+ end
274
+ end
275
+ end
276
+
277
+ Then /^I should see "([^\"]*)" in the HTML$/ do |text|
278
+ patiently do
279
+ page.body.should include(text)
280
+ end
281
+ end
282
+
283
+ Then /^I should not see "([^\"]*)" in the HTML$/ do |text|
284
+ patiently do
285
+ page.body.should_not include(text)
286
+ end
287
+ end
288
+
289
+ Then /^I should see an error$/ do
290
+ (400 .. 599).should include(page.status_code)
291
+ end
292
+
293
+ Then /^the window should be titled "([^"]*)"$/ do |title|
294
+ page.should have_css('title', :text => title)
295
+ end
296
+
297
+ When /^I reload the page$/ do
298
+ visit current_path
299
+ end
300
+
301
+ Then /^"([^\"]+)" should( not)? be visible$/ do |text, negate|
302
+ paths = [
303
+ "//*[@class='hidden']/*[contains(.,'#{text}')]",
304
+ "//*[@class='invisible']/*[contains(.,'#{text}')]",
305
+ "//*[@style='display: none;']/*[contains(.,'#{text}')]"
306
+ ]
307
+ xpath = paths.join '|'
308
+ expectation = negate ? :should : :should_not
309
+ patiently do
310
+ page.send(expectation, have_xpath(xpath))
311
+ end
312
+ end
313
+
314
+ When /^I click on "([^\"]+)"$/ do |text|
315
+ matcher = ['*', { :text => text }]
316
+ patiently do
317
+ element = page.find(:css, *matcher)
318
+ while better_match = element.first(:css, *matcher)
319
+ element = better_match
320
+ end
321
+ element.click
322
+ end
323
+ end
324
+
325
+ Then /^I should (not )?see an element "([^"]*)"$/ do |negate, selector|
326
+ expectation = negate ? :should_not : :should
327
+ patiently do
328
+ page.send(expectation, have_css(selector))
329
+ end
330
+ end
331
+
332
+ Then /^I should get a text response$/ do
333
+ step 'I should get a response with content-type "text/plain"'
334
+ end
@@ -0,0 +1,5 @@
1
+ module Spreewald
2
+ def self.github_url
3
+ "https://github.com/makandra/spreewald"
4
+ end
5
+ end
@@ -0,0 +1,42 @@
1
+ class MailFinder
2
+ class << self
3
+
4
+ attr_accessor :user_identity
5
+
6
+ def find(conditions)
7
+ ActionMailer::Base.deliveries.detect do |mail|
8
+ [ conditions[:to].nil? || mail.to.include?(resolve_email conditions[:to]),
9
+ conditions[:cc].nil? || mail.cc.andand.include?(resolve_email conditions[:cc]),
10
+ conditions[:bcc].nil? || mail.bcc.andand.include?(resolve_email conditions[:bcc]),
11
+ conditions[:from].nil? || mail.from.include?(resolve_email conditions[:from]),
12
+ conditions[:subject].nil? || mail.subject.include?(conditions[:subject]),
13
+ conditions[:body].nil? || mail.body.include?(conditions[:body]),
14
+ conditions[:attachments].nil? || conditions[:attachments].split(/\s*,\s*/).sort == Array(mail.attachments).collect(&:original_filename).sort
15
+ ].all?
16
+ end.tap do |mail|
17
+ log(mail)
18
+ end
19
+ end
20
+
21
+ def resolve_email(identity)
22
+ if identity =~ /^.+\@.+$/
23
+ identity
24
+ else
25
+ User.send("find_by_#{user_identity || 'email'}!", identity).email
26
+ end
27
+ end
28
+
29
+ def log(mail)
30
+ if mail.present?
31
+ File.open("log/test_mails.log", "a") do |file|
32
+ file << "From: #{mail.from}\n"
33
+ file << "To: #{mail.to.join(', ')}\n"
34
+ file << "Subject: #{mail.subject}\n\n"
35
+ file << mail.body
36
+ file << "\n-------------------------\n\n"
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,36 @@
1
+ module PathSelectorFallbacks
2
+ def _selector_for(locator)
3
+ if respond_to?(:select_for)
4
+ selector_for(locator)
5
+ elsif locator =~ /^"(.+)"$/
6
+ $1
7
+ else
8
+ raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
9
+ "Add and require a selectors.rb file (compare #{Spreewald.github_url}/examples/selectors.rb)"
10
+ end
11
+ end
12
+
13
+ def _path_to(page_name)
14
+ if respond_to?(:path_to)
15
+ path_to(page_name)
16
+ else
17
+ begin
18
+ page_name =~ /^the (.*) page$/
19
+ path_components = $1.split(/\s+/)
20
+ self.send(path_components.push('path').join('_').to_sym)
21
+ rescue NoMethodError, ArgumentError
22
+ raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
23
+ "Add and require a paths.rb file (compare #{Spreewald.github_url}/examples/paths.rb)"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ World(PathSelectorFallbacks)
29
+
30
+ module WithinHelpers
31
+ def with_scope(locator)
32
+ locator ? within(*_selector_for(locator)) { yield } : yield
33
+ end
34
+ end
35
+ World(WithinHelpers)
36
+
@@ -0,0 +1,20 @@
1
+ module ToleranceForSeleniumSyncIssues
2
+ # This is similiar but not entirely the same as Capybara::Node::Base#wait_until or Capybara::Session#wait_until
3
+ def patiently(seconds=Capybara.default_wait_time, &block)
4
+ if page.driver.wait?
5
+ start_time = Time.now
6
+ begin
7
+ block.call
8
+ rescue => e
9
+ raise e if (Time.now - start_time) >= seconds
10
+ sleep(0.05)
11
+ raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if Time.now == start_time
12
+ retry
13
+ end
14
+ else
15
+ block.call
16
+ end
17
+ end
18
+ end
19
+
20
+ World(ToleranceForSeleniumSyncIssues)
@@ -0,0 +1,3 @@
1
+ module Spreewald
2
+ VERSION = "0.0.1"
3
+ end
data/spreewald.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $: << File.expand_path('../lib', __FILE__)
3
+ require 'spreewald_support/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.authors = ["Tobias Kraze"]
7
+ gem.email = ["tobias@kraze.eu"]
8
+ gem.description = %q{A collection of cucumber steps we use in our projects, including steps to check HTML, tables, emails and some utility methods.}
9
+ gem.summary = %q{Collection of useful cucumber steps.}
10
+ gem.homepage = "https://github.com/makandra/spreewald"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "spreewald"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = Spreewald::VERSION
18
+
19
+ gem.add_runtime_dependency('cucumber-rails', '>=1.3.0')
20
+ gem.add_runtime_dependency('cucumber')
21
+ gem.add_runtime_dependency('capybara')
22
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spreewald
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Tobias Kraze
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-09-21 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: cucumber-rails
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 27
29
+ segments:
30
+ - 1
31
+ - 3
32
+ - 0
33
+ version: 1.3.0
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: cucumber
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: capybara
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :runtime
63
+ version_requirements: *id003
64
+ description: A collection of cucumber steps we use in our projects, including steps to check HTML, tables, emails and some utility methods.
65
+ email:
66
+ - tobias@kraze.eu
67
+ executables: []
68
+
69
+ extensions: []
70
+
71
+ extra_rdoc_files: []
72
+
73
+ files:
74
+ - .gitignore
75
+ - Gemfile
76
+ - LICENSE
77
+ - README.md
78
+ - Rakefile
79
+ - examples/paths.rb
80
+ - examples/selectors.rb
81
+ - lib/spreewald.rb
82
+ - lib/spreewald/all_steps.rb
83
+ - lib/spreewald/development_steps.rb
84
+ - lib/spreewald/email_steps.rb
85
+ - lib/spreewald/table_steps.rb
86
+ - lib/spreewald/timecop_steps.rb
87
+ - lib/spreewald/web_steps.rb
88
+ - lib/spreewald_support/github.rb
89
+ - lib/spreewald_support/mail_finder.rb
90
+ - lib/spreewald_support/path_selector_fallbacks.rb
91
+ - lib/spreewald_support/tolerance_for_selenium_sync_issues.rb
92
+ - lib/spreewald_support/version.rb
93
+ - spreewald.gemspec
94
+ homepage: https://github.com/makandra/spreewald
95
+ licenses: []
96
+
97
+ post_install_message:
98
+ rdoc_options: []
99
+
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ hash: 3
117
+ segments:
118
+ - 0
119
+ version: "0"
120
+ requirements: []
121
+
122
+ rubyforge_project:
123
+ rubygems_version: 1.8.24
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Collection of useful cucumber steps.
127
+ test_files: []
128
+
129
+ has_rdoc: