locatine 0.02878 → 0.03050
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/locatine.rb +2 -0
- data/lib/locatine/daemon.rb +1 -7
- data/lib/locatine/daemon_helpers/methods.rb +8 -0
- data/lib/locatine/element.rb +15 -1
- data/lib/locatine/error.rb +1 -1
- data/lib/locatine/logger.rb +6 -2
- data/lib/locatine/results.rb +43 -47
- data/lib/locatine/results_helpers/common.rb +3 -10
- data/lib/locatine/results_helpers/comparing.rb +51 -0
- data/lib/locatine/results_helpers/config.rb +48 -0
- data/lib/locatine/results_helpers/find_by_magic.rb +3 -1
- data/lib/locatine/results_helpers/guess.rb +3 -32
- data/lib/locatine/results_helpers/info_generator.rb +2 -4
- data/lib/locatine/results_helpers/xpath_generator.rb +2 -0
- data/lib/locatine/session.rb +82 -42
- data/lib/locatine/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6ec7ffd6c0a45544ae5cbd20581f72190bbfa3ee5dd2c5e444740c1d03d7ba04
|
|
4
|
+
data.tar.gz: 7552e77cfc41106c4679a99554980f67ad4decc354348ee0d01479c9799687fa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6d42ad78b43ff2335357546b50daa98734e1d06527e26fc6608540135ffb73d4f1aebcf9b5e3fb44c74b3125a31045b3206a8ddabdc0c08211f28f71390fdc9f
|
|
7
|
+
data.tar.gz: 2b752ff4e3a7b60ae8eb12f585eef9df6445f3c659169e7470bcfbc18f848938762815a8a977ce4825be250f527a425b0c2ff1b96d52240db4223e9d1d8a201e
|
data/README.md
CHANGED
|
@@ -14,7 +14,7 @@ That's it.
|
|
|
14
14
|
|
|
15
15
|
## Stage of development:
|
|
16
16
|
|
|
17
|
-
Version of Locatine is **0.
|
|
17
|
+
Version of Locatine is **0.03050**. The 4th version since rewriting. 5-15 next versions is dedicated to bug fixing, tweaking.
|
|
18
18
|
|
|
19
19
|
## Attention
|
|
20
20
|
|
data/lib/locatine.rb
CHANGED
|
@@ -6,6 +6,8 @@ require 'locatine/results_helpers/find_by_magic'
|
|
|
6
6
|
require 'locatine/results_helpers/guess'
|
|
7
7
|
require 'locatine/results_helpers/info_generator'
|
|
8
8
|
require 'locatine/results_helpers/xpath_generator'
|
|
9
|
+
require 'locatine/results_helpers/comparing'
|
|
10
|
+
require 'locatine/results_helpers/config'
|
|
9
11
|
|
|
10
12
|
require 'locatine/logger'
|
|
11
13
|
require 'locatine/version'
|
data/lib/locatine/daemon.rb
CHANGED
|
@@ -4,7 +4,7 @@ require 'sinatra/base'
|
|
|
4
4
|
require 'json'
|
|
5
5
|
|
|
6
6
|
module Locatine
|
|
7
|
-
|
|
7
|
+
##
|
|
8
8
|
# Locatine daemon based on sinatra
|
|
9
9
|
#
|
|
10
10
|
# run Locatine::Daemon.run!
|
|
@@ -34,12 +34,6 @@ module Locatine
|
|
|
34
34
|
{ result: result }.to_json
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
def send_error(error)
|
|
38
|
-
status error.status
|
|
39
|
-
|
|
40
|
-
error.answer
|
|
41
|
-
end
|
|
42
|
-
|
|
43
37
|
# selenium calls
|
|
44
38
|
post '/wd/hub/session/*/element' do
|
|
45
39
|
content_type settings.headers['Content-Type']
|
|
@@ -7,6 +7,8 @@ module Locatine
|
|
|
7
7
|
#
|
|
8
8
|
# Methods that are used by daemon
|
|
9
9
|
module Methods
|
|
10
|
+
private
|
|
11
|
+
|
|
10
12
|
def api_request(type, path, query_string, body, new_headers)
|
|
11
13
|
uri = make_uri(path, query_string)
|
|
12
14
|
req = Net::HTTP.const_get(type).new(uri,
|
|
@@ -80,6 +82,12 @@ module Locatine
|
|
|
80
82
|
path_array = request.path_info.split('/')
|
|
81
83
|
path_array.size >= 7 ? path_array[6] : nil
|
|
82
84
|
end
|
|
85
|
+
|
|
86
|
+
def send_error(error)
|
|
87
|
+
status error.status
|
|
88
|
+
|
|
89
|
+
error.answer
|
|
90
|
+
end
|
|
83
91
|
end
|
|
84
92
|
end
|
|
85
93
|
end
|
data/lib/locatine/element.rb
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Locatine
|
|
4
|
-
|
|
4
|
+
##
|
|
5
5
|
# Locatine single element
|
|
6
|
+
#
|
|
7
|
+
# It is used to store element info and to return parent.
|
|
8
|
+
# I am thinking about moving staleness check here.
|
|
6
9
|
class Element
|
|
7
10
|
attr_accessor :answer
|
|
8
11
|
|
|
12
|
+
##
|
|
13
|
+
# Init method
|
|
14
|
+
#
|
|
15
|
+
# +session+ is a Locatine::Session instance
|
|
16
|
+
# +element_code+ is an element hash returned by selenium it is shaped like:
|
|
17
|
+
# {"element-6066-11e4-a52e-4f735466cecf"=>"c95a0580-4ac7-4c6d-..."}
|
|
9
18
|
def initialize(session, element_code)
|
|
10
19
|
unless element_code
|
|
11
20
|
raise ArgumentError, 'Cannot init element with no element data'
|
|
@@ -15,12 +24,17 @@ module Locatine
|
|
|
15
24
|
@answer = element_code
|
|
16
25
|
end
|
|
17
26
|
|
|
27
|
+
##
|
|
28
|
+
# Returning a parent element
|
|
18
29
|
def parent
|
|
19
30
|
parent = File.read("#{HOME}/scripts/parent.js")
|
|
20
31
|
new_answer = @session.execute_script(parent, self)
|
|
21
32
|
new_answer.nil? ? nil : Locatine::Element.new(@session, new_answer)
|
|
22
33
|
end
|
|
23
34
|
|
|
35
|
+
##
|
|
36
|
+
# Method to get the info about particular element or return it if it was
|
|
37
|
+
# gathered before
|
|
24
38
|
def info
|
|
25
39
|
return @info if @info
|
|
26
40
|
|
data/lib/locatine/error.rb
CHANGED
data/lib/locatine/logger.rb
CHANGED
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
require 'colorize'
|
|
4
4
|
|
|
5
5
|
module Locatine
|
|
6
|
-
|
|
6
|
+
##
|
|
7
7
|
# Methods for sending lines to STDOUT
|
|
8
|
+
#
|
|
9
|
+
# Some of methods are specific and should be run in a correct class only!
|
|
8
10
|
module Logger
|
|
11
|
+
private
|
|
12
|
+
|
|
9
13
|
def warn(text)
|
|
10
14
|
puts "WARNING: #{Time.now}: ".yellow + text
|
|
11
15
|
end
|
|
@@ -20,7 +24,7 @@ module Locatine
|
|
|
20
24
|
|
|
21
25
|
def warn_locator
|
|
22
26
|
warn("Locator is broken. For #{name} by"\
|
|
23
|
-
" #{@locator['using']}>>>'#{locator['value']}'")
|
|
27
|
+
" #{@locator['using']}>>>'#{@locator['value']}'")
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
def warn_guess
|
data/lib/locatine/results.rb
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Locatine
|
|
4
|
+
##
|
|
5
|
+
# Locatine results container.
|
|
4
6
|
#
|
|
5
|
-
#
|
|
7
|
+
# Results is a pretty strange concept. It is an array of returned elements
|
|
8
|
+
# which is extended by methods of finding and gathering elements.
|
|
6
9
|
class Results < Array
|
|
7
10
|
include Locatine::ResultsHelpers::InfoGenerator
|
|
8
11
|
include Locatine::ResultsHelpers::XpathGenerator
|
|
@@ -10,16 +13,49 @@ module Locatine
|
|
|
10
13
|
include Locatine::ResultsHelpers::Common
|
|
11
14
|
include Locatine::Logger
|
|
12
15
|
include Locatine::ResultsHelpers::Guess
|
|
16
|
+
include Locatine::ResultsHelpers::Comparing
|
|
17
|
+
include Locatine::ResultsHelpers::Config
|
|
18
|
+
|
|
19
|
+
attr_accessor :name
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# Method to find elements
|
|
23
|
+
#
|
|
24
|
+
# +session+ instance of Locatine::Session
|
|
25
|
+
# +locator+ can be a classic locator shaped for webdriver protocol like:
|
|
26
|
+
# {'using => 'xpath', 'value' => '//div'} or
|
|
27
|
+
# {'using' => 'css selector', 'value' => 'div'}
|
|
28
|
+
# It also can be a locator with magic comment like
|
|
29
|
+
# {'using' => 'css selector', 'value' => 'div/*magic comment*/'}
|
|
30
|
+
# It also can be a locator with incapsulated json
|
|
31
|
+
# {'using' => 'css selector', 'value' => 'div/*{"name": "magic comment"}*/'}
|
|
32
|
+
# It can be a locatine locator
|
|
33
|
+
# {'using' => 'locatine', 'value' => '{"name": "magic comment"}'} or
|
|
34
|
+
# {'using' => 'locatine', 'value' => 'magic comment'
|
|
35
|
+
# +parent+ is the parent element to look for the nested ones.
|
|
36
|
+
def find(session, locator, parent)
|
|
37
|
+
configure(session, locator, parent)
|
|
38
|
+
timer
|
|
39
|
+
classic_find
|
|
40
|
+
guess if name_only?
|
|
41
|
+
return self unless empty?
|
|
13
42
|
|
|
14
|
-
|
|
43
|
+
find_by_magic if known && tolerance.positive?
|
|
44
|
+
similar? ? found : not_found
|
|
45
|
+
end
|
|
15
46
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
47
|
+
##
|
|
48
|
+
# Method to return information about elements found
|
|
49
|
+
#
|
|
50
|
+
# Information is returned combined with the previously known data and can
|
|
51
|
+
# be stored and used as is. It means that its returning not the data about
|
|
52
|
+
# one particular search. But the combined data of all previous searches
|
|
53
|
+
def info
|
|
54
|
+
stability_bump(raw_info)
|
|
21
55
|
end
|
|
22
56
|
|
|
57
|
+
private
|
|
58
|
+
|
|
23
59
|
def simple_find
|
|
24
60
|
path = @parent ? "/element/#{@parent}/elements" : '/elements'
|
|
25
61
|
response = @session.api_request(path, 'Post', @locator.to_json)
|
|
@@ -75,16 +111,6 @@ module Locatine
|
|
|
75
111
|
find_by_data(base) if empty? && !trusted.empty? && !base['0'].empty?
|
|
76
112
|
end
|
|
77
113
|
|
|
78
|
-
def find
|
|
79
|
-
timer
|
|
80
|
-
classic_find
|
|
81
|
-
guess if name_only?
|
|
82
|
-
return self unless empty?
|
|
83
|
-
|
|
84
|
-
find_by_magic if known && tolerance.positive?
|
|
85
|
-
similar? ? found : not_found
|
|
86
|
-
end
|
|
87
|
-
|
|
88
114
|
def found
|
|
89
115
|
log_found
|
|
90
116
|
uniq
|
|
@@ -94,35 +120,5 @@ module Locatine
|
|
|
94
120
|
warn_lost
|
|
95
121
|
[]
|
|
96
122
|
end
|
|
97
|
-
|
|
98
|
-
def read_locator
|
|
99
|
-
case @locator['using']
|
|
100
|
-
when 'css selector'
|
|
101
|
-
# "button/*{json}*/"
|
|
102
|
-
read_locator_routine(%r{/\*(.*)\*/$})
|
|
103
|
-
when 'xpath'
|
|
104
|
-
# "//button['{json}']"
|
|
105
|
-
read_locator_routine(/\[\'(.*)\'\]$/)
|
|
106
|
-
when 'locatine'
|
|
107
|
-
read_locator_routine(/(.*)/)
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def read_locator_routine(regexp)
|
|
112
|
-
matched = @locator['value'].match(regexp)
|
|
113
|
-
@config = matched ? config_provided(matched[1]) : {}
|
|
114
|
-
@locator['value'] = @locator['value'].gsub(matched[0], '') if matched
|
|
115
|
-
@locator = @config['locator'] if @config['locator']
|
|
116
|
-
@name = @config['name'] || @locator['value']
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def config_provided(config)
|
|
120
|
-
JSON.parse(config)
|
|
121
|
-
rescue StandardError
|
|
122
|
-
result = {}
|
|
123
|
-
result['tolerance'] = 0 if config.start_with?('exactly')
|
|
124
|
-
result['name'] = config.gsub('exactly ', '')
|
|
125
|
-
result
|
|
126
|
-
end
|
|
127
123
|
end
|
|
128
124
|
end
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module Locatine
|
|
4
4
|
module ResultsHelpers
|
|
5
|
-
|
|
5
|
+
##
|
|
6
6
|
# Some common methods without much logic
|
|
7
7
|
module Common
|
|
8
|
+
private
|
|
9
|
+
|
|
8
10
|
def timer
|
|
9
11
|
@time ||= Time.now
|
|
10
12
|
timeout > Time.now - @time
|
|
@@ -27,15 +29,6 @@ module Locatine
|
|
|
27
29
|
(item['name'] == hash['name']) && (item['type'] == hash['type'])
|
|
28
30
|
end
|
|
29
31
|
|
|
30
|
-
def info_hash_eq(item, hash)
|
|
31
|
-
# Return true
|
|
32
|
-
# If type is unknown (but not a text)
|
|
33
|
-
# Or when type and name are similar
|
|
34
|
-
(unknown_no_text(item, hash) || same_name_type(item, hash)) &&
|
|
35
|
-
# And at the same time values are (almost) the same
|
|
36
|
-
(item['value'].downcase == hash['value'].downcase)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
32
|
def stability
|
|
40
33
|
@config['stability'] || @session.stability
|
|
41
34
|
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Locatine
|
|
4
|
+
module ResultsHelpers
|
|
5
|
+
#
|
|
6
|
+
# Trying to guess element here
|
|
7
|
+
module Comparing
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def count_similarity
|
|
11
|
+
all = 0
|
|
12
|
+
same = 0
|
|
13
|
+
# Next is necessary for unknown reason (smthing thread related)
|
|
14
|
+
raw = raw_info['0']
|
|
15
|
+
get_trusted(known['0']).each do |hash|
|
|
16
|
+
caught = (raw.select { |item| info_hash_eq(item, hash) }).first
|
|
17
|
+
all += 1
|
|
18
|
+
same += 1 if caught
|
|
19
|
+
end
|
|
20
|
+
similar_enough(same, all)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def similar?
|
|
24
|
+
return false if empty?
|
|
25
|
+
|
|
26
|
+
return true if tolerance == 100
|
|
27
|
+
|
|
28
|
+
count_similarity
|
|
29
|
+
rescue RuntimeError => e
|
|
30
|
+
raise e.message unless e.message == 'stale element reference'
|
|
31
|
+
|
|
32
|
+
warn_unstable_page
|
|
33
|
+
false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def similar_enough(same, all)
|
|
37
|
+
sameness = (same * 100) / all
|
|
38
|
+
sameness >= 100 - tolerance
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def info_hash_eq(item, hash)
|
|
42
|
+
# Return true
|
|
43
|
+
# If type is unknown (but not a text)
|
|
44
|
+
# Or when type and name are similar
|
|
45
|
+
(unknown_no_text(item, hash) || same_name_type(item, hash)) &&
|
|
46
|
+
# And at the same time values are (almost) the same
|
|
47
|
+
(item['value'].downcase == hash['value'].downcase)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Locatine
|
|
4
|
+
module ResultsHelpers
|
|
5
|
+
#
|
|
6
|
+
# Trying to guess element here
|
|
7
|
+
module Config
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def configure(session, locator, parent)
|
|
11
|
+
@session = session
|
|
12
|
+
@locator = locator.clone
|
|
13
|
+
read_locator
|
|
14
|
+
@parent = parent
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def read_locator
|
|
18
|
+
case @locator['using']
|
|
19
|
+
when 'css selector'
|
|
20
|
+
# "button/*{json}*/"
|
|
21
|
+
read_locator_routine(%r{/\*(.*)\*/$})
|
|
22
|
+
when 'xpath'
|
|
23
|
+
# "//button['{json}']"
|
|
24
|
+
read_locator_routine(/\[\'(.*)\'\]$/)
|
|
25
|
+
when 'locatine'
|
|
26
|
+
read_locator_routine(/(.*)/)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def read_locator_routine(regexp)
|
|
31
|
+
matched = @locator['value'].match(regexp)
|
|
32
|
+
@config = matched ? config_provided(matched[1]) : {}
|
|
33
|
+
@locator['value'] = @locator['value'].gsub(matched[0], '') if matched
|
|
34
|
+
@locator = @config['locator'] if @config['locator']
|
|
35
|
+
@name = @config['name'] || @locator['value']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def config_provided(config)
|
|
39
|
+
JSON.parse(config)
|
|
40
|
+
rescue StandardError
|
|
41
|
+
result = {}
|
|
42
|
+
result['tolerance'] = 0 if config.start_with?('exactly')
|
|
43
|
+
result['name'] = config.gsub('exactly ', '')
|
|
44
|
+
result
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module Locatine
|
|
4
4
|
module ResultsHelpers
|
|
5
|
-
|
|
5
|
+
##
|
|
6
6
|
# Trying to guess element here
|
|
7
7
|
module Guess
|
|
8
|
+
private
|
|
9
|
+
|
|
8
10
|
def guess
|
|
9
11
|
warn_guess
|
|
10
12
|
@config['tolerance'] = 100
|
|
@@ -40,37 +42,6 @@ module Locatine
|
|
|
40
42
|
end
|
|
41
43
|
answer
|
|
42
44
|
end
|
|
43
|
-
|
|
44
|
-
def count_similarity
|
|
45
|
-
all = 0
|
|
46
|
-
same = 0
|
|
47
|
-
# Next is necessary for unknown reason (smthing thread related)
|
|
48
|
-
raw = raw_info['0']
|
|
49
|
-
get_trusted(known['0']).each do |hash|
|
|
50
|
-
caught = (raw.select { |item| info_hash_eq(item, hash) }).first
|
|
51
|
-
all += 1
|
|
52
|
-
same += 1 if caught
|
|
53
|
-
end
|
|
54
|
-
similar_enough(same, all)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def similar?
|
|
58
|
-
return false if empty?
|
|
59
|
-
|
|
60
|
-
return true if tolerance == 100
|
|
61
|
-
|
|
62
|
-
count_similarity
|
|
63
|
-
rescue RuntimeError => e
|
|
64
|
-
raise e.message unless e.message == 'stale element reference'
|
|
65
|
-
|
|
66
|
-
warn_unstable_page
|
|
67
|
-
false
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def similar_enough(same, all)
|
|
71
|
-
sameness = (same * 100) / all
|
|
72
|
-
sameness >= 100 - tolerance
|
|
73
|
-
end
|
|
74
45
|
end
|
|
75
46
|
end
|
|
76
47
|
end
|
data/lib/locatine/session.rb
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Locatine
|
|
4
|
+
##
|
|
5
|
+
# Locatine Session class.
|
|
4
6
|
#
|
|
5
|
-
#
|
|
7
|
+
# Each selenium session gets a locatine session. Locatine session knows
|
|
8
|
+
# selenium address and session_id so it is able to communicate with selenium.
|
|
9
|
+
# It has no complex logic, but acts like a bridge between daemon and selenium
|
|
10
|
+
# while element is searched
|
|
6
11
|
class Session
|
|
7
12
|
include Locatine::Logger
|
|
8
13
|
attr_accessor :json, :depth, :trusted, :untrusted, :tolerance, :stability,
|
|
9
14
|
:elements, :timeout
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
##
|
|
17
|
+
# Init of the new session instance
|
|
18
|
+
#
|
|
19
|
+
# +selenium+ is a selenium address like "https://host:port"
|
|
20
|
+
# +session+ is a session id provided by selenium
|
|
16
21
|
def initialize(selenium, session)
|
|
17
22
|
@selenium = selenium
|
|
18
23
|
@parsed_selenium = URI.parse @selenium
|
|
@@ -23,6 +28,10 @@ module Locatine
|
|
|
23
28
|
configure defaults
|
|
24
29
|
end
|
|
25
30
|
|
|
31
|
+
##
|
|
32
|
+
# This method is to set settings
|
|
33
|
+
#
|
|
34
|
+
# +params+ is a hash of settings like {json: "some", depth: 0...}
|
|
26
35
|
def configure(params)
|
|
27
36
|
params.to_h.each_pair do |var, value|
|
|
28
37
|
instance_variable_set("@#{var}", value)
|
|
@@ -31,23 +40,14 @@ module Locatine
|
|
|
31
40
|
params
|
|
32
41
|
end
|
|
33
42
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@elements = JSON.parse(File.read(@json))['elements']
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def write
|
|
46
|
-
File.open(@json, 'w') do |f|
|
|
47
|
-
f.write(JSON.pretty_generate('elements' => @elements))
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
43
|
+
##
|
|
44
|
+
# Find method is for finding elements.
|
|
45
|
+
#
|
|
46
|
+
# That is the part that is replacing simple finding by selenium
|
|
47
|
+
# +params+ is a hash of settings like {json: "some", depth: 0...}
|
|
48
|
+
# +parent+ is an element code of the element to look under. It is counted
|
|
49
|
+
# only for the most simple search. If element is lost parent will be
|
|
50
|
+
# ignored
|
|
51
51
|
def find(params, parent = nil)
|
|
52
52
|
find_routine(params, parent)
|
|
53
53
|
rescue RuntimeError => e
|
|
@@ -57,17 +57,13 @@ module Locatine
|
|
|
57
57
|
find(params, parent)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
end
|
|
68
|
-
answer
|
|
69
|
-
end
|
|
70
|
-
|
|
60
|
+
##
|
|
61
|
+
# Session can execute js scripts on a page
|
|
62
|
+
#
|
|
63
|
+
# Note this method will be not called when you are asking selenoum via
|
|
64
|
+
# locatine to execute a script. This class is for internal use.
|
|
65
|
+
# +script+ some valid js code
|
|
66
|
+
# +*args+ arguments to be passed to script.
|
|
71
67
|
def execute_script(script, *args)
|
|
72
68
|
args.map! { |item| item.class == Locatine::Element ? item.answer : item }
|
|
73
69
|
response = api_request('/execute/sync', 'Post',
|
|
@@ -79,6 +75,8 @@ module Locatine
|
|
|
79
75
|
value
|
|
80
76
|
end
|
|
81
77
|
|
|
78
|
+
##
|
|
79
|
+
# Returning information about the current page
|
|
82
80
|
def page
|
|
83
81
|
# We need duplicated JSON parse since standart
|
|
84
82
|
# chromedriver giving an error here if the page is too large
|
|
@@ -86,14 +84,14 @@ module Locatine
|
|
|
86
84
|
JSON.parse(page, max_nesting: false)['result']
|
|
87
85
|
end
|
|
88
86
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
87
|
+
##
|
|
88
|
+
# This method is used to ask selenium about something.
|
|
89
|
+
#
|
|
90
|
+
# We are using it to ask for elements found by selenium or
|
|
91
|
+
# for script execution
|
|
92
|
+
# +path+ is a relative path to call on selenium like '/elements'
|
|
93
|
+
# +method+ is an http method to perform ('Get', 'Post', etc.)
|
|
94
|
+
# +body+ is for request data. json here (selenium wants it) or nil
|
|
97
95
|
def api_request(path, method, body)
|
|
98
96
|
uri = call_uri(path)
|
|
99
97
|
req = Net::HTTP.const_get(method)
|
|
@@ -103,5 +101,47 @@ module Locatine
|
|
|
103
101
|
req.body = body
|
|
104
102
|
Net::HTTP.new(uri.hostname, uri.port).start { |http| http.request(req) }
|
|
105
103
|
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
def defaults
|
|
108
|
+
{ json: "#{Dir.pwd}/locatine_files/default.json", depth: 3, trusted: [],
|
|
109
|
+
untrusted: [], tolerance: 50, stability: 10, timeout: 25 }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def read
|
|
113
|
+
dir = File.dirname(@json)
|
|
114
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
|
115
|
+
unless File.exist?(@json)
|
|
116
|
+
File.open(@json, 'w') do |f|
|
|
117
|
+
f.write('{"elements" : {}}')
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
@elements = JSON.parse(File.read(@json))['elements']
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def write
|
|
124
|
+
File.open(@json, 'w') do |f|
|
|
125
|
+
f.write(JSON.pretty_generate('elements' => @elements))
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def find_routine(params, parent)
|
|
130
|
+
results = Results.new
|
|
131
|
+
answer = results.find(self, params, parent)
|
|
132
|
+
if !answer.empty? && answer.first.class != Locatine::Error
|
|
133
|
+
@elements[results.name] = results.info
|
|
134
|
+
write
|
|
135
|
+
end
|
|
136
|
+
answer
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def call_uri(path)
|
|
140
|
+
URI::HTTP.build(
|
|
141
|
+
host: @parsed_selenium.host,
|
|
142
|
+
port: @parsed_selenium.port,
|
|
143
|
+
path: "/wd/hub/session/#{@session}#{path}"
|
|
144
|
+
)
|
|
145
|
+
end
|
|
106
146
|
end
|
|
107
147
|
end
|
data/lib/locatine/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: locatine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '0.
|
|
4
|
+
version: '0.03050'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sergei Seleznev
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-03-
|
|
11
|
+
date: 2020-03-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -145,6 +145,8 @@ files:
|
|
|
145
145
|
- lib/locatine/logger.rb
|
|
146
146
|
- lib/locatine/results.rb
|
|
147
147
|
- lib/locatine/results_helpers/common.rb
|
|
148
|
+
- lib/locatine/results_helpers/comparing.rb
|
|
149
|
+
- lib/locatine/results_helpers/config.rb
|
|
148
150
|
- lib/locatine/results_helpers/find_by_magic.rb
|
|
149
151
|
- lib/locatine/results_helpers/guess.rb
|
|
150
152
|
- lib/locatine/results_helpers/info_generator.rb
|