watirmark 5.14.16

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 (106) hide show
  1. data/app_generators/create_project/create_project_generator.rb +115 -0
  2. data/app_generators/create_project/templates/features/env.rb.erb +8 -0
  3. data/app_generators/create_project/templates/features/model_steps.rb.erb +9 -0
  4. data/app_generators/create_project/templates/features/post_error_steps.rb.erb +15 -0
  5. data/app_generators/create_project/templates/features/sample.feature.erb +5 -0
  6. data/app_generators/create_project/templates/features/site_steps.rb.erb +7 -0
  7. data/app_generators/create_project/templates/generators/controller.rb.erb +9 -0
  8. data/app_generators/create_project/templates/generators/generate.rb.erb +9 -0
  9. data/app_generators/create_project/templates/generators/model.rb.erb +7 -0
  10. data/app_generators/create_project/templates/generators/mvc_generator.rb.erb +100 -0
  11. data/app_generators/create_project/templates/generators/rbeautify.rb.erb +212 -0
  12. data/app_generators/create_project/templates/generators/view.rb.erb +16 -0
  13. data/app_generators/create_project/templates/generators/workflow_loader.rb.erb +1 -0
  14. data/app_generators/create_project/templates/library/base_controller.rb.erb +9 -0
  15. data/app_generators/create_project/templates/library/base_view.rb.erb +6 -0
  16. data/app_generators/create_project/templates/library/configuration.rb.erb +6 -0
  17. data/app_generators/create_project/templates/library/core_libraries.rb.erb +9 -0
  18. data/app_generators/create_project/templates/library/loader.rb.erb +23 -0
  19. data/app_generators/create_project/templates/library/page_load_checker.rb.erb +11 -0
  20. data/app_generators/create_project/templates/library/post_errors_checker.rb.erb +23 -0
  21. data/app_generators/create_project/templates/library/project_require_file.rb.erb +8 -0
  22. data/app_generators/create_project/templates/library/search_controller.rb.erb +12 -0
  23. data/app_generators/create_project/templates/library/workflows.rb.erb +0 -0
  24. data/app_generators/create_project/templates/project/config.yml.erb +3 -0
  25. data/app_generators/create_project/templates/project/gemfile.rb.erb +11 -0
  26. data/app_generators/create_project/templates/project/rakefile.rb.erb +21 -0
  27. data/bin/etapestry/Gemfile +11 -0
  28. data/bin/etapestry/config.yml +3 -0
  29. data/bin/etapestry/features/etapestry_home.feature +5 -0
  30. data/bin/etapestry/features/step_definitions/model_steps.rb +9 -0
  31. data/bin/etapestry/features/step_definitions/post_error_steps.rb +15 -0
  32. data/bin/etapestry/features/step_definitions/site_steps.rb +7 -0
  33. data/bin/etapestry/features/support/env.rb +8 -0
  34. data/bin/etapestry/generators/mvc/mvc_generator.rb +100 -0
  35. data/bin/etapestry/generators/mvc/rbeautify.rb +212 -0
  36. data/bin/etapestry/generators/mvc/templates/controller.rb.erb +9 -0
  37. data/bin/etapestry/generators/mvc/templates/model.rb.erb +7 -0
  38. data/bin/etapestry/generators/mvc/templates/view.rb.erb +16 -0
  39. data/bin/etapestry/generators/mvc/templates/workflow_loader.rb.erb +1 -0
  40. data/bin/etapestry/lib/etapestry.rb +8 -0
  41. data/bin/etapestry/lib/etapestry/checkers/page_load_checker.rb +11 -0
  42. data/bin/etapestry/lib/etapestry/checkers/post_errors_checker.rb +23 -0
  43. data/bin/etapestry/lib/etapestry/configuration.rb +6 -0
  44. data/bin/etapestry/lib/etapestry/core_libraries.rb +9 -0
  45. data/bin/etapestry/lib/etapestry/loader.rb +23 -0
  46. data/bin/etapestry/lib/etapestry/site/base_controller.rb +9 -0
  47. data/bin/etapestry/lib/etapestry/site/base_view.rb +6 -0
  48. data/bin/etapestry/lib/etapestry/site/search_controller.rb +12 -0
  49. data/bin/etapestry/lib/etapestry/workflows.rb +0 -0
  50. data/bin/etapestry/rakefile.rb +21 -0
  51. data/bin/etapestry/script/generate.rb +9 -0
  52. data/bin/twitter/features/hashtag_search.feature +93 -0
  53. data/bin/twitter/features/step_definitions/hashtag_steps.rb +9 -0
  54. data/bin/twitter/lib/twitter/workflows/search/result_controller.rb +13 -0
  55. data/bin/twitter/lib/twitter/workflows/search/result_model.rb +5 -0
  56. data/bin/twitter/lib/twitter/workflows/search/result_view.rb +19 -0
  57. data/bin/watirmark +10 -0
  58. data/lib/watirmark.rb +26 -0
  59. data/lib/watirmark/at_exit.rb +13 -0
  60. data/lib/watirmark/configuration.rb +201 -0
  61. data/lib/watirmark/controller/actions.rb +172 -0
  62. data/lib/watirmark/controller/assertions.rb +116 -0
  63. data/lib/watirmark/controller/controller.rb +191 -0
  64. data/lib/watirmark/controller/dialogs.rb +33 -0
  65. data/lib/watirmark/controller/matcher.rb +19 -0
  66. data/lib/watirmark/cucumber/cuke_helper.rb +150 -0
  67. data/lib/watirmark/cucumber/email_helper.rb +103 -0
  68. data/lib/watirmark/cucumber/env.rb +9 -0
  69. data/lib/watirmark/cucumber/hooks.rb +16 -0
  70. data/lib/watirmark/cucumber/model_helper.rb +34 -0
  71. data/lib/watirmark/cucumber/transforms.rb +55 -0
  72. data/lib/watirmark/exceptions.rb +15 -0
  73. data/lib/watirmark/extensions/ruby_extensions.rb +129 -0
  74. data/lib/watirmark/extensions/webdriver_extensions.rb +150 -0
  75. data/lib/watirmark/formatters/snapshot_formatter.rb +23 -0
  76. data/lib/watirmark/loader.rb +87 -0
  77. data/lib/watirmark/model.rb +3 -0
  78. data/lib/watirmark/models/cucumber_helper.rb +49 -0
  79. data/lib/watirmark/models/debug_methods.rb +21 -0
  80. data/lib/watirmark/models/default_values.rb +21 -0
  81. data/lib/watirmark/models/factory.rb +168 -0
  82. data/lib/watirmark/models/factory_method_generators.rb +84 -0
  83. data/lib/watirmark/models/factory_methods.rb +72 -0
  84. data/lib/watirmark/models/trait.rb +35 -0
  85. data/lib/watirmark/models/upload_csv.rb +24 -0
  86. data/lib/watirmark/page/keyed_element.rb +63 -0
  87. data/lib/watirmark/page/page.rb +50 -0
  88. data/lib/watirmark/page/page_definition.rb +187 -0
  89. data/lib/watirmark/page/process_page.rb +112 -0
  90. data/lib/watirmark/page/radio_maps.rb +53 -0
  91. data/lib/watirmark/profile.rb +22 -0
  92. data/lib/watirmark/rake/smoketest.rb +17 -0
  93. data/lib/watirmark/screenshot.rb +127 -0
  94. data/lib/watirmark/session.rb +115 -0
  95. data/lib/watirmark/version.rb +5 -0
  96. data/spec/assertions_spec.rb +95 -0
  97. data/spec/config_spec.rb +82 -0
  98. data/spec/controller_actions_spec.rb +91 -0
  99. data/spec/controller_spec.rb +426 -0
  100. data/spec/controllers_and_models_spec.rb +52 -0
  101. data/spec/model_factory_spec.rb +568 -0
  102. data/spec/model_traits_spec.rb +141 -0
  103. data/spec/page_spec.rb +127 -0
  104. data/spec/process_page_spec.rb +163 -0
  105. data/spec/spec_helper.rb +17 -0
  106. metadata +238 -0
@@ -0,0 +1,33 @@
1
+ module Watirmark
2
+ module Dialogs
3
+ def modal_exists?
4
+ !!(Page.browser.windows.size > 1)
5
+ end
6
+
7
+ def with_modal_dialog(&block)
8
+ wait_for_modal_dialog
9
+ parent_window = (Page.browser.windows.size) - 2
10
+ begin
11
+ Page.browser.windows.last.use
12
+ Page.browser.wait
13
+ block.call
14
+ ensure
15
+ Page.browser.windows[parent_window].use
16
+ end
17
+ end
18
+
19
+ def wait_for_modal_dialog
20
+ begin
21
+ Timeout::timeout(30) {
22
+ until modal_exists?
23
+ sleep 0.002
24
+ end
25
+ Page.browser.wait
26
+ sleep 0.02
27
+ }
28
+ rescue Timeout::Error
29
+ raise Watirmark::TestError, 'Timed out while waiting for modal dialog to open'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module Watirmark
2
+ class Matcher
3
+ class << self
4
+ @@matchers = {}
5
+
6
+ def add_matcher(name, &block)
7
+ @@matchers[name] = block
8
+ end
9
+
10
+ def exists?(name)
11
+ @@matchers.has_key?(name)
12
+ end
13
+
14
+ def matches?(element, expected, actual)
15
+ instance_exec(element, actual, &@@matchers[expected])
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,150 @@
1
+ require_relative '../models/cucumber_helper'
2
+
3
+ module CukeHelper
4
+ include Watirmark::Model::CucumberHelper
5
+
6
+ def log
7
+ Watirmark::Configuration.instance.logger
8
+ end
9
+
10
+ def eval_keywords(hash)
11
+ hash.each do |key, value|
12
+ hash[key] = format_value(value)
13
+ end
14
+ hash
15
+ end
16
+
17
+ # when the input is an array, eval each element
18
+ def eval_raw_record(row)
19
+ row.each_index do |col|
20
+ row[col] = format_value(row[col])
21
+ end
22
+ row
23
+ end
24
+
25
+ # calls the models method if of the pattern <name>.method
26
+ def call_model_methods(hash)
27
+ hash.each { |key, value| hash[key] = eval(value[1..value.length]) if value[0, 1].eql?("=") }
28
+ hash
29
+ end
30
+
31
+ # return {:foo=1, :bar=2} from {'foo' =>1, 'bar' =>2}
32
+ def colonize(hash)
33
+ newhash = {}
34
+ hash.each { |k, v| newhash[k.to_sym] = v }
35
+ newhash
36
+ end
37
+
38
+ # returns [{:foo=1, :bar=2}, {:foo=3, :bar=4}] list of hash records
39
+ # from table table where first row headers are keys and each row values
40
+ # | foo | bar |
41
+ # | 1 | 2 |
42
+ # | 3 | 4 |
43
+ def hash_record_list table
44
+ table.map_headers! { |h| h.to_sym }
45
+ records = table.hashes
46
+ records.map { |record| eval_keywords(record) }
47
+ end
48
+
49
+ # returns {:foo=1, :bar=2} hash record
50
+ # from a key, value 2 column table
51
+ # | foo | 1 |
52
+ # | bar | 2 |
53
+ def hash_record table
54
+ colonize eval_keywords(table.rows_hash)
55
+ end
56
+
57
+ # returns .raw but still handles eval-ing the keywords
58
+ def raw_record table
59
+ table.raw.map { |record| eval_raw_record(record) }
60
+ end
61
+
62
+ #Given a list of keys or strings (call it key), return a string composed of
63
+ #record_hash[key] or the string is key isn't really a key. Yea, screwy I know
64
+ def compose_string_from(record_hash, key_list)
65
+ result = ''
66
+ key_list.each do |key|
67
+ if record_hash[key]
68
+ result += record_hash[key]
69
+ elsif key.is_a? String
70
+ result += key
71
+ end
72
+ end
73
+ result
74
+ end
75
+
76
+ # Allows expected values for a cucumber table field to be different
77
+ # based on whether you are using Service Bus or DataSync. Use case is
78
+ # for a bug in DataSync that was not replicated in Service Bus
79
+ # In this example: DataSync incorrectly assigns 'Donation' and Service
80
+ # Bus correctly assigns 'TeamRaiser Gift' to transaction type field
81
+ # # VERIFY ---------------+-------------------------------------------+
82
+ # | accountname | Tr01_Hellraiser Eventdonor Household |
83
+ # | type | Individual Gift |
84
+ # | transactiontype | =syncmode('TeamRaiser Gift','Donation') |
85
+ def syncmode(expected_bus, expected_datasync)
86
+ if ENV['SYNCMODE'] == 'DataSync'
87
+ expected_datasync
88
+ else
89
+ expected_bus
90
+ end
91
+ end
92
+
93
+ # if a block provided raises VerificationException we verify again
94
+ # this method acts as a gateway to prevent false negatives in testing CRM objects that we expect to change their values after being
95
+ # updated by the service bus
96
+ # motivation:
97
+ # After serivce bus sends a message to a CRM it takes a while sometimes for the updates to the object to occur.
98
+ # When we verify the state of the object we may still look at old values.
99
+ # We want to introduce a pooling mechanism that would re-verify one or more times after a duration of time
100
+ # and only fail after the specified count of tries.
101
+ # usage:
102
+ # verify_failure { controller.verify } #=> provide block that can fail with VerificationException
103
+ def verify_failure(tries_count=6, seconds_between_tries=30)
104
+ counter = 0
105
+ loop do
106
+ counter += 1
107
+ begin
108
+ yield
109
+ rescue Watirmark::VerificationException => e
110
+ Watirmark.logger.warn "*** reverifying failure: #{e}"
111
+ raise e if counter >= tries_count
112
+ sleep seconds_between_tries
113
+ else
114
+ break
115
+ end
116
+ end
117
+ end
118
+
119
+ # given a hash and list of keys, make the values into a float if they exist
120
+ # FIXME: this is a work around until the Cucumber tests use a new matcher
121
+ # in convio_watir by making strings into floats
122
+ #
123
+ # record={:amountreceived => "10.00", :probability => "100"}
124
+ # floatify(record, [:amountreceived, :probability])
125
+ # changes record into
126
+ # record={:amountreceived => 10.0, :probability => 100.0}
127
+ def floatify(record_hash, key_list)
128
+ key_list.each do |key|
129
+ record_hash[key] = record_hash[key].to_f if record_hash[key]
130
+ end
131
+ record_hash
132
+ end
133
+
134
+ # merges sequentially a list of hashes
135
+ def multimerge *hashes
136
+ hashes.inject({}) { |memo, hash| hash.nil? ? memo : memo.merge(hash) }
137
+ end
138
+
139
+ def create_ts(with_separators=true)
140
+ if with_separators
141
+ Time.now.strftime "%Y:%m:%d:%H:%M:%S"
142
+ else
143
+ Time.now.strftime "%Y%m%d%H%M%S"
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+
150
+
@@ -0,0 +1,103 @@
1
+ module EmailHelper
2
+
3
+ # Access the list of emails we've read and cached
4
+ def emails
5
+ EmailCollection
6
+ end
7
+
8
+ # Parse the email body into an object
9
+ def email_body(body)
10
+ EmailBody.new(body)
11
+ end
12
+
13
+ class EmailCollection
14
+ class << self
15
+ def email
16
+ @email ||= {}
17
+ end
18
+
19
+ # Connect to the INBOX
20
+ def qa_inbox(model)
21
+ WatirmarkEmail::QAMail.new(email_address(model) )
22
+ end
23
+
24
+ # Return an email if we've seen it
25
+ def found_email(model)
26
+ email[model.model_name]
27
+ end
28
+
29
+ # Read the contents of an email, cache it and delete the email
30
+ def read_email(model, subject, timeout=30)
31
+ email_content = qa_inbox(model).get_email_text(["SUBJECT", subject, "TO", model.email], timeout)
32
+ email[model.model_name] = EmailBody.new(email_content)
33
+ end
34
+
35
+ def log_email(model)
36
+ Watirmark.logger.info "Email Received"
37
+ Watirmark.logger.info email[model.model_name].body.inspect
38
+ end
39
+
40
+ # Access a cached copy of an email
41
+ def [](model)
42
+ email[model.model_name]
43
+ end
44
+
45
+ # Remove our cached copy of the email
46
+ def delete(model)
47
+ email[model.model_name] = nil
48
+ end
49
+
50
+ # Format the email address so we're always referring to the qasendmail domain
51
+ def email_address(model)
52
+ model.email.gsub(/\+.+/,'').gsub(/@.+/, '@qasendmail.corp.convio.com')
53
+ end
54
+ end
55
+ end
56
+
57
+ class EmailLink
58
+ attr_accessor :href, :text
59
+
60
+ def initialize(doc)
61
+ @href = doc['href']
62
+ @text = doc.content
63
+ end
64
+ end
65
+
66
+ class EmailBody
67
+ attr_accessor :doc, :body
68
+
69
+ def initialize(body)
70
+ @body = body
71
+ @doc = ::Nokogiri::HTML.parse body
72
+ end
73
+
74
+ def links
75
+ unless @links
76
+ @links = []
77
+ @doc.xpath('//a').each do |link|
78
+ @links << EmailLink.new(link)
79
+ end
80
+ end
81
+ @links
82
+ end
83
+
84
+ def link(how, matcher)
85
+ links.each do |link|
86
+ case how
87
+ when :text
88
+ return link if /#{matcher}/.matches link.text
89
+ when :href
90
+ return link if /#{matcher}/.matches link.href
91
+ end
92
+ end
93
+ nil
94
+ end
95
+
96
+ def inspect
97
+ @doc.to_s
98
+ end
99
+
100
+ end
101
+ end
102
+
103
+
@@ -0,0 +1,9 @@
1
+ require 'watirmark/cucumber/cuke_helper'
2
+ require 'watirmark/cucumber/email_helper'
3
+ require 'watirmark/cucumber/model_helper'
4
+ require 'watirmark/cucumber/transforms'
5
+ require 'watirmark/cucumber/hooks'
6
+
7
+ World CukeHelper
8
+ World EmailHelper
9
+ World ModelHelper
@@ -0,0 +1,16 @@
1
+ Around('@catch-post-failure') do |scenario, block|
2
+ Watirmark::Session.instance.catch_post_failures(&block)
3
+ end
4
+
5
+ # Initialize post failures so we don't get leakage between scenarios
6
+ Before('~@catch-post-failure') do
7
+ Watirmark::Session.instance.post_failure = nil
8
+ end
9
+
10
+ After do |scenario|
11
+ image = "#{Time.now.to_i}-#{UUID.new.generate(:compact)}.png"
12
+ path = "reports/screenshots"
13
+ FileUtils.mkdir_p path unless File.directory? path
14
+ Page.browser.screenshot.save "#{path}/#{image}"
15
+ embed "screenshots/#{image}", 'image/png'
16
+ end
@@ -0,0 +1,34 @@
1
+ module ModelHelper
2
+ def add_model_debug_values(table)
3
+ table.raw.each do |row|
4
+ DebugModelValues[row[0]][row[1]] = row[2]
5
+ end
6
+ end
7
+
8
+ def update_model(model, table)
9
+ model.update(hash_record(table))
10
+ end
11
+
12
+ def with_updated_model(model, table, &block)
13
+ unless model.includes?(hash_record(table))
14
+ update_model(model, table)
15
+ block.call
16
+ Watirmark.logger.info "Updated models '#{model.model_name}':\n#{hash_record(table).inspect}"
17
+ end
18
+ end
19
+
20
+ # Perform an action using a models and update
21
+ # the models if that action is successful
22
+ def with_model(model, table, &block)
23
+ orig_model = model.clone
24
+ update_model(model, table)
25
+ block.call
26
+ if Watirmark::Session.instance.post_failure
27
+ Watirmark.logger.info "Reverting Model #{Watirmark::Session.instance.post_failure}"
28
+ model.update(orig_model.to_h) # revert models on failure
29
+ elsif model.to_h != orig_model.to_h
30
+ Watirmark.logger.info "Updated model '#{model.model_name}' #{hash_record(table).inspect}"
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,55 @@
1
+ # This is a globally accessible static hash to
2
+ # store all models declared by the test automation. Making it available
3
+ # allows us to use the models values as table parameters in the gherkin!
4
+ DataModels = {}
5
+
6
+
7
+ module Watirmark
8
+ module Transforms
9
+ class << self
10
+ def new_model model_name, user_defined_name
11
+ if model_exists?(user_defined_name) && !temporary_model?(user_defined_name)
12
+ DataModels[user_defined_name]
13
+ else
14
+ DataModels[user_defined_name] = model_class(model_name).new(:model_name => user_defined_name)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def model_exists?(name)
21
+ DataModels.key?(name)
22
+ end
23
+
24
+ def model_class(name)
25
+ model_class_name(name).split('::').inject(Kernel) {|context, x| context.const_get x}
26
+ end
27
+
28
+ def model_class_name(name)
29
+ "#{name.split.map(&:camelize).join}Model"
30
+ end
31
+
32
+ def temporary_model?(user_defined_name)
33
+ DataModels[user_defined_name].kind_of?(ModelOpenStruct)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ # Create a new models and add it to the DataModels hash
40
+ NEW_MODEL = Transform /^\[new (\S+) (\S+)\]$/ do |model_name, user_defined_name|
41
+ model_name.chop! if model_name.end_with?(':')
42
+ Watirmark::Transforms.new_model model_name, user_defined_name
43
+ end
44
+
45
+ OLD_STYLE_MODEL = Transform /^\[new ([^:]+): (\S+)\]$/ do |model_name, user_defined_name|
46
+ model_name = model_name.camelize
47
+ model_name.chop! if model_name.end_with?(':')
48
+ Watirmark::Transforms.new_model model_name, user_defined_name
49
+ end
50
+
51
+ # Return the models from the collection of existing models
52
+ MODEL = Transform /^\[(\S+)\]$/ do |model_name|
53
+ DataModels[model_name] ||= ModelOpenStruct.new(:model_name => model_name)
54
+ end
55
+
@@ -0,0 +1,15 @@
1
+ module Watirmark
2
+ class Watirmark::MatcherNotFound < RuntimeError ;end
3
+ class Watirmark::TestError < RuntimeError ;end
4
+ class Watirmark::TestFailure < RuntimeError ;end
5
+ class Watirmark::PostFailure < RuntimeError ;end
6
+ class Watirmark::TDPage < RuntimeError; end
7
+ class Watirmark::SecurityIssue < RuntimeError; end
8
+ class Watirmark::WebPageElementNotFound < RuntimeError ;end
9
+ class Watirmark::ModelNotFound < RuntimeError ;end
10
+ class Watirmark::ModelCreationError < RuntimeError ;end
11
+ class Watirmark::InvalidConfigurationFile < RuntimeError ;end
12
+ class Watirmark::VerificationException < RuntimeError
13
+ attr_accessor :actual, :expected
14
+ end
15
+ end