watirmark 5.14.16

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