turnip-extra_steps 0.1.0

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.
@@ -0,0 +1,2 @@
1
+ module Turnip::ExtraSteps::Support
2
+ end
@@ -0,0 +1,30 @@
1
+ module Turnip::ExtraSteps::Support::CustomMatchers
2
+ rspec = defined?(RSpec) ? RSpec : Spec
3
+
4
+ rspec::Matchers.define :contain_with_wildcards do |expected_string|
5
+ match do |field_value|
6
+ @field_value = field_value.to_s
7
+ @expected_string = expected_string
8
+ regex_parts = expected_string.to_s.split('*', -1).collect { |part| Regexp.escape(part) }
9
+
10
+ @field_value =~ /\A#{regex_parts.join(".*")}\z/m
11
+ end
12
+
13
+ failure_message do
14
+ "The field's content #{@field_value.inspect} did not match #{@expected_string.inspect}"
15
+ end
16
+
17
+ failure_message_when_negated do
18
+ "The field's content #{@field_value.inspect} matches #{@expected_string.inspect}"
19
+ end
20
+ end
21
+
22
+ rspec::Matchers.define :be_sorted do
23
+ match do |array|
24
+ sort_method = defined?(array.natural_sort) ? :natural_sort : :sort
25
+
26
+ array == array.send(sort_method)
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,59 @@
1
+ # coding: UTF-8
2
+
3
+ class MailFinder
4
+ class << self
5
+
6
+ attr_accessor :user_identity
7
+
8
+ def find(conditions)
9
+ filename_method = Rails::VERSION::MAJOR < 3 ? 'original_filename' : 'filename'
10
+ ActionMailer::Base.deliveries.detect do |mail|
11
+ mail_body = email_text_body(mail)
12
+ [ conditions[:to].nil? || mail.to.include?(resolve_email conditions[:to]),
13
+ conditions[:cc].nil? || mail.cc.andand.include?(resolve_email conditions[:cc]),
14
+ conditions[:bcc].nil? || mail.bcc.andand.include?(resolve_email conditions[:bcc]),
15
+ conditions[:from].nil? || mail.from.include?(resolve_email conditions[:from]),
16
+ conditions[:reply_to].nil? || mail.reply_to.include?(resolve_email conditions[:reply_to]),
17
+ conditions[:subject].nil? || mail.subject.include?(conditions[:subject]),
18
+ conditions[:body].nil? || mail_body.include?(conditions[:body]),
19
+ conditions[:attachments].nil? || conditions[:attachments].split(/\s*,\s*/).sort == Array(mail.attachments).collect(&:"#{filename_method}").sort
20
+ ].all?
21
+ end.tap do |mail|
22
+ log(mail)
23
+ end
24
+ end
25
+
26
+ def resolve_email(identity)
27
+ if identity =~ /^.+\@.+$/
28
+ identity
29
+ else
30
+ User.send("find_by_#{user_identity || 'email'}!", identity).email
31
+ end
32
+ end
33
+
34
+ def log(mail)
35
+ if mail.present?
36
+ if defined?(Rails)
37
+ File.open(Rails.root.join("log/test_mails.log"), "a") do |file|
38
+ file << "From: #{mail.from}\n"
39
+ file << "To: #{mail.to.join(', ')}\n" if mail.to
40
+ file << "Subject: #{mail.subject}\n\n"
41
+ file << email_text_body(mail)
42
+ file << "\n-------------------------\n\n"
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def email_text_body(mail)
49
+ if mail.parts.any?
50
+ mail.parts.select { |part| part.content_type.include?('text/') }.collect(&:decoded).join("\n")
51
+ elsif mail.body.respond_to? :raw_source
52
+ mail.body.raw_source
53
+ else
54
+ mail.body
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,38 @@
1
+ # coding: UTF-8
2
+
3
+ module Turnip::ExtraSteps::Support::PathSelectorFallbacks
4
+ def _selector_for(locator)
5
+ if respond_to?(:selector_for)
6
+ selector_for(locator)
7
+ elsif locator =~ /^"(.+)"$/
8
+ $1
9
+ else
10
+ raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
11
+ "Add and require a selectors.rb file (compare /examples/selectors.rb)"
12
+ end
13
+ end
14
+
15
+ def _path_to(page_name)
16
+ if respond_to?(:path_to)
17
+ path_to(page_name)
18
+ else
19
+ begin
20
+ page_name =~ /^the (.*) page$/
21
+ path_components = $1.split(/\s+/)
22
+ self.send(path_components.push('path').join('_').to_sym)
23
+ rescue NoMethodError, ArgumentError
24
+ raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
25
+ "Add and require a paths.rb file (compare /examples/paths.rb)"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ RSpec.configure { |c| c.include Turnip::ExtraSteps::Support::PathSelectorFallbacks}
31
+
32
+ module Turnip::ExtraSteps::Support::WithinHelpers
33
+ def with_scope(locator)
34
+ locator ? within(*_selector_for(locator)) { yield } : yield
35
+ end
36
+ end
37
+ RSpec.configure { |c| c.include Turnip::ExtraSteps::Support::WithinHelpers}
38
+
@@ -0,0 +1,13 @@
1
+ # coding: UTF-8
2
+
3
+ module Turnip::ExtraSteps::Support::StepFallback
4
+ def step(*args)
5
+ if defined?(super)
6
+ super
7
+ else
8
+ When(*args)
9
+ end
10
+ end
11
+ end
12
+
13
+ RSpec.configure { |c| c.include Turnip::ExtraSteps::Support::StepFallback}
@@ -0,0 +1,42 @@
1
+ # coding: UTF-8
2
+
3
+ module Turnip::ExtraSteps::Support::ToleranceForSeleniumSyncIssues
4
+ RETRY_ERRORS = %w[
5
+ Capybara::ElementNotFound
6
+ Spec::Expectations::ExpectationNotMetError
7
+ RSpec::Expectations::ExpectationNotMetError
8
+ Minitest::Assertion
9
+ Capybara::Poltergeist::ClickFailed
10
+ Capybara::ExpectationNotMet
11
+ Selenium::WebDriver::Error::StaleElementReferenceError
12
+ Selenium::WebDriver::Error::NoAlertPresentError
13
+ Selenium::WebDriver::Error::ElementNotVisibleError
14
+ Selenium::WebDriver::Error::NoSuchFrameError
15
+ Selenium::WebDriver::Error::NoAlertPresentError
16
+ ]
17
+
18
+ # This is similiar but not entirely the same as Capybara::Node::Base#wait_until or Capybara::Session#wait_until
19
+ def patiently(seconds=Capybara.default_wait_time, &block)
20
+ old_wait_time = Capybara.default_wait_time
21
+ # dont make nested wait_untils use up all the alloted time
22
+ Capybara.default_wait_time = 0 # for we are a jealous gem
23
+ if page.driver.wait?
24
+ start_time = Time.now
25
+ begin
26
+ block.call
27
+ rescue Exception => e
28
+ raise e unless RETRY_ERRORS.include?(e.class.name)
29
+ raise e if (Time.now - start_time) >= seconds
30
+ sleep(0.05)
31
+ 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
32
+ retry
33
+ end
34
+ else
35
+ block.call
36
+ end
37
+ ensure
38
+ Capybara.default_wait_time = old_wait_time
39
+ end
40
+ end
41
+
42
+ RSpec.configure { |c| c.include Turnip::ExtraSteps::Support::ToleranceForSeleniumSyncIssues}
@@ -0,0 +1,3 @@
1
+ module Spreewald
2
+ VERSION = '1.2.6'
3
+ end
@@ -0,0 +1,114 @@
1
+ module Turnip::ExtraSteps::Support::WebStepsHelpers
2
+
3
+ def assert_visible(options)
4
+ visibility_test(options.merge(:expectation => :visible))
5
+ end
6
+
7
+ def assert_hidden(options)
8
+ visibility_test(options.merge(:expectation => :hidden))
9
+ end
10
+
11
+ private
12
+
13
+ def visibility_test(options)
14
+ case Capybara::current_driver
15
+ when :selenium, :webkit, :poltergeist
16
+ detect_visibility_with_js(options)
17
+ else
18
+ detect_visibility_with_capybara(options)
19
+ end
20
+ end
21
+
22
+ def detect_visibility_with_js(options)
23
+ patiently do
24
+
25
+ selector_javascript = if options.has_key?(:selector)
26
+ options[:selector].to_json
27
+ else
28
+ "':contains(' + " + options[:text].to_json + " + ')'"
29
+ end
30
+
31
+ visibility_detecting_javascript = %[
32
+ (function() {
33
+ var selector = #{selector_javascript};
34
+ var jqueryLoaded = (typeof jQuery != 'undefined');
35
+
36
+ function findCandidates() {
37
+ if (jqueryLoaded) {
38
+ return $(selector);
39
+ } else {
40
+ return $$(selector);
41
+ }
42
+ }
43
+
44
+ function isExactCandidate(candidate) {
45
+ if (jqueryLoaded) {
46
+ return $(candidate).find(selector).length == 0;
47
+ } else {
48
+ return candidate.select(selector).length == 0;
49
+ }
50
+ }
51
+
52
+ function elementVisible(element) {
53
+ if (jqueryLoaded) {
54
+ return $(element).is(':visible');
55
+ } else {
56
+ return element.offsetWidth > 0 && element.offsetHeight > 0;
57
+ }
58
+ }
59
+
60
+ var candidates = findCandidates();
61
+
62
+ if (candidates.length == 0) {
63
+ throw("Selector not found in page: " + selector);
64
+ }
65
+
66
+ for (var i = 0; i < candidates.length; i++) {
67
+ var candidate = candidates[i];
68
+ if (isExactCandidate(candidate) && elementVisible(candidate)) {
69
+ return true;
70
+ }
71
+ }
72
+ return false;
73
+
74
+ })();
75
+ ]
76
+
77
+ visibility_detecting_javascript.gsub!(/\n/, ' ')
78
+ if options[:expectation] == :visible
79
+ expect(page.evaluate_script(visibility_detecting_javascript)).to be_truthy
80
+ else
81
+ expect(page.evaluate_script(visibility_detecting_javascript)).to be_falsy
82
+ end
83
+ end
84
+ end
85
+
86
+ def detect_visibility_with_capybara(options)
87
+ begin
88
+ old_ignore_hidden_elements = Capybara.ignore_hidden_elements
89
+ Capybara.ignore_hidden_elements = false
90
+ if options.has_key?(:selector)
91
+ expect(page).to have_css(options[:selector])
92
+ have_hidden_tag = have_css(".hidden #{options[:selector]}, .invisible #{selector_or_text}, [style~=\"display: none\"] #{options[:selector]}")
93
+ if options[:expectation] == :hidden
94
+ expect(page).to have_hidden_tag
95
+ else
96
+ expect(page).not_to have_hidden_tag
97
+ end
98
+ else
99
+ expect(page).to have_css('*', :text => options[:text])
100
+ have_hidden_text = have_css('.hidden, .invisible, [style~="display: none"]', :text => options[:text])
101
+ if options[:expectation] == :hidden
102
+ expect(page).to have_hidden_text
103
+ else
104
+ expect(page).not_to have_hidden_text
105
+ end
106
+ end
107
+ ensure
108
+ Capybara.ignore_hidden_elements = old_ignore_hidden_elements
109
+ end
110
+ end
111
+
112
+ end
113
+
114
+ RSpec.configure { |c| c.include Turnip::ExtraSteps::Support::WebStepsHelpers}
@@ -0,0 +1,187 @@
1
+ # coding: UTF-8
2
+
3
+ require 'turnip/extra_steps/support/tolerance_for_selenium_sync_issues'
4
+
5
+ module Turnip::ExtraSteps::Support::TableStepsHelper
6
+ module ArrayMethods
7
+
8
+ def find_row(expected_row)
9
+ find_index do |row|
10
+ expected_row.all? do |expected_column|
11
+ first_column = row.find_index do |column|
12
+ content = normalize_content(column.content)
13
+ expected_content = normalize_content(expected_column)
14
+ matching_parts = expected_content.split(/\s*\*\s*/, -1).collect { |part| Regexp.escape(part) }
15
+ matching_expression = /\A#{matching_parts.join(".*")}\z/
16
+ content =~ matching_expression
17
+ end
18
+ if first_column.nil?
19
+ false
20
+ else
21
+ row = row[(first_column + 1)..-1]
22
+ true
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ def normalize_content(content)
29
+ nbsp = " "
30
+ content.gsub(/[\r\n\t]+/, ' ').gsub(nbsp, ' ').gsub(/ {2,}/, ' ').strip
31
+ end
32
+
33
+ end
34
+
35
+ rspec = defined?(RSpec) ? RSpec : Spec
36
+
37
+ rspec::Matchers.define :contain_table do |*args|
38
+ match do |tables|
39
+ @last_unmatched_row = nil
40
+ @extra_rows = nil
41
+ @best_rows_matched = -1
42
+ options = args.extract_options!
43
+ expected_table = args.first
44
+ tables.any? do |table|
45
+ skipped_rows = []
46
+ rows_matched = 0
47
+ match = expected_table.all? do |expected_row|
48
+ if @best_rows_matched < rows_matched
49
+ @last_unmatched_row = expected_row
50
+ @best_rows_matched = rows_matched
51
+ end
52
+ table.extend ArrayMethods
53
+ first_row = table.find_row(expected_row)
54
+ if first_row.nil?
55
+ false
56
+ else
57
+ rows_matched += 1
58
+ if options[:unordered]
59
+ table.delete_at(first_row)
60
+ else
61
+ skipped_rows += table[0...first_row]
62
+ table = table[(first_row + 1)..-1]
63
+ end
64
+ true
65
+ end
66
+ end
67
+ remaining_rows = skipped_rows + table
68
+ if match and options[:exactly] and not remaining_rows.empty?
69
+ @extra_rows = remaining_rows
70
+ match = false
71
+ end
72
+ match
73
+ end
74
+ end
75
+
76
+ failure_message do
77
+ if @extra_rows
78
+ "Found the following extra row: #{@extra_rows.first.collect(&:content).collect(&:squish).inspect}"
79
+ elsif @last_unmatched_row
80
+ "Could not find the following row: #{@last_unmatched_row.inspect}"
81
+ else
82
+ "Could not find a table"
83
+ end
84
+ end
85
+
86
+ failure_message_when_negated do
87
+ "Found the complete table: #{args.first.inspect}."
88
+ end
89
+ end
90
+
91
+ def parse_table(table)
92
+ if table.is_a?(String)
93
+ table.sub!(/^\n/, '')
94
+ # multiline string. split it assuming a format like cucumber tables have.
95
+ table.split(/\n/).collect do |line|
96
+ line.sub!(/^\|/, '')
97
+ line.sub!(/\|$/, '')
98
+ line.gsub!(/^\ +/, '')
99
+ line.gsub!(/\ +$/, '')
100
+ line.split(/\s*\|\s*/)
101
+ end
102
+ else
103
+ # vanilla cucumber table.
104
+ table.raw
105
+ end
106
+ end
107
+ end
108
+ RSpec.configure { |c| c.include Turnip::ExtraSteps::Support::TableStepsHelper}
109
+
110
+
111
+ # Check the content of tables in your HTML.
112
+ #
113
+ # See [this article](https://makandracards.com/makandra/763-cucumber-step-to-match-table-rows-with-capybara) for details.
114
+ #Then /^I should( not)? see a table with (exactly )?the following rows( in any order)?:?$/ do |negate, exactly, unordered, expected_table|
115
+ step "I :whether_to see a table with the following rows:" do |positive, expected_table|
116
+ patiently do
117
+ document = Nokogiri::HTML(page.body)
118
+ tables = document.xpath('//table').collect { |table| table.xpath('.//tr').collect { |row| row.xpath('.//th|td') } }
119
+ parsed_table = parse_table(expected_table)
120
+
121
+ options = { exactly: false , unordered: false }
122
+
123
+ if positive
124
+ expect(tables).to contain_table(parsed_table, options)
125
+ #tables.should contain_table(parsed_table, options)
126
+ else
127
+ expect(tables).not_to contain_table(parsed_table, options)
128
+ #tables.should_not contain_table(parsed_table, options)
129
+ end
130
+ end
131
+ end
132
+
133
+ step "I :whether_to see a table with exactly the following rows:" do |positive, expected_table|
134
+ patiently do
135
+ document = Nokogiri::HTML(page.body)
136
+ tables = document.xpath('//table').collect { |table| table.xpath('.//tr').collect { |row| row.xpath('.//th|td') } }
137
+ parsed_table = parse_table(expected_table)
138
+
139
+ options = { exactly: true, unordered: false }
140
+
141
+ if positive
142
+ expect(tables).to contain_table(parsed_table, options)
143
+ #tables.should contain_table(parsed_table, options)
144
+ else
145
+ expect(tables).not_to contain_table(parsed_table, options)
146
+ #tables.should_not contain_table(parsed_table, options)
147
+ end
148
+ end
149
+ end
150
+
151
+ step "I :whether_to see a table with the following rows in any order:" do |positive, expected_table|
152
+ patiently do
153
+ document = Nokogiri::HTML(page.body)
154
+ tables = document.xpath('//table').collect { |table| table.xpath('.//tr').collect { |row| row.xpath('.//th|td') } }
155
+ parsed_table = parse_table(expected_table)
156
+
157
+ options = { exactly: false, unordered: true }
158
+
159
+ if positive
160
+ expect(tables).to contain_table(parsed_table, options)
161
+ #tables.should contain_table(parsed_table, options)
162
+ else
163
+ expect(tables).not_to contain_table(parsed_table, options)
164
+ #tables.should_not contain_table(parsed_table, options)
165
+ end
166
+ end
167
+ end
168
+
169
+ step "I :whether_to see a table with exactly the following rows in any order:" do |positive, expected_table|
170
+ patiently do
171
+ document = Nokogiri::HTML(page.body)
172
+ tables = document.xpath('//table').collect { |table| table.xpath('.//tr').collect { |row| row.xpath('.//th|td') } }
173
+ parsed_table = parse_table(expected_table)
174
+
175
+ options = { exactly: true, unordered: true }
176
+
177
+ if positive
178
+ expect(tables).to contain_table(parsed_table, options)
179
+ #tables.should contain_table(parsed_table, options)
180
+ else
181
+ expect(tables).not_to contain_table(parsed_table, options)
182
+ #tables.should_not contain_table(parsed_table, options)
183
+ end
184
+ end
185
+ end
186
+
187
+