spreewald 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: