howitzer 0.0.3 → 1.0.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.
- data/.gitignore +8 -0
- data/.rspec +3 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +32 -0
- data/GETTING_STARTED.md +529 -0
- data/Gemfile +4 -2
- data/LICENSE +2 -2
- data/README.md +57 -13
- data/Rakefile +9 -2
- data/bin/howitzer +79 -31
- data/generators/base_generator.rb +87 -0
- data/generators/config/config_generator.rb +16 -20
- data/generators/config/templates/default.yml +26 -7
- data/generators/cucumber/cucumber_generator.rb +20 -26
- data/generators/{tasks → cucumber}/templates/cucumber.rake +0 -0
- data/generators/{config → cucumber}/templates/cucumber.yml +0 -0
- data/generators/emails/emails_generator.rb +11 -18
- data/generators/emails/templates/example_email.rb +1 -0
- data/generators/pages/pages_generator.rb +16 -18
- data/generators/pages/templates/example_menu.rb +1 -0
- data/generators/pages/templates/example_page.rb +1 -1
- data/generators/root/root_generator.rb +18 -20
- data/generators/root/templates/.gitignore +2 -1
- data/generators/root/templates/Gemfile +3 -2
- data/generators/root/templates/Rakefile +10 -0
- data/generators/root/templates/boot.rb +3 -9
- data/generators/rspec/rspec_generator.rb +23 -0
- data/generators/rspec/templates/example_spec.rb +7 -0
- data/generators/rspec/templates/rspec.rake +34 -0
- data/generators/rspec/templates/spec_helper.rb +56 -0
- data/generators/tasks/tasks_generator.rb +11 -17
- data/generators/tasks/templates/common.rake +15 -0
- data/howitzer.gemspec +13 -2
- data/lib/howitzer.rb +1 -0
- data/lib/howitzer/helpers.rb +87 -2
- data/lib/howitzer/init.rb +0 -1
- data/lib/howitzer/patches/rawler_patched.rb +86 -0
- data/lib/howitzer/settings.rb +27 -0
- data/lib/howitzer/utils.rb +3 -12
- data/lib/howitzer/utils/capybara_patched.rb +3 -2
- data/lib/howitzer/utils/capybara_settings.rb +158 -24
- data/lib/howitzer/utils/data_generator/data_storage.rb +35 -1
- data/lib/howitzer/utils/data_generator/gen.rb +45 -3
- data/lib/howitzer/utils/email/email.rb +44 -5
- data/lib/howitzer/utils/email/mail_client.rb +28 -22
- data/lib/howitzer/utils/email/mailgun_helper.rb +30 -4
- data/lib/howitzer/utils/locator_store.rb +111 -19
- data/lib/howitzer/utils/log.rb +137 -0
- data/lib/howitzer/utils/page_validator.rb +86 -0
- data/lib/howitzer/vendor/firebug-1.12.1-fx.xpi +0 -0
- data/lib/howitzer/vendor/firepath-0.9.7-fx.xpi +0 -0
- data/lib/howitzer/version.rb +2 -2
- data/lib/howitzer/web_page.rb +159 -19
- data/spec/active_resource.rb +0 -0
- data/spec/config/custom.yml +1 -0
- data/spec/config/default.yml +28 -0
- data/spec/spec_helper.rb +46 -1
- data/spec/support/boot_helper.rb +15 -0
- data/spec/support/generator_helper.rb +13 -0
- data/spec/support/logger_helper.rb +12 -0
- data/spec/unit/bin/howitzer_spec.rb +175 -0
- data/spec/unit/generators/generators_spec.rb +175 -0
- data/spec/unit/lib/capybara_settings_spec.rb +170 -0
- data/spec/unit/lib/helpers_spec.rb +619 -0
- data/spec/unit/lib/init_spec.rb +14 -0
- data/spec/unit/lib/settings_spec.rb +17 -0
- data/spec/unit/lib/utils/data_generator/data_storage_spec.rb +62 -0
- data/spec/unit/lib/utils/data_generator/gen_spec.rb +151 -0
- data/spec/unit/lib/utils/email/email_spec.rb +75 -0
- data/spec/unit/lib/utils/email/mail_client_spec.rb +115 -0
- data/spec/unit/lib/utils/email/mailgun_helper_spec.rb +95 -0
- data/spec/unit/lib/utils/locator_store_spec.rb +122 -0
- data/spec/unit/lib/utils/log_spec.rb +107 -0
- data/spec/unit/lib/utils/page_validator_spec.rb +142 -0
- data/spec/unit/lib/web_page_spec.rb +250 -0
- data/spec/unit/version_spec.rb +8 -0
- metadata +215 -15
- data/Gemfile.lock +0 -103
- data/History.md +0 -20
- data/lib/howitzer/utils/logger.rb +0 -108
- data/spec/howitzer/version_spec.rb +0 -8
@@ -1,19 +1,53 @@
|
|
1
1
|
module DataGenerator
|
2
2
|
|
3
|
+
##
|
4
|
+
#
|
5
|
+
# Data can be stored in memory using DataStorage
|
6
|
+
#
|
7
|
+
|
3
8
|
module DataStorage
|
4
9
|
@data ||= {}
|
5
10
|
|
6
11
|
class << self
|
12
|
+
|
13
|
+
##
|
14
|
+
#
|
15
|
+
# Saves data into memory. Marking by namespace and key
|
16
|
+
#
|
17
|
+
# *Parameters:*
|
18
|
+
# * +ns+ - Namespace
|
19
|
+
# * +key+ - Key that should be uniq in namespace
|
20
|
+
# * +value+ - Data value
|
21
|
+
#
|
22
|
+
|
23
|
+
|
7
24
|
def store(ns, key, value)
|
8
25
|
check_ns(ns)
|
9
26
|
@data[ns][key] = value
|
10
27
|
end
|
11
28
|
|
29
|
+
##
|
30
|
+
#
|
31
|
+
# Gets data from memory. Can get all namespace or single data value in namespace using key
|
32
|
+
#
|
33
|
+
# *Parameters:*
|
34
|
+
# * +ns+ - Namespace
|
35
|
+
# * +key+ - Key that isn't necessary required (default to: nil)
|
36
|
+
#
|
37
|
+
|
12
38
|
def extract(ns, key=nil)
|
13
39
|
check_ns(ns)
|
14
40
|
key ? @data[ns][key] : @data[ns]
|
15
41
|
end
|
16
42
|
|
43
|
+
##
|
44
|
+
#
|
45
|
+
# Deletes all records from namespace
|
46
|
+
#
|
47
|
+
# *Parameters:*
|
48
|
+
# * +ns+ - Namespace
|
49
|
+
#
|
50
|
+
|
17
51
|
def clear_ns(ns)
|
18
52
|
init_ns(ns)
|
19
53
|
end
|
@@ -38,4 +72,4 @@ module DataGenerator
|
|
38
72
|
|
39
73
|
end
|
40
74
|
end
|
41
|
-
end
|
75
|
+
end
|
@@ -1,11 +1,28 @@
|
|
1
1
|
module DataGenerator
|
2
2
|
module Gen
|
3
|
-
|
3
|
+
|
4
|
+
##
|
5
|
+
#
|
6
|
+
# This module generates uniq User object with uniq generated data.
|
7
|
+
# Examples:
|
4
8
|
# member = Gen::user #user.email: 'u<XXXX>@<settings.mail_pop3_domain>'
|
5
9
|
# member = Gen::user('user@test.com') #user.email: 'member@test.com'
|
6
|
-
# member = Gen::user(settings.def_test_user)
|
10
|
+
# member = Gen::user(settings.def_test_user) #user.email: settings.def_test_user
|
7
11
|
|
8
12
|
class << self
|
13
|
+
|
14
|
+
##
|
15
|
+
#
|
16
|
+
# Generates new User object with generated data.
|
17
|
+
#
|
18
|
+
# *Parameters:*
|
19
|
+
# * +params+ - Custom parameters
|
20
|
+
#
|
21
|
+
# *Returns:*
|
22
|
+
# * +user+ - New generated User object
|
23
|
+
#
|
24
|
+
|
25
|
+
|
9
26
|
def user(params={})
|
10
27
|
prefix = serial
|
11
28
|
default = {
|
@@ -18,6 +35,17 @@ module DataGenerator
|
|
18
35
|
User.new(default.merge(params))
|
19
36
|
end
|
20
37
|
|
38
|
+
##
|
39
|
+
#
|
40
|
+
# Gets User object by it's number
|
41
|
+
#
|
42
|
+
# *Parameters:*
|
43
|
+
# * +num+ - User number
|
44
|
+
#
|
45
|
+
# *Returns:*
|
46
|
+
# * +user+ - User object
|
47
|
+
#
|
48
|
+
|
21
49
|
def given_user_by_number(num)
|
22
50
|
data = DataStorage.extract('user', num.to_i)
|
23
51
|
unless data
|
@@ -27,11 +55,25 @@ module DataGenerator
|
|
27
55
|
data
|
28
56
|
end
|
29
57
|
|
58
|
+
##
|
59
|
+
#
|
60
|
+
# Generates uniq string
|
61
|
+
# @return [String] Generated string
|
62
|
+
#
|
63
|
+
# *Returns:*
|
64
|
+
# * +string+ - Generated string
|
65
|
+
#
|
66
|
+
|
30
67
|
def serial
|
31
68
|
a = [('a'..'z').to_a, (0..9).to_a].flatten.shuffle
|
32
69
|
"#{Time.now.utc.strftime("%j%H%M%S")}#{a[0..4].join}"
|
33
70
|
end
|
34
71
|
|
72
|
+
##
|
73
|
+
#
|
74
|
+
# Deletes mailboxes for all users that were generated before
|
75
|
+
#
|
76
|
+
|
35
77
|
def delete_all_mailboxes
|
36
78
|
DataStorage.extract('user').each_value do |user|
|
37
79
|
user.delete_mailbox
|
@@ -86,4 +128,4 @@ module DataGenerator
|
|
86
128
|
end
|
87
129
|
end
|
88
130
|
end
|
89
|
-
end
|
131
|
+
end
|
@@ -5,32 +5,71 @@ class Email
|
|
5
5
|
include RSpec::Matchers
|
6
6
|
attr_reader :recipient_address
|
7
7
|
|
8
|
+
##
|
9
|
+
#
|
10
|
+
# Creates new email with message
|
11
|
+
#
|
12
|
+
# *Parameters:*
|
13
|
+
# * +message+ - email message
|
14
|
+
#
|
15
|
+
|
8
16
|
def initialize(message)
|
9
|
-
message.subject.
|
17
|
+
expect(message.subject).to include(self.class::SUBJECT)
|
10
18
|
@recipient_address = ::Mail::Address.new(message.to.first)
|
11
19
|
@message = message
|
12
20
|
end
|
13
21
|
|
22
|
+
##
|
23
|
+
#
|
24
|
+
# Search mail by recepient
|
25
|
+
#
|
26
|
+
# *Parameters:*
|
27
|
+
# * +recepient+ - recepient's email address
|
28
|
+
#
|
29
|
+
|
14
30
|
def self.find_by_recipient(recipient)
|
15
31
|
find(recipient, self::SUBJECT)
|
16
32
|
end
|
17
33
|
|
34
|
+
##
|
35
|
+
#
|
36
|
+
# Search mail by recepient and subject.
|
37
|
+
#
|
38
|
+
# *Parameters:*
|
39
|
+
# * +recepient+ - recepient's email address
|
40
|
+
# * +subject+ - email subject
|
41
|
+
#
|
42
|
+
|
18
43
|
def self.find(recipient, subject)
|
19
|
-
|
20
|
-
|
44
|
+
messages = MailClient.by_email(recipient).find_mail do |mail|
|
45
|
+
/#{Regexp.escape(subject)}/ === mail.subject && mail.to == [recipient]
|
21
46
|
end
|
22
47
|
|
23
48
|
if messages.first.nil?
|
24
49
|
log.error "#{self} was not found (recipient: '#{recipient}')"
|
25
|
-
|
50
|
+
return # TODO check log.error raises error
|
26
51
|
end
|
27
52
|
new(messages.first)
|
28
53
|
end
|
29
54
|
|
55
|
+
##
|
56
|
+
#
|
57
|
+
# Returns plain text body of email message
|
58
|
+
#
|
59
|
+
|
30
60
|
def plain_text_body
|
31
61
|
get_mime_part(@message, 'text/plain').to_s
|
32
62
|
end
|
33
63
|
|
64
|
+
##
|
65
|
+
#
|
66
|
+
# Allows to get email MIME attachment
|
67
|
+
#
|
68
|
+
# *Parameters:*
|
69
|
+
# * +part+ - recepient's email address
|
70
|
+
# * +type+ - MIME message part
|
71
|
+
#
|
72
|
+
|
34
73
|
def get_mime_part(part, type)
|
35
74
|
return part.body if part["content-type"].to_s =~ %r!#{type}!
|
36
75
|
# Recurse the multi-parts
|
@@ -43,4 +82,4 @@ class Email
|
|
43
82
|
|
44
83
|
protected :get_mime_part
|
45
84
|
|
46
|
-
end
|
85
|
+
end
|
@@ -10,18 +10,41 @@ class MailClient
|
|
10
10
|
|
11
11
|
def self.default
|
12
12
|
log.info "Connect to default mailbox"
|
13
|
-
options =
|
14
|
-
@clients[options] =
|
13
|
+
options = merge_opts
|
14
|
+
@clients[options] = new unless @clients.has_key?(options)
|
15
15
|
@clients[options]
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.by_email(name)
|
19
19
|
log.info "Connect to '#{name}' mailbox"
|
20
|
-
options = self.merge_opts(:
|
21
|
-
@clients[options] =
|
20
|
+
options = self.merge_opts(pop3: { user_name: name }, smtp: {})
|
21
|
+
@clients[options] = new(options) unless @clients.has_key?(options)
|
22
22
|
@clients[options]
|
23
23
|
end
|
24
24
|
|
25
|
+
def self.merge_opts(opts={smtp: {}, pop3: {}})
|
26
|
+
def_smtp_opts = {
|
27
|
+
address: settings.mail_smtp_server,
|
28
|
+
port: settings.mail_smtp_port,
|
29
|
+
domain: settings.mail_smtp_domain,
|
30
|
+
user_name: settings.mail_smtp_user_name,
|
31
|
+
password: settings.mail_smtp_user_pass,
|
32
|
+
authentication: 'plain',
|
33
|
+
enable_starttls_auto: true
|
34
|
+
}
|
35
|
+
|
36
|
+
def_pop3_opts = {
|
37
|
+
address: settings.mail_pop3_server,
|
38
|
+
port: settings.mail_pop3_port,
|
39
|
+
user_name: settings.mail_pop3_user_name,
|
40
|
+
password: settings.mail_pop3_user_pass
|
41
|
+
}
|
42
|
+
{
|
43
|
+
smtp: def_smtp_opts.merge(opts[:smtp]),
|
44
|
+
pop3: def_pop3_opts.merge(opts[:pop3])
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
25
48
|
def find_mail(max_wait = settings.mail_pop3_timeout, keep_or_delete = :delete, &block)
|
26
49
|
messages = []
|
27
50
|
time_of_start = Time.now
|
@@ -98,7 +121,7 @@ class MailClient
|
|
98
121
|
|
99
122
|
private
|
100
123
|
def initialize(*arg)
|
101
|
-
@options =
|
124
|
+
@options = self.class.merge_opts(*arg)
|
102
125
|
Net::POP3.enable_ssl(OpenSSL::SSL::VERIFY_NONE)
|
103
126
|
@old_ids = []
|
104
127
|
options = @options
|
@@ -106,21 +129,4 @@ class MailClient
|
|
106
129
|
@time_of_start = Time.now
|
107
130
|
end
|
108
131
|
|
109
|
-
def self.merge_opts(opts={:smtp => {}, :pop3 => {}})
|
110
|
-
def_smtp_opts = {:address => settings.mail_smtp_server,
|
111
|
-
:port => settings.mail_smtp_port,
|
112
|
-
:domain => settings.mail_smtp_domain,
|
113
|
-
:user_name => settings.mail_smtp_user_name,
|
114
|
-
:password => settings.mail_smtp_user_pass,
|
115
|
-
:authentication => 'plain',
|
116
|
-
:enable_starttls_auto => true}
|
117
|
-
|
118
|
-
def_pop3_opts = {:address => settings.mail_pop3_server,
|
119
|
-
:port => settings.mail_pop3_port,
|
120
|
-
:user_name => settings.mail_pop3_user_name,
|
121
|
-
:password => settings.mail_pop3_user_pass}
|
122
|
-
{:smtp => def_smtp_opts.merge(opts[:smtp]),
|
123
|
-
:pop3 => def_pop3_opts.merge(opts[:pop3])}
|
124
|
-
end
|
125
|
-
|
126
132
|
end
|
@@ -1,5 +1,16 @@
|
|
1
1
|
module MailgunHelper
|
2
2
|
|
3
|
+
##
|
4
|
+
#
|
5
|
+
# Creates new mailbox for given user_name
|
6
|
+
#
|
7
|
+
# *Parameters:*
|
8
|
+
# * +user_name+ - user name
|
9
|
+
# * +domain+ - domain (default to: settings.mail_pop3_domain )
|
10
|
+
# * +password+ - password (default to: settings.mail_pop3_user_pass )
|
11
|
+
#
|
12
|
+
|
13
|
+
|
3
14
|
def create_mailbox(user_name,
|
4
15
|
domain=settings.mail_pop3_domain,
|
5
16
|
password=settings.mail_pop3_user_pass)
|
@@ -9,6 +20,14 @@ module MailgunHelper
|
|
9
20
|
mbox
|
10
21
|
end
|
11
22
|
|
23
|
+
##
|
24
|
+
#
|
25
|
+
# Deletes given mailbox
|
26
|
+
#
|
27
|
+
# *Parameters:*
|
28
|
+
# * +mailbox+ - mailbox to delete
|
29
|
+
#
|
30
|
+
|
12
31
|
def delete_mailbox(mailbox)
|
13
32
|
log.info "Delete '#{mailbox.user}@#{mailbox.domain}' mailbox"
|
14
33
|
begin
|
@@ -18,11 +37,18 @@ module MailgunHelper
|
|
18
37
|
end
|
19
38
|
end
|
20
39
|
|
40
|
+
##
|
41
|
+
#
|
42
|
+
# Deletes all mailboxes except those in exceptions
|
43
|
+
#
|
44
|
+
# *Parameters:*
|
45
|
+
# * +exceptions+ - list of email addresses
|
46
|
+
#
|
47
|
+
|
21
48
|
def delete_all_mailboxes(*exceptions)
|
22
|
-
|
23
|
-
exceptions += %w"postmaster@#{settings.mail_smtp_domain}" #system and default mailbox
|
49
|
+
exceptions += ["postmaster@#{settings.mail_smtp_domain}"] #system and default mailbox
|
24
50
|
exceptions = exceptions.uniq
|
25
|
-
log.info "Delete all mailboxes
|
51
|
+
log.info "Delete all mailboxes except: #{exceptions.map(&:inspect).join(', ')}"
|
26
52
|
i = 0
|
27
53
|
Mailbox.find(:all).each do |m|
|
28
54
|
next if exceptions.include?("#{m.user}@#{m.domain}")
|
@@ -32,4 +58,4 @@ module MailgunHelper
|
|
32
58
|
|
33
59
|
log.info "Were deleted '#{i}' mailboxes"
|
34
60
|
end
|
35
|
-
end
|
61
|
+
end
|
@@ -18,52 +18,156 @@
|
|
18
18
|
|
19
19
|
|
20
20
|
module LocatorStore
|
21
|
+
BadLocatorParamsError = Class.new(StandardError)
|
22
|
+
LocatorNotDefinedError = Class.new(StandardError)
|
23
|
+
|
21
24
|
def self.included(base)
|
22
25
|
base.extend(ClassMethods)
|
23
26
|
end
|
24
27
|
|
25
28
|
module ClassMethods
|
29
|
+
LOCATOR_TYPES = [:base, :link, :field, :button]
|
26
30
|
class BadLocatorParamsError < StandardError; end
|
27
31
|
class LocatorNotSpecifiedError < StandardError; end
|
28
32
|
|
33
|
+
##
|
34
|
+
#
|
35
|
+
# Adds css or xpath locator into LocatorStore.
|
36
|
+
# Also locator can be set by lambda expression. For example: lambda{|name|{xpath: ".//a[@id='#{name}']"}}
|
37
|
+
#
|
38
|
+
# *Parameters:*
|
39
|
+
# * +name+ - Locator name
|
40
|
+
# * +params+ - String for css locator or hash with :xpath key and string value for xpath locator
|
41
|
+
#
|
42
|
+
|
29
43
|
def add_locator(name, params)
|
30
44
|
add_locator_by_type(:base, name, params)
|
31
45
|
end
|
32
46
|
|
47
|
+
##
|
48
|
+
#
|
49
|
+
# Adds locator for link into LocatorStore. Link can be found by: id, text
|
50
|
+
# Capybara methods that can work with this locator type are: click_link, find_link
|
51
|
+
#
|
52
|
+
# *Parameters:*
|
53
|
+
# * +name+ - Locator name
|
54
|
+
# * +params+ - ID or text of link
|
55
|
+
#
|
56
|
+
|
33
57
|
def add_link_locator(name, params)
|
34
58
|
add_locator_by_type(:link, name, params)
|
35
59
|
end
|
36
60
|
|
61
|
+
##
|
62
|
+
#
|
63
|
+
# Adds locator for field into LocatorStore. Field can be found by: name, id, text
|
64
|
+
# Capybara methods that can work with this locator type are: find_field, fill_in
|
65
|
+
#
|
66
|
+
# *Parameters:*
|
67
|
+
# * +name+ - Locator name
|
68
|
+
# * +params+ - Name, ID or text of field
|
69
|
+
#
|
70
|
+
|
37
71
|
def add_field_locator(name, params)
|
38
72
|
add_locator_by_type(:field, name, params)
|
39
73
|
end
|
40
74
|
|
75
|
+
##
|
76
|
+
#
|
77
|
+
# Add locator for button into LocatorStore. Button can be found by: id, name, value
|
78
|
+
# Capybara methods that can work with this locator type are: click_button, find_button
|
79
|
+
#
|
80
|
+
# *Parameters:*
|
81
|
+
# * +name+ - Locator name
|
82
|
+
# * +params+ - Name, ID or value
|
83
|
+
#
|
84
|
+
|
41
85
|
def add_button_locator(name, params)
|
42
86
|
add_locator_by_type(:button, name, params)
|
43
87
|
end
|
44
88
|
|
89
|
+
##
|
90
|
+
#
|
91
|
+
# Takes css or xpath locator from LocatorStore by name
|
92
|
+
#
|
93
|
+
# *Parameters:*
|
94
|
+
# * +name+ - Locator name
|
95
|
+
#
|
96
|
+
|
45
97
|
def locator(name)
|
46
98
|
locator_by_type(:base, name)
|
47
99
|
end
|
48
100
|
|
101
|
+
##
|
102
|
+
#
|
103
|
+
# Take link locator from LocatorStore by name
|
104
|
+
#
|
105
|
+
# *Parameters:*
|
106
|
+
# * +name+ - Locator name
|
107
|
+
#
|
108
|
+
|
49
109
|
def link_locator(name)
|
50
110
|
locator_by_type(:link, name)
|
51
111
|
end
|
52
112
|
|
113
|
+
##
|
114
|
+
#
|
115
|
+
# Take field locator from LocatorStore by name
|
116
|
+
#
|
117
|
+
# *Parameters:*
|
118
|
+
# * +name+ - Locator name
|
119
|
+
#
|
120
|
+
|
53
121
|
def field_locator(name)
|
54
122
|
locator_by_type(:field, name)
|
55
123
|
end
|
56
124
|
|
125
|
+
##
|
126
|
+
#
|
127
|
+
# Take button locator from LocatorStore be name
|
128
|
+
#
|
129
|
+
# *Parameters:*
|
130
|
+
# * +name+ - Locator name
|
131
|
+
#
|
132
|
+
|
57
133
|
def button_locator(name)
|
58
134
|
locator_by_type(:button, name)
|
59
135
|
end
|
60
136
|
|
137
|
+
##
|
138
|
+
#
|
139
|
+
# Get locator set by lambda.
|
140
|
+
# For example: find(apply(locator(:locator_name), 'register')).click
|
141
|
+
#
|
142
|
+
# *Parameters:*
|
143
|
+
# * +locator+ - Locator set with lambda expression
|
144
|
+
# * +values+ - Arguments that should be matched lambda expression params
|
145
|
+
#
|
146
|
+
|
61
147
|
def apply(locator, *values)
|
62
148
|
locator.call(*values).to_a.flatten
|
63
149
|
end
|
64
150
|
|
151
|
+
def find_element(name)
|
152
|
+
type, locator = find_locator(name)
|
153
|
+
if type == :base
|
154
|
+
send :find, locator
|
155
|
+
else
|
156
|
+
send "find_#{type}", locator
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
65
160
|
protected
|
66
161
|
|
162
|
+
def find_locator(name)
|
163
|
+
name = name.to_s.to_sym
|
164
|
+
LOCATOR_TYPES.each do|type|
|
165
|
+
return [type, locator_by_type(type, name)] if (@locators || {}).fetch(self.name, {}).fetch(type, {})[name]
|
166
|
+
end
|
167
|
+
raise(LocatorNotDefinedError, name)
|
168
|
+
end
|
169
|
+
|
170
|
+
# looks up locator in current and all super classes
|
67
171
|
def parent_locator(type, name)
|
68
172
|
if !@locators.nil? && @locators.key?(self.name) && @locators[self.name].key?(type) && @locators[self.name][type].key?(name)
|
69
173
|
@locators[self.name][type][name]
|
@@ -76,7 +180,7 @@ module LocatorStore
|
|
76
180
|
|
77
181
|
def locator_by_type(type, name)
|
78
182
|
locator = parent_locator(type, name)
|
79
|
-
raise(
|
183
|
+
raise(LocatorNotDefinedError, name) if locator.nil?
|
80
184
|
locator
|
81
185
|
end
|
82
186
|
|
@@ -96,23 +200,11 @@ module LocatorStore
|
|
96
200
|
end
|
97
201
|
end
|
98
202
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
self.class.link_locator(name)
|
105
|
-
end
|
106
|
-
|
107
|
-
def field_locator(name)
|
108
|
-
self.class.field_locator(name)
|
109
|
-
end
|
110
|
-
|
111
|
-
def button_locator(name)
|
112
|
-
self.class.button_locator(name)
|
203
|
+
#delegate class methods to instance
|
204
|
+
ClassMethods.public_instance_methods.each do |name|
|
205
|
+
define_method(name) do |*args|
|
206
|
+
self.class.send(name, *args)
|
207
|
+
end
|
113
208
|
end
|
114
209
|
|
115
|
-
|
116
|
-
self.class.apply(locator, *values)
|
117
|
-
end
|
118
|
-
end
|
210
|
+
end
|