zander 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3875d0299b3297f68eaa7e38a203019569f21a83
4
+ data.tar.gz: c0a8da31fe54b84197cc417c763e87fc8a99206c
5
+ SHA512:
6
+ metadata.gz: a532118b690fd416ad00181a5383ad1d2aea20b1cb547daedf52051ed7b7276fd8fda7e63b591c0bf4da3df8b98436a650e83cc78e55caae3ad0718f0ffd7918
7
+ data.tar.gz: 243f56c183f86eb198a7630964994530b86cb2df4e3eef1a688206630abd971b31ffdfa5e22e182f51fc434128cd4fb48d3f9f4c18f989981037100c21489265
data/.gitignore ADDED
@@ -0,0 +1,38 @@
1
+ share/html_v2.yaml
2
+ share/chromedriver
3
+
4
+ *.gem
5
+ *.rbc
6
+ /.config
7
+ /coverage/
8
+ /InstalledFiles
9
+ /pkg/
10
+ /spec/reports/
11
+ /test/tmp/
12
+ /test/version_tmp/
13
+ /tmp/
14
+
15
+ ## Specific to RubyMotion:
16
+ .dat*
17
+ .repl_history
18
+ build/
19
+
20
+ ## Documentation cache and generated files:
21
+ /.yardoc/
22
+ /_yardoc/
23
+ /doc/
24
+ /rdoc/
25
+
26
+ ## Environment normalisation:
27
+ /.bundle/
28
+ /lib/bundler/man/
29
+
30
+ # for a library or gem, you might want to ignore these files since the code is
31
+ # intended to run in multiple environments; otherwise, check them in:
32
+ # Gemfile.lock
33
+ # .ruby-version
34
+ # .ruby-gemset
35
+
36
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
37
+ .rvmrc
38
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ gem 'selenium-webdriver', '~> 2.43.0'
3
+ gem 'json', '~> 1.8.1'
4
+ #gem 'prawn', '~> 1.3.0'
5
+ gem 'pdfkit', '~> 0.6.2'
6
+ gem 'yard', '~> 0.8.7.6'
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Spencer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ Streamline Selenium WebDriver Testing with Zander
2
+ ---
data/bin/zander ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ #######################################################################################################
3
+ # This executable file is an example three ways to properly use 'zander'. #
4
+ # 1.) Demo version #
5
+ # Simply run this executable file. #
6
+ # $ ./zander #
7
+ # #
8
+ # The demo version will use the fiels provided in the gem's share directory. #
9
+ # share/sites.yaml #
10
+ # share/actions.yaml #
11
+ # #
12
+ # These files attempt to log on to a google account. #
13
+ # The user name and password are invalid, and the sign in will fail #
14
+ # #
15
+ # 2.) Custom files version #
16
+ # You must provid both the sites.yaml and actions.yaml #
17
+ # #
18
+ # #
19
+ # 3.) Specific version #
20
+ # This version allows you to provide an array of the websites you want exectued #
21
+ # [0] will only execute the actions for the first URL #
22
+ # [0,1] will execute the actions for the first two URLs, etc #
23
+ # #
24
+ # Note: In some cases full control over the driver and loggin is required #
25
+ # Include the Zander::Manual module which has the @@driver and @@log variables #
26
+ # overide the self.drive method and make sure to add a 'manual' call in your actions.yaml #
27
+ # a full example is shown at the bottom #
28
+ # #
29
+ #######################################################################################################
30
+ #require 'zander'
31
+ require '/Users/sc/projects/ruby/appeals/lib/zander'
32
+ #######################################################################################################
33
+ ### 1.) Demo - Uses share/sites.yaml and shre/actions.yaml ###
34
+ Zander.run ###
35
+ #######################################################################################################
36
+
37
+ #######################################################################################################
38
+ ### 2.) Custom files - Example specifying script fiels ###
39
+ #DIR = File.join((File.expand_path('../', File.expand_path(File.dirname(__FILE__)))), "/share/") ###
40
+ #Zander.run(sites: "#{DIR}sites.yaml", actions: "#{DIR}actions.yaml") ###
41
+ #######################################################################################################
42
+
43
+ #######################################################################################################
44
+ ### 3.) Specific - Eample specifing which URL entries to process ###
45
+ #Zander.run(sites: "#{DIR}sites.yaml", actions: "#{DIR}actions.yaml", steps: [0]) ###
46
+ #######################################################################################################
47
+
48
+ #######################################################################################################
49
+ ### Example file that uses the manual driving method ###
50
+ #######################################################################################################
51
+ # require 'zander' #
52
+ # include Zander::Manual #
53
+ # Zander::Manual.module_eval do #
54
+ # def self.drive #
55
+ # driver = @@driver #
56
+ # log = @@log #
57
+ # log.debug("I got the logger and the driver") #
58
+ # log.debug("current url: #{driver.current_url}") #
59
+ # end #
60
+ # end #
61
+ # Zander.run #
62
+ #######################################################################################################
data/lib/zander.rb ADDED
@@ -0,0 +1,59 @@
1
+ #####################################################################################################################
2
+ # ZANDER THE GREAT #
3
+ # ,__ #
4
+ # | `'. #
5
+ # __ |`-._/_.:---`-.._ #
6
+ # \='. _/..--'`__ `'-._ #
7
+ # \- '-.--"` === / o `', #
8
+ # )= ( .--_ | _.' #
9
+ # /_=.'-._ {=_-_ | .--`-. #
10
+ # /_.' `\`'-._ '-= \ _.' #
11
+ # ) _.-'`'-.. _..-'` #
12
+ # /_.' `/";';`| #
13
+ # \` .'/ #
14
+ # '--' #
15
+ # #
16
+ # Zander is a framerwork for facilitating automated Selenium webdriver testing #
17
+ # URLs and corrisponding log in credentials are defined in the share/sites.yaml #
18
+ # The actions to be taken and the element identifiers are defined in share/actions.yaml #
19
+ #####################################################################################################################
20
+ lib = File.expand_path('../../lib/', __FILE__)
21
+ $:.unshift lib unless $:.include?(lib)
22
+ # p $:.dup
23
+
24
+ module Zander
25
+ def self.run(sites: nil, actions: nil, steps: nil)
26
+
27
+ if steps == nil
28
+ steps = ARGV[0].split(',').map(&:to_i) unless ARGV[0] == nil
29
+ end
30
+
31
+ if (sites != nil && actions != nil)
32
+ zander = Sites.new(sites,steps)
33
+ zander.add_actions(actions)
34
+ else
35
+ zander = Sites.new(Util.get_path('share/sites.yaml'),steps)
36
+ zander.add_actions(Util.get_path('share/actions.yaml'))
37
+ end
38
+
39
+ zander.set_log_level Logger::DEBUG
40
+ zander.sites.each do |site|
41
+ site.drive
42
+ end
43
+
44
+ end
45
+ end
46
+ require 'zander/cmd_mapper'
47
+ require 'zander/sites'
48
+ require 'zander/action'
49
+ require 'zander/manual'
50
+ require 'zander/site'
51
+ require 'zander/util'
52
+ require 'zander/ht'
53
+
54
+ require 'selenium-webdriver'
55
+ require 'yaml'
56
+ require 'logger'
57
+
58
+
59
+
@@ -0,0 +1,225 @@
1
+ module Zander
2
+ class Action
3
+
4
+ def initialize(site, driver, log, hash)
5
+ @site = site
6
+ @log = log
7
+ @driver = driver
8
+ @private_variable = false
9
+ parse_before_action(hash)
10
+ parse_action_type(hash)
11
+ parse_after_action(hash)
12
+ @log.debug("Created #{self.class.name} #{self}")
13
+ end
14
+
15
+ def private_variable?
16
+ @private_variable
17
+ end
18
+
19
+ def parse_before_action(hash)
20
+ if hash.has_key?(:before_action)
21
+ @before_action = hash[:before_action]
22
+ end
23
+ end
24
+
25
+ def parse_after_action(hash)
26
+ if hash.has_key?(:after_action)
27
+ @after_action = hash[:after_action]
28
+ end
29
+ end
30
+
31
+ def parse_action_type(hash)
32
+ if hash.has_key? :action_type
33
+ @action_type = hash[:action_type]
34
+ parse_type(hash)
35
+ end
36
+ end
37
+
38
+ def parse_type(hash)
39
+ case @action_type
40
+ when 'click_element','print_element','switch_to_iframe'
41
+ set_identifier(hash)
42
+ when 'input_variable'
43
+ set_identifier(hash)
44
+ set_variable(hash)
45
+ when 'input_data'
46
+ set_identifier(hash)
47
+ set_data(hash)
48
+ when 'done','switch_to_new_window'
49
+ else
50
+ @log.error("#{__method__} can't handle action_type #{@action_type} for #{self}")
51
+ end
52
+ end
53
+
54
+ def set_identifier(hash)
55
+ if hash.has_key? :identifier
56
+ identifier = hash[:identifier]
57
+ @finder_key = identifier.keys[0]
58
+ @finder_value = identifier.values[0]
59
+ end
60
+ end
61
+
62
+ def set_variable(hash)
63
+ if hash.has_key? :variable
64
+ @private_variable = true if hash[:variable] == "password"
65
+ @variable = @site.instance_variable_get("@#{hash[:variable]}".to_sym)
66
+ end
67
+ end
68
+
69
+ def set_data(hash)
70
+ if hash.has_key? :data
71
+ @data = hash[:data]
72
+ end
73
+ end
74
+
75
+ def drive
76
+ element = get_element
77
+ do_action(element)
78
+ sleep(1)
79
+ end
80
+
81
+ def get_element
82
+ case @action_type
83
+ when 'click_element', 'input_variable', 'print_element','switch_to_iframe', 'input_data'
84
+ get_element_from_finders
85
+ when 'done','switch_to_new_window'
86
+ else
87
+ @log.error("Can't handle action_type #{@action_type} for #{self}")
88
+ end
89
+ end
90
+
91
+ def get_element_from_finders
92
+ if @finder_key != nil
93
+ @log.debug("Find element #{@finder_key}='#{@finder_value}'")
94
+ case @finder_key
95
+ when :id,:name,:xpath
96
+ element = @driver.find_element(@finder_key => @finder_value)
97
+ when :css
98
+ when :class
99
+ # could be multiple // might need to add a n: 0
100
+ element = @driver.find_element(@finder_key => @finder_value)
101
+ when :class_name
102
+ when :link
103
+ when :link_text
104
+ when :partial_link_text
105
+ when :tag_name
106
+ else
107
+ @log.error("#{__method__} invalid finder_key, must be a Selenium::WebDriver::SearchContext::FINDERS:")
108
+ @log.error(Selenium::WebDriver::SearchContext::FINDERS.keys)
109
+ end
110
+ else
111
+ @log.error("#{__method__} tried to locate element, but @finder_key == nil")
112
+ end
113
+ element
114
+ end
115
+
116
+ def get_elements_from_finders
117
+ if @finder_key != nil
118
+ @log.debug("Find elements #{@finder_key}='#{@finder_value}'")
119
+ case @finder_key
120
+ when :id
121
+ element = @driver.find_elements(@finder_key => @finder_value)
122
+ when :xpath
123
+ element = @driver.find_elements(:xpath, identifier[:xpath])
124
+ when :css
125
+ when :class
126
+ when :class_name
127
+ when :name
128
+ when :link
129
+ when :link_text
130
+ when :partial_link_text
131
+ when :tag_name
132
+ else
133
+ @log.error("#{__method__} invalid finder_key, must be a Selenium::WebDriver::SearchContext::FINDERS:")
134
+ @log.error(Selenium::WebDriver::SearchContext::FINDERS.keys)
135
+ end
136
+ else
137
+ @log.error("#{__method__} tried to locate element, but @finder_key == nil")
138
+ end
139
+ element
140
+ end
141
+
142
+ def do_action(element)
143
+ @log.debug("try #{@action_type} #{@finder_key}='#{@finder_value}'")
144
+ case @action_type
145
+ when 'click_element'
146
+ element.click
147
+ when 'input_variable'
148
+ @log.info("Send '#{masked_variable}' to #{@finder_key}='#{@finder_value}' element")
149
+ element.clear
150
+ element.send_keys @variable
151
+ when 'print_element'
152
+ @log.info("text: #{element.text}
153
+ \t\ttag_name: #{element.tag_name}
154
+ \t\tlocation: (#{element.location.x},#{element.location.y})")
155
+ when 'input_data'
156
+ @log.info("Send '#{@data}' to #{@finder_key}='#{@finder_value}' element")
157
+ element.clear
158
+ element.send_keys @data
159
+ when 'switch_to_iframe'
160
+ @log.error("Can't locate iframe with #{@finder_key}='#{@finder_value}'. iframe can only be located via 'id'") unless @finder_key == :id
161
+ @driver.switch_to.frame(@finder_value)
162
+ sleep(3)
163
+ when 'switch_to_new_window'
164
+ @log.debug("'main_window' saved")
165
+ main_window = @driver.window_handle
166
+ new_window = nil
167
+ @driver.window_handles.each do |window|
168
+ if main_window != nil && main_window != window
169
+ new_window = window
170
+ end
171
+ end
172
+ @log.error("Couldn't find new window") if new_window == nil
173
+ @driver.switch_to.window(new_window)
174
+ @log.debug("Switched to new window #{driver.current_url}")
175
+ close_other_windows
176
+ when 'done'
177
+ close_other_windows
178
+ @driver.quit if @site.last?
179
+ else
180
+ @log.error("Could not preform action #{@action_type} on #{@finder_key}='#{@finder_value}' element")
181
+ end
182
+ @log.info("#{@action_type} #{@finder_key}='#{@finder_value}'")
183
+ end
184
+
185
+ def close_other_windows
186
+ main_window = @driver.window_handle
187
+ @driver.window_handles.each do |other_window|
188
+ if main_window != nil && main_window != other_window
189
+ @driver.switch_to.window(other_window)
190
+ url = @driver.current_url
191
+ @driver.close
192
+ @log.debug("Closed window '#{url}'")
193
+ end
194
+ end
195
+ @driver.switch_to.window(main_window)
196
+ end
197
+
198
+ def masked_variable
199
+ if private_variable?
200
+ clear = 3 #keep last 3 in clear text
201
+ masked = @variable[0];
202
+ (@variable.length-(clear+1)).times do
203
+ masked << '*'
204
+ end
205
+ masked << @variable[(@variable.length-clear)...@variable.length]
206
+ else
207
+ @variable
208
+ end
209
+ end
210
+
211
+ def inspect
212
+ to_s
213
+ end
214
+
215
+ def to_s
216
+ "<#{self.class.name}:0x#{'%x'%(self.object_id<<1)} @site=<Site:0x#{'%x'%(@site.object_id<<1)} ...> @action_type=#{@action_type} >"
217
+ end
218
+
219
+ private :to_s, :masked_variable, :close_other_windows
220
+ private :do_action, :get_element_from_finders, :get_elements_from_finders
221
+ private :get_element, :set_data, :set_variable, :set_identifier
222
+ private :parse_after_action, :parse_action_type, :parse_before_action
223
+ private :private_variable?
224
+ end
225
+ end
@@ -0,0 +1,21 @@
1
+ module Zander
2
+ module CommandMapper
3
+ def self.map(site, driver, log, cmd)
4
+ @site = site
5
+ @driver = driver
6
+ @log = log
7
+ @cmd = cmd
8
+ if cmd.is_a?(Hash)
9
+ if cmd.has_key? :action
10
+ Action.new(@site, @driver, @log, @cmd)
11
+ elsif cmd.has_key? :manual
12
+ Manual.set(@driver, @log)
13
+ Manual.drive
14
+ Manual.destroy
15
+ else
16
+ @log.error("Can't mapp comand for #{cmd.inspect}")
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/zander/ht.rb ADDED
@@ -0,0 +1,20 @@
1
+ # Hash Tools
2
+ class Hash
3
+ def change_keys(hash)
4
+ hash.each do |key,value|
5
+ if !key.is_a?(Hash) && !value.is_a?(Hash)
6
+ hash = hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
7
+ else
8
+ hash.map{ |k,v| hash[k] = change_keys(v) if v.is_a?(Hash) }
9
+ end
10
+ end
11
+ hash = hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
12
+ end
13
+
14
+
15
+ def keys_to_sym
16
+ change_keys(self)
17
+ end
18
+
19
+ private :change_keys
20
+ end
@@ -0,0 +1,17 @@
1
+ module Zander
2
+ module Manual
3
+ def self.set(driver, log)
4
+ @@driver = driver
5
+ @@log = log
6
+ end
7
+
8
+ def self.drive
9
+ ## empty method to implement
10
+ end
11
+
12
+ def self.destroy
13
+ @@driver = nil
14
+ @@log = nil
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,90 @@
1
+ module Zander
2
+ class Site
3
+
4
+ def initialize(parent:, hash:, driver:, log:)
5
+ @actions = Array.new
6
+ @parent = parent unless parent == nil
7
+ @log = log unless log == nil
8
+ @driver = driver unless driver == nil
9
+ create_attr_accessor(hash)
10
+ @log.debug("Created #{self}")
11
+ end
12
+
13
+ def get_variables
14
+ Hash[instance_variables.map { |name| [name, instance_variable_get(name)] } ]
15
+ end
16
+
17
+ # Map each hash in actions array with CommandMapper.
18
+ # If the result is an Action object, add it to the acctions array
19
+ def add_actions(actions)
20
+ actions.each do |action|
21
+ # convert keys in action hash to symbols
22
+ puts "Action Hash::: #{action}"
23
+ action = action.keys_to_sym
24
+ @log.debug("Create action #{action}")
25
+ obj = CommandMapper.map(self, @driver, @log, action)
26
+ @actions.push(obj) if obj.is_a?(Action)
27
+ end
28
+ end
29
+
30
+ # Is this instance the last Site object defined in share/sites.yaml
31
+ def last?
32
+ @url != nil && @parent.sites.last.respond_to?(:url) && @parent.sites.last.url == @url
33
+ end
34
+
35
+ def drive()
36
+ @driver.navigate.to self.url
37
+ @log.info("Opened #{@driver.current_url}")
38
+ @actions.each do |action|
39
+ action.drive
40
+ end
41
+ end
42
+
43
+ # Creates instance variables for each key value in a given hash
44
+ # { url => 'www.google.com', user_name => 'coolUser', password => 'secretPassword' }
45
+ # would create the following instance variables
46
+ # @url = 'www.google.com'
47
+ # @user_name = 'coolUser'
48
+ # @password = 'secretPassword'
49
+ def create_attr_accessor(hash)
50
+ hash.each do |key,value|
51
+ value = value.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} if value.is_a?(Hash)
52
+ instance_variable_set("@#{key}", value)
53
+ self.class.__send__(:attr_accessor, "#{key}")
54
+ self.__send__("#{key}=", value)
55
+ end
56
+ end
57
+
58
+ # Helper method for to_s
59
+ # returns a pretty string of all the actions
60
+ def get_vars
61
+ vars = ""
62
+ vh = Hash[self.instance_variables.map {|name|[name, instance_variable_get(name)]}]
63
+ vh.each_with_index do |(key,value), index|
64
+ if key.to_s == "@parent"
65
+ vars << @parent.get_abbr_to_s
66
+ elsif key.to_s == "@actions"
67
+ @actions.each do |action|
68
+ vars << action.to_s
69
+ end
70
+ elsif index == vh.size - 1
71
+ vars << "#{key}=\"#{value}\""
72
+ else
73
+ "#{key}=\"#{value}\", "
74
+ end
75
+ end
76
+ vars
77
+ end
78
+
79
+ def inspect
80
+ to_s
81
+ end
82
+
83
+ def to_s
84
+ "<#{self.class.name}:0x#{'%x'%(self.object_id<<1)} #{get_vars}"
85
+ end
86
+
87
+ private :to_s, :get_vars, :create_attr_accessor, :get_variables
88
+
89
+ end
90
+ end
@@ -0,0 +1,88 @@
1
+ module Zander
2
+ class Sites
3
+ IMPLICIT_WAIT = 10
4
+ YAML_URL = 'URL'
5
+ YAML_ACTIONS = 'ACTIONS'
6
+ LOG_FILE = STDOUT # 'log.txt'
7
+
8
+ attr_reader :sites
9
+
10
+ def initialize(yaml_file, steps = nil)
11
+ @sites_yaml_file = yaml_file
12
+ @log = Logger.new(LOG_FILE,10,1024000)
13
+ @log.level = Logger::DEBUG
14
+ @sites = Array.new
15
+ ### FIREFOX PROFILE
16
+ profile = Selenium::WebDriver::Firefox::Profile.new
17
+ profile['browser.download.dir'] = '/Users/sc/Desktop/appeals/HCFA_AND_POTF'
18
+ profile['browser.download.folderList'] = 2
19
+ profile['browser.helperApps.neverAsk.saveToDisk'] = "application/pdf"
20
+ profile['browser.download.alertOnEXEOpen'] = false
21
+ profile['browser.download.manager.showWhenStarting'] = false
22
+ profile['browser.download.manager.focusWhenStarting'] = false
23
+ profile['browser.helperApps.alwaysAsk.force'] = false
24
+ profile['browser.download.manager.alertOnEXEOpen'] = false
25
+ profile['browser.download.manager.closeWhenDone'] = false
26
+ profile['browser.download.manager.showAlertOnComplete'] = false
27
+ profile['browser.download.manager.useWindow'] = false
28
+ profile['browser.download.manager.showWhenStarting'] = false
29
+ profile['services.sync.prefs.sync.browser.download.manager.showWhenStarting'] = false
30
+ profile['pdfjs.disabled'] = true
31
+ ## END FIREFOX PROFILE
32
+ @driver = Selenium::WebDriver.for :firefox, :profile => profile
33
+ @driver.manage.timeouts.implicit_wait = IMPLICIT_WAIT
34
+ @log.debug("Selenium timeouts set to #{IMPLICIT_WAIT} seconds")
35
+ yaml = YAML::load(File.read(@sites_yaml_file))
36
+ if yaml.has_key? 'WEBSITES'
37
+ yaml['WEBSITES'].each_with_index do |site, index|
38
+ if steps == nil
39
+ @log.debug("Create Site #{site}")
40
+ @sites.push(Site.new(parent: self, hash: site, driver: @driver, log: @log))
41
+ else
42
+ if steps.include?(index)
43
+ @log.debug("Create Site #{site}")
44
+ @sites.push(Site.new(parent: self, hash: site, driver: @driver, log: @log))
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
51
+
52
+ def set_log_level(level)
53
+ @log.level = level
54
+ end
55
+
56
+ def get_site(url)
57
+ @sites.each do |site|
58
+ return site if site.url == url
59
+ end
60
+ nil
61
+ end
62
+
63
+ def get_abbr_to_s
64
+ "<#{self.class.name}:0x#{'%x'%(self.object_id<<1)} ...>"
65
+ end
66
+
67
+ def add_actions(yaml_file)
68
+ yaml = YAML::load(File.read(yaml_file))
69
+ if yaml.has_key? 'WEBSITES'
70
+ yaml['WEBSITES'].each do |website|
71
+ if website.has_key?(YAML_URL) && website.has_key?(YAML_ACTIONS)
72
+ site = self.get_site(website[YAML_URL])
73
+ if site != nil
74
+ @log.debug("Add #{website[YAML_ACTIONS]}")
75
+ site.add_actions(website[YAML_ACTIONS])
76
+ else
77
+ @log.error("Error:: '#{website[YAML_URL]}' in #{yaml_file} was not in #{@sites_yaml_file}")
78
+ end
79
+ else
80
+ @log.error("#{yaml_file} doesn't contain a #{YAML_URL} array")
81
+ end
82
+ end
83
+ else
84
+ @log.error("#{yaml_file} doesn't contain a WEBSITES array")
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,8 @@
1
+ # Utility helpers
2
+ module Zander
3
+ module Util
4
+ def self.get_path(file_name)
5
+ File.join((File.expand_path('../../', File.expand_path(File.dirname(__FILE__)))), file_name)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module Zander
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,56 @@
1
+ ##
2
+ # Attribues is a hash of hashes the first hash will always be the way to identify an
3
+ # html tag ie (id: user_id or class: members) The action hash will consist of a simple action like click
4
+ # or could contain a complex action like input which will contain a field that mapps to a website object
5
+ #
6
+ # Gmail login example:
7
+ #WEBSTIES:
8
+ # - URL: https://accounts.google.com
9
+ # id: Email
10
+ # action:
11
+ # - variable: user_name
12
+ # id: Passwd
13
+ # action:
14
+ # - variable: password
15
+ # id: signIn
16
+ # action: click
17
+ # This yaml file would know that for https://accounts.google.com it should find the html attribute
18
+ # <input id="Email" name="Email" placeholder="Email" value="" spellcheck="false" class="" type="email">
19
+ # and insert the WebSite#user_name value
20
+ #
21
+ ##
22
+ WEBSITES:
23
+ - URL: https://www.google.com/
24
+ ACTIONS:
25
+ - action:
26
+ action_type: click_element
27
+ identifier:
28
+ id: gb_70
29
+ - action:
30
+ action_type: print_element
31
+ identifier:
32
+ class: tagline
33
+ - action:
34
+ action_type: input_variable
35
+ identifier:
36
+ id: Email
37
+ variable: user_name
38
+ - action:
39
+ action_type: input_variable
40
+ identifier:
41
+ id: Passwd
42
+ variable: password
43
+ - action:
44
+ action_type: click_element
45
+ identifier:
46
+ id: signIn
47
+ - manual:
48
+ - action:
49
+ action_type: done
50
+ # - URL:
51
+ # ATTRIBUTES:
52
+ # - identifier:
53
+ # id:
54
+ # action:
55
+ # - identifier:
56
+ # action: done
data/share/sites.yaml ADDED
@@ -0,0 +1,17 @@
1
+ #############################################
2
+ # Browsie can handle multiple arguements all
3
+ # that is required is that each email have
4
+ # corresponding password, and that each
5
+ # argument have a space followed by a '-'
6
+ # followed by another space, then the argument
7
+ #
8
+ # If you don't have one or both of these accounts
9
+ # delete out the keywords and arguments alltogether.
10
+ #############################################
11
+ WEBSITES:
12
+ - url: https://www.google.com/
13
+ user_name: "Replace this with your username"
14
+ password: "Replace this with your password"
15
+ # - url:
16
+ # user_name:
17
+ # password:
data/zander.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require 'zander/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'zander'
8
+ s.version = Zander::VERSION
9
+ s.date = '2014-11-13'
10
+ s.licenses = ['MIT']
11
+ s.summary = "Simple Web Automation"
12
+ s.description = "Zabner will help automate web testing using Selenium::WebDriver"
13
+ s.authors = ["Spencer Carlson"]
14
+ s.email = 'spencerdcarlson@gmail.com'
15
+ s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ s.executables = %w(zander)
17
+ s.homepage = ''
18
+ s.require_paths = %w(lib)
19
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zander
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Spencer Carlson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-13 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Zabner will help automate web testing using Selenium::WebDriver
14
+ email: spencerdcarlson@gmail.com
15
+ executables:
16
+ - zander
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - Gemfile
22
+ - LICENSE
23
+ - README.md
24
+ - bin/zander
25
+ - lib/zander.rb
26
+ - lib/zander/action.rb
27
+ - lib/zander/cmd_mapper.rb
28
+ - lib/zander/ht.rb
29
+ - lib/zander/manual.rb
30
+ - lib/zander/site.rb
31
+ - lib/zander/sites.rb
32
+ - lib/zander/util.rb
33
+ - lib/zander/version.rb
34
+ - share/actions.yaml
35
+ - share/sites.yaml
36
+ - zander.gemspec
37
+ homepage: ''
38
+ licenses:
39
+ - MIT
40
+ metadata: {}
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubyforge_project:
57
+ rubygems_version: 2.2.2
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Simple Web Automation
61
+ test_files: []
62
+ has_rdoc: