testcentricity_apps 4.0.15 → 4.1.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.
@@ -1,47 +1,28 @@
1
- require 'yaml'
2
- require 'json'
3
- require 'virtus'
4
- require 'time'
1
+ require 'active_support'
2
+ require 'active_support/core_ext/hash'
5
3
  require 'chronic'
6
4
  require 'faker'
5
+ require 'json'
6
+ require 'rexml/document'
7
+ require 'smarter_csv'
8
+ require 'time'
9
+ require 'virtus'
10
+ require 'yaml'
7
11
 
8
12
 
9
13
  module TestCentricity
10
14
 
11
15
  PRIMARY_DATA_PATH ||= 'config/test_data/'
16
+ SECONDARY_DATA_PATH ||= 'config/data/'
12
17
  PRIMARY_DATA_FILE ||= "#{PRIMARY_DATA_PATH}data."
13
18
  YML_PRIMARY_DATA_FILE ||= "#{PRIMARY_DATA_FILE}yml"
14
19
  JSON_PRIMARY_DATA_FILE ||= "#{PRIMARY_DATA_FILE}json"
15
20
 
16
21
 
17
- class DataObject
18
- attr_accessor :current
19
- attr_accessor :context
20
- attr_accessor :hash_table
21
-
22
- def initialize(data)
23
- @hash_table = data
24
- end
25
-
26
- def self.current
27
- @current
28
- end
29
-
30
- def self.current=(current)
31
- @current = current
32
- end
33
- end
34
-
35
-
36
22
  class DataPresenter
37
23
  include Virtus.model
38
24
 
39
25
  attr_accessor :current
40
- attr_accessor :context
41
-
42
- def initialize(data)
43
- self.attributes = data unless data.nil?
44
- end
45
26
 
46
27
  def self.current
47
28
  @current
@@ -53,48 +34,162 @@ module TestCentricity
53
34
  end
54
35
 
55
36
 
56
- # :nocov:
57
37
  class DataSource
58
38
  attr_accessor :file_path
59
- attr_accessor :node
39
+ attr_accessor :file_extension
60
40
 
61
- def read_yaml_node_data(file_name, node_name)
62
- @file_path = "#{PRIMARY_DATA_PATH}#{file_name}"
63
- @node = node_name
64
- data = YAML.load_file(@file_path)
65
- data[node_name]
41
+ def read_file(file_name, key = nil, node_name = nil, options = nil)
42
+ # check to see if full file path was specified
43
+ if File.exist?(file_name)
44
+ @file_path = file_name
45
+ else
46
+ # construct the full file path to the file to be read
47
+ @file_path = "#{PRIMARY_DATA_PATH}#{file_name}"
48
+ unless File.exist?(@file_path)
49
+ @file_path = "#{SECONDARY_DATA_PATH}#{file_name}"
50
+ raise "File #{file_name} not found in Primary or Secondary folders in config folder" unless File.exist?(@file_path)
51
+ end
52
+ end
53
+ # determine file type and read in data from file
54
+ @file_extension = File.extname(file_name)
55
+ data = case @file_extension
56
+ when '.yml'
57
+ YAML.load_file(@file_path)
58
+ when'.json'
59
+ JSON.parse(File.read(@file_path))
60
+ when '.xml'
61
+ xml_data = File.read(@file_path)
62
+ Hash.from_xml(xml_data)
63
+ when '.csv'
64
+ if options
65
+ SmarterCSV.process(@file_path, options)
66
+ else
67
+ SmarterCSV.process(@file_path)
68
+ end
69
+ else
70
+ raise "#{file_name} is not a supported file type"
71
+ end
72
+ # return data if sourced from a .csv file
73
+ return data if @file_extension == '.csv'
74
+
75
+ # read data from specified key and/or node
76
+ result = if key
77
+ raise "Key #{key} not found" unless data.key?(key)
78
+
79
+ if node_name
80
+ raise "Node #{node_name} not found" unless data[key].key?(node_name)
81
+
82
+ data[key][node_name]
83
+ else
84
+ data[key]
85
+ end
86
+ else
87
+ data
88
+ end
89
+ self.class.send(:process_data, result, options)
66
90
  end
67
91
 
68
- def read_json_node_data(file_name, node_name)
69
- @file_path = "#{PRIMARY_DATA_PATH}#{file_name}"
70
- @node = node_name
71
- raw_data = File.read(@file_path)
72
- data = JSON.parse(raw_data)
73
- data[node_name]
92
+ private
93
+
94
+ def self.process_data(data, options)
95
+ # calculate dynamic values if any are specified
96
+ if data.is_a?(Hash)
97
+ data.each do |key, value|
98
+ data[key] = calculate_dynamic_value(value) if value.to_s.start_with?('eval!')
99
+ end
100
+ end
101
+ return data unless options
102
+
103
+ # convert keys to symbols if :keys_as_symbols is true in options
104
+ if options.key?(:keys_as_symbols) && options[:keys_as_symbols]
105
+ data.transform_keys!(&:to_sym)
106
+ end
107
+ # convert values if :value_converters are specified in options
108
+ if options.key?(:value_converters)
109
+ map_values(data, options[:value_converters])
110
+ else
111
+ data
112
+ end
74
113
  end
75
114
 
76
- private
115
+ def self.map_values(data, value_converters)
116
+ data.each_with_object({}) do |(k, v), new_hash|
117
+ converter = value_converters[k]
118
+ v = converter.convert(v) if converter
119
+ new_hash[k] = v
120
+ end
121
+ end
77
122
 
78
123
  def self.calculate_dynamic_value(value)
79
124
  test_value = value.split('!', 2)
80
125
  parameter = test_value[1].split('.', 2)
81
- case parameter[0]
82
- when 'Date'
83
- result = eval("Chronic.parse('#{parameter[1]}')")
84
- when 'FormattedDate', 'FormatDate'
85
- date_time_params = parameter[1].split(' format! ', 2)
86
- date_time = eval("Chronic.parse('#{date_time_params[0].strip}')")
87
- result = date_time.to_s.format_date_time("#{date_time_params[1].strip}")
88
- else
89
- result = if Faker.constants.include?(parameter[0].to_sym)
126
+ result = case parameter[0]
127
+ when 'Date'
128
+ Chronic.parse(parameter[1])
129
+ when 'FormattedDate', 'FormatDate'
130
+ date_time_params = parameter[1].split(' format! ', 2)
131
+ date_time = Chronic.parse(date_time_params[0].strip)
132
+ date_time.to_s.format_date_time("#{date_time_params[1].strip}")
133
+ else
134
+ if Faker.constants.include?(parameter[0].to_sym)
90
135
  eval("Faker::#{parameter[0]}.#{parameter[1]}")
91
136
  else
92
137
  eval(test_value[1])
93
138
  end
94
- end
139
+ end
95
140
  result.to_s
96
141
  end
97
142
  end
98
- # :nocov:
99
143
  end
100
144
 
145
+
146
+ # perform conversion of String to Boolean when reading data from .csv or .xml files
147
+ class ToBoolean
148
+ def self.convert(value)
149
+ value.to_bool unless value.nil?
150
+ end
151
+ end
152
+
153
+
154
+ # perform conversion of Integer to String when reading data from .csv or .xml files
155
+ class ToString
156
+ def self.convert(value)
157
+ if value.is_a? Integer
158
+ value.to_s
159
+ else
160
+ value
161
+ end
162
+ end
163
+ end
164
+
165
+
166
+ # perform conversion of String to Integer when reading data from .csv or .xml files
167
+ class ToInteger
168
+ def self.convert(value)
169
+ if value.is_a? Integer
170
+ value
171
+ else
172
+ if value.is_int?
173
+ value.to_i
174
+ else
175
+ value
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+
182
+ # perform conversion of String to Float when reading data from .csv or .xml files
183
+ class ToFloat
184
+ def self.convert(value)
185
+ if value.is_a? Float
186
+ value
187
+ else
188
+ if value.is_float?
189
+ value.to_f
190
+ else
191
+ value
192
+ end
193
+ end
194
+ end
195
+ end
@@ -1,9 +1,6 @@
1
1
  module TestCentricity
2
2
  class EnvironData < TestCentricity::DataSource
3
- attr_accessor :current
4
- attr_accessor :data_source_type
5
- attr_accessor :generic_data
6
- attr_accessor :environ_specific_data
3
+ attr_accessor :current, :data_source_type, :generic_data, :environ_specific_data
7
4
 
8
5
  def self.find_environ(environ_name, source_type = :yaml)
9
6
  raise 'No environment specified' if environ_name.nil?
@@ -23,8 +20,7 @@ module TestCentricity
23
20
  read('Environments', environ_name)
24
21
  when :json
25
22
  # read generic test data from data.json file
26
- raw_data = File.read(JSON_PRIMARY_DATA_FILE)
27
- @generic_data = JSON.parse(raw_data)
23
+ @generic_data = JSON.parse(File.read(JSON_PRIMARY_DATA_FILE))
28
24
  # read environment specific test data
29
25
  data_file = "#{PRIMARY_DATA_PATH}#{environ_name}_data.json"
30
26
  @environ_specific_data = if File.exist?(data_file)
@@ -42,27 +38,21 @@ module TestCentricity
42
38
  Environ.current = @current
43
39
  end
44
40
 
45
- def self.read(key_name, node_name)
46
- if @environ_specific_data.key?(key_name) && @environ_specific_data[key_name].key?(node_name)
47
- node_data = @environ_specific_data[key_name][node_name]
48
- else
49
- raise "No key named #{key_name} in generic and environment-specific data" unless @generic_data.key?(key_name)
50
- raise "No node named #{node_name} in #{key_name} section of generic and environment-specific data" unless @generic_data[key_name].key?(node_name)
51
-
52
- node_data = @generic_data[key_name][node_name]
53
- end
41
+ def self.read(key_name, node_name, options = nil)
42
+ node_data = if @environ_specific_data.key?(key_name) && @environ_specific_data[key_name].key?(node_name)
43
+ @environ_specific_data[key_name][node_name]
44
+ else
45
+ raise "No key named #{key_name} in generic and environment-specific data" unless @generic_data.key?(key_name)
46
+ raise "No node named #{node_name} in #{key_name} section of generic and environment-specific data" unless @generic_data[key_name].key?(node_name)
54
47
 
55
- if node_data.is_a?(Hash)
56
- node_data.each do |key, value|
57
- node_data[key] = calculate_dynamic_value(value) if value.to_s.start_with?('eval!')
58
- end
59
- end
60
- node_data
48
+ @generic_data[key_name][node_name]
49
+ end
50
+ process_data(node_data, options)
61
51
  end
62
52
  end
63
53
 
64
54
 
65
- class Environ < TestCentricity::DataObject
55
+ class Environ
66
56
  @session_id = Time.now.strftime('%d%H%M%S%L')
67
57
  @session_time_stamp = Time.now.strftime('%Y%m%d%H%M%S')
68
58
  @test_environment = ENV['TEST_ENVIRONMENT']
@@ -71,56 +61,8 @@ module TestCentricity
71
61
  @language = ENV['LANGUAGE'] || 'English'
72
62
  @screen_shots = []
73
63
 
74
- attr_accessor :test_environment
75
- attr_accessor :session_state
76
- attr_accessor :session_code
77
- attr_accessor :app_session_id
78
- attr_accessor :os
79
- attr_accessor :device
80
- attr_accessor :device_name
81
- attr_accessor :device_type
82
- attr_accessor :device_os
83
- attr_accessor :device_os_version
84
- attr_accessor :device_orientation
85
- attr_accessor :screen_size
86
- attr_accessor :platform
87
- attr_accessor :driver
88
- attr_accessor :driver_name
89
- attr_accessor :appium_driver
90
- attr_accessor :tunneling
91
- attr_accessor :locale
92
- attr_accessor :language
93
-
94
- attr_accessor :parallel
95
- attr_accessor :process_num
96
-
97
- attr_accessor :signed_in
98
- attr_accessor :portal_status
99
- attr_accessor :portal_context
100
-
101
- attr_accessor :user_id
102
- attr_accessor :password
103
- attr_accessor :app_id
104
- attr_accessor :api_key
105
- attr_accessor :option1
106
- attr_accessor :option2
107
- attr_accessor :option3
108
- attr_accessor :option4
109
- attr_accessor :dns
110
- attr_accessor :db_username
111
- attr_accessor :db_password
112
-
113
- attr_accessor :ios_app_path
114
- attr_accessor :ios_ipa_path
115
- attr_accessor :ios_bundle_id
116
- attr_accessor :ios_test_id
117
- attr_accessor :android_apk_path
118
- attr_accessor :android_app_id
119
- attr_accessor :android_test_id
120
- attr_accessor :default_max_wait_time
121
- attr_accessor :deep_link_prefix
122
-
123
- attr_accessor :mac_bundle_id
64
+ attr_accessor :current
65
+ attr_accessor :test_environment, :session_state, :session_code, :app_session_id, :os, :device, :device_name, :device_type, :device_os, :device_os_version, :device_orientation, :screen_size, :platform, :driver, :driver_name, :appium_driver, :tunneling, :locale, :language, :parallel, :process_num, :signed_in, :portal_status, :portal_context, :user_id, :password, :app_id, :api_key, :option1, :option2, :option3, :option4, :dns, :db_username, :db_password, :ios_app_path, :ios_ipa_path, :ios_bundle_id, :ios_test_id, :android_apk_path, :android_app_id, :android_test_id, :default_max_wait_time, :deep_link_prefix, :mac_bundle_id
124
66
 
125
67
  def initialize(data)
126
68
  @user_id = data['USER_ID']
@@ -143,8 +85,14 @@ module TestCentricity
143
85
  @android_test_id = data['ANDROID_TEST_ID']
144
86
  @deep_link_prefix = data['DEEP_LINK_PREFIX']
145
87
  @mac_bundle_id = data['MAC_BUNDLE_ID']
88
+ end
89
+
90
+ def self.current
91
+ @current
92
+ end
146
93
 
147
- super
94
+ def self.current=(current)
95
+ @current = current
148
96
  end
149
97
 
150
98
  def self.new_app_session
@@ -1,7 +1,6 @@
1
1
  module TestCentricity
2
2
  class ExceptionQueue
3
- attr_accessor :error_queue
4
- attr_accessor :active_ui_element
3
+ attr_accessor :error_queue, :active_ui_element
5
4
 
6
5
  def self.enqueue_assert_equal(expected, actual, error_message)
7
6
  is_equal = if expected.is_a?(String) && actual.is_a?(String)
@@ -9,17 +8,17 @@ module TestCentricity
9
8
  else
10
9
  expected == actual
11
10
  end
12
- unless is_equal
13
- enqueue("#{error_message} to be\n '#{expected}'\nbut found\n '#{actual}'")
14
- enqueue_screenshot
15
- end
11
+ return if is_equal
12
+
13
+ enqueue("#{error_message} to be\n '#{expected}'\nbut found\n '#{actual}'")
14
+ enqueue_screenshot
16
15
  end
17
16
 
18
17
  def self.enqueue_assert_not_equal(expected, actual, error_message)
19
- unless expected != actual
20
- enqueue("#{error_message} to not be equal to '#{expected}'")
21
- enqueue_screenshot
22
- end
18
+ return if expected != actual
19
+
20
+ enqueue("#{error_message} to not be equal to '#{expected}'")
21
+ enqueue_screenshot
23
22
  end
24
23
 
25
24
  def self.enqueue_exception(error_message)
@@ -17,6 +17,7 @@ class String
17
17
  def to_bool
18
18
  return true if self == true || self =~ (/(true|t|yes|y|x|1)$/i)
19
19
  return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
20
+
20
21
  raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
21
22
  end
22
23
 
@@ -1,3 +1,3 @@
1
1
  module TestCentricityApps
2
- VERSION = '4.0.15'
2
+ VERSION = '4.1.1'
3
3
  end
@@ -27,6 +27,7 @@ require 'testcentricity_apps/app_elements/menubar'
27
27
  require 'testcentricity_apps/app_elements/radio'
28
28
  require 'testcentricity_apps/app_elements/selectlist'
29
29
  require 'testcentricity_apps/app_elements/switch'
30
+ require 'testcentricity_apps/app_elements/table'
30
31
  require 'testcentricity_apps/app_elements/textfield'
31
32
 
32
33
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: testcentricity_apps
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.15
4
+ version: 4.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - A.J. Mrozinski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-13 00:00:00.000000000 Z
11
+ date: 2026-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 9.2.0
33
+ version: 10.2.0
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 9.2.0
40
+ version: 10.2.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: parallel_tests
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: 3.13.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: selenium-webdriver
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 4.39.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 4.39.0
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: simplecov
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -122,20 +136,34 @@ dependencies:
122
136
  - - ">="
123
137
  - !ruby/object:Gem::Version
124
138
  version: 0.9.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: activesupport
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '4.0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '4.0'
125
153
  - !ruby/object:Gem::Dependency
126
154
  name: appium_lib
127
155
  requirement: !ruby/object:Gem::Requirement
128
156
  requirements:
129
157
  - - "~>"
130
158
  - !ruby/object:Gem::Version
131
- version: 15.2.2
159
+ version: 16.1.1
132
160
  type: :runtime
133
161
  prerelease: false
134
162
  version_requirements: !ruby/object:Gem::Requirement
135
163
  requirements:
136
164
  - - "~>"
137
165
  - !ruby/object:Gem::Version
138
- version: 15.2.2
166
+ version: 16.1.1
139
167
  - !ruby/object:Gem::Dependency
140
168
  name: childprocess
141
169
  requirement: !ruby/object:Gem::Requirement
@@ -207,19 +235,19 @@ dependencies:
207
235
  - !ruby/object:Gem::Version
208
236
  version: '0'
209
237
  - !ruby/object:Gem::Dependency
210
- name: selenium-webdriver
238
+ name: smarter_csv
211
239
  requirement: !ruby/object:Gem::Requirement
212
240
  requirements:
213
- - - '='
241
+ - - ">="
214
242
  - !ruby/object:Gem::Version
215
- version: 4.26.0
243
+ version: '0'
216
244
  type: :runtime
217
245
  prerelease: false
218
246
  version_requirements: !ruby/object:Gem::Requirement
219
247
  requirements:
220
- - - '='
248
+ - - ">="
221
249
  - !ruby/object:Gem::Version
222
- version: 4.26.0
250
+ version: '0'
223
251
  - !ruby/object:Gem::Dependency
224
252
  name: test-unit
225
253
  requirement: !ruby/object:Gem::Requirement
@@ -281,6 +309,7 @@ files:
281
309
  - lib/testcentricity_apps/app_elements/radio.rb
282
310
  - lib/testcentricity_apps/app_elements/selectlist.rb
283
311
  - lib/testcentricity_apps/app_elements/switch.rb
312
+ - lib/testcentricity_apps/app_elements/table.rb
284
313
  - lib/testcentricity_apps/app_elements/textfield.rb
285
314
  - lib/testcentricity_apps/appium_server.rb
286
315
  - lib/testcentricity_apps/data_objects/data_objects_helper.rb
@@ -306,7 +335,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
306
335
  requirements:
307
336
  - - ">="
308
337
  - !ruby/object:Gem::Version
309
- version: 3.0.0
338
+ version: 3.1.0
310
339
  required_rubygems_version: !ruby/object:Gem::Requirement
311
340
  requirements:
312
341
  - - ">="
@@ -314,7 +343,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
314
343
  version: '0'
315
344
  requirements:
316
345
  - Appium
317
- rubygems_version: 3.3.26
346
+ rubygems_version: 3.4.10
318
347
  signing_key:
319
348
  specification_version: 4
320
349
  summary: A Screen Object Model Framework for MacOS desktop app and iOS and/or Android