locatine 0.01659 → 0.01811
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/locatine/app/manifest.json +1 -1
- data/lib/locatine/for_search/data_generate.rb +100 -0
- data/lib/locatine/for_search/data_logic.rb +54 -0
- data/lib/locatine/for_search/dialog_logic.rb +118 -0
- data/lib/locatine/for_search/file_work.rb +65 -0
- data/lib/locatine/for_search/find_by_css.rb +47 -0
- data/lib/locatine/for_search/find_by_guess.rb +65 -0
- data/lib/locatine/for_search/find_by_locator.rb +87 -0
- data/lib/locatine/for_search/find_by_magic.rb +117 -0
- data/lib/locatine/for_search/find_logic.rb +77 -0
- data/lib/locatine/for_search/helpers.rb +100 -0
- data/lib/locatine/for_search/highlight.rb +42 -0
- data/lib/locatine/for_search/listening.rb +47 -0
- data/lib/locatine/for_search/merge.rb +38 -0
- data/lib/locatine/for_search/public.rb +118 -0
- data/lib/locatine/for_search/saying.rb +142 -0
- data/lib/locatine/for_search/xpath_generator.rb +50 -0
- data/lib/locatine/for_search.rb +6 -0
- data/lib/locatine/search.rb +32 -30
- data/lib/locatine/version.rb +1 -1
- metadata +19 -17
- data/lib/locatine/data_generate.rb +0 -98
- data/lib/locatine/data_logic.rb +0 -53
- data/lib/locatine/dialog_actions.rb +0 -71
- data/lib/locatine/dialog_logic.rb +0 -118
- data/lib/locatine/file_work.rb +0 -61
- data/lib/locatine/find_by_css.rb +0 -45
- data/lib/locatine/find_by_guess.rb +0 -62
- data/lib/locatine/find_by_locator.rb +0 -84
- data/lib/locatine/find_by_magic.rb +0 -114
- data/lib/locatine/find_logic.rb +0 -77
- data/lib/locatine/helpers.rb +0 -91
- data/lib/locatine/highlight.rb +0 -41
- data/lib/locatine/merge.rb +0 -36
- data/lib/locatine/public.rb +0 -116
- data/lib/locatine/xpath_generator.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 291cbcc01b2a41fb79a851461f620ab5e3089d9d
|
4
|
+
data.tar.gz: e8f0125d9caafe79dabf0834cdbd4e50737e5e42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1766f658d20d1fe90fb1a854ea493a23835961847578ec246820b36dc7aea3c55d304efdc99261de6badd13514c518e9dc6e4348ee1a57c151b8a82d7618221
|
7
|
+
data.tar.gz: 44ab3200dbe3290012e7ffc43f3a68d2729d44ef8b94bb5cf9e71fb13836df26b04e0b163e6e598bede348e5d6404fe2e4dbd9346a9e9b364d425e0e5e476246
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Locatine
|
2
|
+
module ForSearch
|
3
|
+
##
|
4
|
+
# Collecting data of element and making it dynamic
|
5
|
+
module DataGenerate
|
6
|
+
private
|
7
|
+
|
8
|
+
def real_text_of(element)
|
9
|
+
element.text == element.inner_html ? element.text : ''
|
10
|
+
end
|
11
|
+
|
12
|
+
def mesure(element)
|
13
|
+
xy = element.location
|
14
|
+
wh = element.size
|
15
|
+
return xy.x, xy.y, wh.width, wh.height
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_dynamic_tag(element, vars)
|
19
|
+
tag = element.tag_name
|
20
|
+
tag = "\#{tag}" if vars[:tag] == tag
|
21
|
+
push_hash('tag', tag, 'tag')
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_dynamic_text(element, vars)
|
25
|
+
attrs = []
|
26
|
+
real_text_of(element).split(/['" ]/).each do |word|
|
27
|
+
final = if !vars[:text].to_s.strip.empty?
|
28
|
+
word.gsub(vars[:text].to_s, "\#{text}")
|
29
|
+
else
|
30
|
+
word
|
31
|
+
end
|
32
|
+
attrs.push push_hash('text', final, 'text') unless final.empty?
|
33
|
+
end
|
34
|
+
attrs
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_dimension(name, value, vars)
|
38
|
+
s_name = name.to_s
|
39
|
+
value = value.to_s.gsub(vars[name], "\#{#{s_name}}") if vars[name]
|
40
|
+
value
|
41
|
+
end
|
42
|
+
|
43
|
+
def processed_dimensions(element, vars)
|
44
|
+
x, y, width, height = mesure(element)
|
45
|
+
x = process_dimension(:x, x, vars)
|
46
|
+
y = process_dimension(:y, y, vars)
|
47
|
+
width = process_dimension(:width, width, vars)
|
48
|
+
height = process_dimension(:height, height, vars)
|
49
|
+
return x, y, width, height
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_dimensions(element, vars)
|
53
|
+
resolution = window_size
|
54
|
+
x, y, w, h = processed_dimensions(element, vars)
|
55
|
+
push_hash(resolution, "#{x}*#{y}*#{w}*#{h}", 'dimensions')
|
56
|
+
end
|
57
|
+
|
58
|
+
def hash_by_style(style, value, vars)
|
59
|
+
value.gsub!(vars[style.to_sym], "\#{#{style}}") if vars[style.to_sym]
|
60
|
+
push_hash(style, value, 'css')
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_raw_css(element)
|
64
|
+
test_script = 'return typeof(arguments[0])'
|
65
|
+
ok = engine.execute_script(test_script, element) == 'object'
|
66
|
+
script = 'return getComputedStyle(arguments[0]).cssText'
|
67
|
+
return engine.execute_script(script, element) if ok
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_dynamic_css(element, vars)
|
71
|
+
attrs = []
|
72
|
+
raw = get_raw_css(element)
|
73
|
+
if raw
|
74
|
+
styles = css_text_to_hash(get_raw_css(element))
|
75
|
+
(styles.to_a - @default_styles).to_h.each_pair do |style, value|
|
76
|
+
hash = hash_by_style(style, value, vars)
|
77
|
+
attrs.push(hash) if hash
|
78
|
+
end
|
79
|
+
end
|
80
|
+
attrs
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Collecting attributes of the element
|
85
|
+
def get_attributes(element)
|
86
|
+
attributes = element.attributes
|
87
|
+
array = []
|
88
|
+
attributes.each_pair do |name, value|
|
89
|
+
next if name.to_s == 'locatineclass' # Should never happen
|
90
|
+
|
91
|
+
value.split(/['" ]/).reject(&:empty?).uniq.each do |part|
|
92
|
+
array.push('name' => name.to_s, 'type' => 'attribute',
|
93
|
+
'value' => part)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
array
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Locatine
|
2
|
+
module ForSearch
|
3
|
+
##
|
4
|
+
# Logic of collecting data of the element
|
5
|
+
module DataLogic
|
6
|
+
private
|
7
|
+
|
8
|
+
def get_dynamic_attributes(element, vars)
|
9
|
+
attrs = []
|
10
|
+
get_attributes(element).each do |hash|
|
11
|
+
value = vars[hash['name'].to_sym]
|
12
|
+
hash['value'].gsub!(value, "\#{#{hash['name']}}") if value
|
13
|
+
attrs.push hash
|
14
|
+
end
|
15
|
+
attrs
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Generating array of hashes representing data of the element
|
20
|
+
def get_element_info(element, vars, depth)
|
21
|
+
attrs = get_dynamic_attributes(element, vars)
|
22
|
+
attrs.push get_dynamic_tag(element, vars)
|
23
|
+
attrs += get_dynamic_text(element, vars)
|
24
|
+
attrs += get_dynamic_css(element, vars) if depth.to_i.zero? && visual?
|
25
|
+
attrs.push get_dimensions(element, vars) if depth.to_i.zero? && visual?
|
26
|
+
attrs
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Generating data for group of elements
|
31
|
+
def generate_data(result, vars)
|
32
|
+
family = {}
|
33
|
+
result.each do |item|
|
34
|
+
family = get_commons(get_family_info(item, vars), family)
|
35
|
+
end
|
36
|
+
family
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Getting element\\parents information
|
41
|
+
def get_family_info(element, vars)
|
42
|
+
i = 0
|
43
|
+
attributes = {}
|
44
|
+
while i != @depth
|
45
|
+
attributes[i.to_s] = get_element_info(element, vars, i)
|
46
|
+
i += 1
|
47
|
+
element = element.parent
|
48
|
+
i = @depth unless element.exists?
|
49
|
+
end
|
50
|
+
attributes
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Locatine
|
2
|
+
module ForSearch
|
3
|
+
##
|
4
|
+
# Logic of recieving element selected by user
|
5
|
+
module DialogLogic
|
6
|
+
private
|
7
|
+
|
8
|
+
def suggest_element(element, vars, name, scope)
|
9
|
+
attributes = {}
|
10
|
+
if !element.nil?
|
11
|
+
attributes = generate_data(element, vars)
|
12
|
+
send_found(name, scope, element.length)
|
13
|
+
elsif name.length >= 5
|
14
|
+
send_guessing(name, scope)
|
15
|
+
element, attributes = find_by_guess(scope, name, vars)
|
16
|
+
end
|
17
|
+
mass_highlight_turn(element) if element
|
18
|
+
return element, attributes
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_selected_attributes(new_attributes, attributes)
|
22
|
+
if get_from_app('locatinecollection') == 'true'
|
23
|
+
get_commons(new_attributes, attributes.to_h)
|
24
|
+
else
|
25
|
+
new_attributes
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def selected_element_attributes(tag, index, vars)
|
30
|
+
generate_data([engine.elements(tag_name: tag)[index]], vars).to_h
|
31
|
+
end
|
32
|
+
|
33
|
+
def selected_element(tag, index, vars, attributes)
|
34
|
+
new_attributes = selected_element_attributes(tag, index, vars)
|
35
|
+
new_attributes = add_selected_attributes(new_attributes, attributes)
|
36
|
+
element = find_by_data(new_attributes, vars)
|
37
|
+
return element, new_attributes
|
38
|
+
end
|
39
|
+
|
40
|
+
def working_on_selected(tag, index, vars, attributes)
|
41
|
+
send_working(tag, index)
|
42
|
+
element, new_attributes = selected_element(tag, index, vars, attributes)
|
43
|
+
warn_dropping(tag, index) unless element
|
44
|
+
|
45
|
+
warn_type(tag) if @type && !element
|
46
|
+
|
47
|
+
return_selected(element, attributes, new_attributes, vars)
|
48
|
+
end
|
49
|
+
|
50
|
+
def return_old_selection(attrs, vars)
|
51
|
+
return find_by_data(attrs, vars).to_a, attrss.to_h if attrs.to_h != {}
|
52
|
+
|
53
|
+
return nil, {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def return_selected(element, attributes, new_attributes, vars)
|
57
|
+
if !element && new_attributes.to_h != {}
|
58
|
+
send_lost
|
59
|
+
return return_old_selection(attributes, vars)
|
60
|
+
|
61
|
+
end
|
62
|
+
return element, new_attributes
|
63
|
+
end
|
64
|
+
|
65
|
+
def what_was_selected(element, attributes, vars, name, scope)
|
66
|
+
tag, index = tag_index
|
67
|
+
send_to_app('locatineconfirmed', 'ok')
|
68
|
+
mass_highlight_turn(element, false) if element
|
69
|
+
element, attributes = working_on_selected(tag, index, vars, attributes)
|
70
|
+
if element
|
71
|
+
mass_highlight_turn(element)
|
72
|
+
send_selected(element.length, name, scope)
|
73
|
+
end
|
74
|
+
return element, attributes
|
75
|
+
end
|
76
|
+
|
77
|
+
def decline(element, name, scope)
|
78
|
+
mass_highlight_turn(element, false) if element
|
79
|
+
send_to_app('locatineconfirmed', 'ok')
|
80
|
+
send_clear(name, scope)
|
81
|
+
return nil, {}
|
82
|
+
end
|
83
|
+
|
84
|
+
def user_selection(els, attrs, vars, name, scope)
|
85
|
+
case get_from_app('locatineconfirmed')
|
86
|
+
when 'selected'
|
87
|
+
els, attrs = what_was_selected(els, attrs, vars, name, scope)
|
88
|
+
when 'declined'
|
89
|
+
els, attrs = decline(els, name, scope)
|
90
|
+
end
|
91
|
+
return els, attrs
|
92
|
+
end
|
93
|
+
|
94
|
+
def listening(els, attrs, vars, name, scope)
|
95
|
+
until get_from_app('locatineconfirmed') == 'true'
|
96
|
+
sleep(0.1)
|
97
|
+
els, attrs = user_selection(els, attrs, vars, name, scope)
|
98
|
+
end
|
99
|
+
return els, attrs if els
|
100
|
+
|
101
|
+
decline(els, name, scope)
|
102
|
+
listening(els, attrs, vars, name, scope)
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# request send and waiting for an answer
|
107
|
+
def ask(scope, name, element, vars)
|
108
|
+
start_listening(scope, name)
|
109
|
+
element, attributes = suggest_element(element, vars, name, scope)
|
110
|
+
@cold_time = 0
|
111
|
+
element, attributes = listening(element, attributes, vars, name, scope)
|
112
|
+
@cold_time = nil
|
113
|
+
response_action(element)
|
114
|
+
return element, attributes
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Locatine
|
2
|
+
module ForSearch
|
3
|
+
##
|
4
|
+
# Methods about creating, reading and writing files
|
5
|
+
module FileWork
|
6
|
+
private
|
7
|
+
|
8
|
+
##
|
9
|
+
# Reading data from provided file which is set on init of the class
|
10
|
+
# instance
|
11
|
+
#
|
12
|
+
# If there is no dir or\and file they will be created
|
13
|
+
def read_create
|
14
|
+
FileUtils.mkdir_p(@folder) unless File.directory?(@folder)
|
15
|
+
hash = Hash.new { |h, k| h[k] = Hash.new { |hi, ki| hi[ki] = {} } }
|
16
|
+
create_json_file unless File.exist?(@json)
|
17
|
+
hash.merge(JSON.parse(File.read(@json))['data'])
|
18
|
+
end
|
19
|
+
|
20
|
+
def import_file(json)
|
21
|
+
@json = json
|
22
|
+
@folder = File.dirname(@json)
|
23
|
+
@name = File.basename(@json)
|
24
|
+
@data = read_create
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_json_file
|
28
|
+
f = File.new(@json, 'w')
|
29
|
+
f.puts '{"data" : {}}'
|
30
|
+
f.close
|
31
|
+
send_info "#{@json} is created"
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Setting stability
|
36
|
+
def set_stability(first, second)
|
37
|
+
second = first if second.to_h == {}
|
38
|
+
final = Hash.new { |hash, key| hash[key] = [] }
|
39
|
+
first.each_pair do |depth, array|
|
40
|
+
final[depth] = same_entries(array, second, depth, true).uniq
|
41
|
+
end
|
42
|
+
final
|
43
|
+
end
|
44
|
+
|
45
|
+
def stability_bump(to_add, hash)
|
46
|
+
if to_add.empty? # new ones
|
47
|
+
hash['stability'] = '1'
|
48
|
+
elsif to_add[0]['stability'].to_i < @stability_limit # old ones
|
49
|
+
to_add[0]['stability'] = (to_add[0]['stability'].to_i + 1).to_s
|
50
|
+
end
|
51
|
+
to_add.empty? ? [hash] : to_add
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Saving json
|
56
|
+
def store(attributes, scope, name)
|
57
|
+
@data[scope][name] = set_stability(attributes, @data[scope][name])
|
58
|
+
to_write = { 'data' => @data }
|
59
|
+
File.open(@json, 'w') do |f|
|
60
|
+
f.write(JSON.pretty_generate(to_write))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Locatine
|
2
|
+
module ForSearch
|
3
|
+
##
|
4
|
+
# Looking for elements by css values
|
5
|
+
module FindByCss
|
6
|
+
private
|
7
|
+
|
8
|
+
def css_array_by_data(data, vars)
|
9
|
+
q_css = []
|
10
|
+
get_trusted(data['0']).each do |hash|
|
11
|
+
if hash['type'] == 'css'
|
12
|
+
value = process_string(hash['value'], vars) if vars[hash['name']]
|
13
|
+
q_css.push("#{hash['name']}: #{value || hash['value']}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
q_css
|
17
|
+
end
|
18
|
+
|
19
|
+
def return_caught_elements(caught)
|
20
|
+
all = []
|
21
|
+
caught.each do |i|
|
22
|
+
@help_hash[i[0]] ||= engine.elements(tag_name: i[0].downcase).to_a
|
23
|
+
elm = @help_hash[i[0]][i[1].to_i]
|
24
|
+
all.push(elm) if elm
|
25
|
+
end
|
26
|
+
all
|
27
|
+
end
|
28
|
+
|
29
|
+
def select_elements_from_raws_by_css(q_css, raws)
|
30
|
+
all = []
|
31
|
+
@help_hash = {}
|
32
|
+
q_css.each do |item|
|
33
|
+
caught = (raws.select { |i| i[2].include?(item) })
|
34
|
+
all += return_caught_elements(caught)
|
35
|
+
end
|
36
|
+
all
|
37
|
+
end
|
38
|
+
|
39
|
+
def full_find_by_css(data, vars)
|
40
|
+
q_css = css_array_by_data(data, vars)
|
41
|
+
script = File.read("#{HOME}/large_scripts/css.js")
|
42
|
+
raws = engine.execute_script(script)
|
43
|
+
select_elements_from_raws_by_css(q_css, raws)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Locatine
|
2
|
+
module ForSearch
|
3
|
+
##
|
4
|
+
# If html code is good and name is related to the code, Locatine can guess
|
5
|
+
# it
|
6
|
+
#
|
7
|
+
# Methods for finding element by name only
|
8
|
+
module FindByGuess
|
9
|
+
private
|
10
|
+
|
11
|
+
def main_guess(name)
|
12
|
+
all = []
|
13
|
+
name.split(' ').each do |part|
|
14
|
+
all += guess_by_part(part)
|
15
|
+
end
|
16
|
+
all
|
17
|
+
end
|
18
|
+
|
19
|
+
def guess_by_part(part)
|
20
|
+
all = []
|
21
|
+
tag_xpath = "//#{part}#{not_magic_div}"
|
22
|
+
text_xpath = "//*[contains(text(),'#{part}')]#{not_magic_div}"
|
23
|
+
attr_xpath = "//*[@*[contains(., '#{part}')]]#{not_magic_div}"
|
24
|
+
all += find_by_locator(xpath: tag_xpath).to_a
|
25
|
+
all += find_by_locator(xpath: text_xpath).to_a
|
26
|
+
all += find_by_locator(xpath: attr_xpath).to_a
|
27
|
+
all
|
28
|
+
end
|
29
|
+
|
30
|
+
def full_guess(all, vars, name)
|
31
|
+
max = all.count(all.max_by { |i| all.count(i) })
|
32
|
+
if max >= name.split(' ').length
|
33
|
+
guess = (all.select { |i| all.count(i) == max }).uniq
|
34
|
+
guess_data = generate_data(guess, vars)
|
35
|
+
found_by_data = find_by_data(guess_data, vars)
|
36
|
+
end
|
37
|
+
return found_by_data, guess_data.to_h
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_guess(all, vars, name, scope)
|
41
|
+
guess, guess_data = full_guess(all, vars, name)
|
42
|
+
if guess.nil? || (engine.elements.length / guess.length <= 4)
|
43
|
+
send_no_guess(name, scope)
|
44
|
+
guess = nil
|
45
|
+
guess_data = {}
|
46
|
+
else
|
47
|
+
send_has_guess(guess.length, name, scope)
|
48
|
+
end
|
49
|
+
return guess, guess_data
|
50
|
+
end
|
51
|
+
|
52
|
+
def find_by_guess(scope, name, vars)
|
53
|
+
@cold_time = 0
|
54
|
+
all = main_guess(name)
|
55
|
+
if all.empty?
|
56
|
+
send_no_guess(name, scope)
|
57
|
+
else
|
58
|
+
guess, guess_data = check_guess(all, vars, name, scope)
|
59
|
+
end
|
60
|
+
@cold_time = nil
|
61
|
+
return guess, guess_data.to_h
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Locatine
|
2
|
+
module ForSearch
|
3
|
+
##
|
4
|
+
# Methods related to the most simple search by ready locator.
|
5
|
+
module FindByLocator
|
6
|
+
private
|
7
|
+
|
8
|
+
def collection?(the_class)
|
9
|
+
case the_class.superclass.to_s
|
10
|
+
when 'Watir::Element'
|
11
|
+
false
|
12
|
+
when 'Watir::ElementCollection'
|
13
|
+
true
|
14
|
+
else
|
15
|
+
collection?(the_class.superclass)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Getting all the elements matching a locator
|
21
|
+
def find_by_locator(locator)
|
22
|
+
method = @type.nil? ? :elements : @type
|
23
|
+
results = engine.send(method, locator)
|
24
|
+
return correct_method_detected(results) if collection?(results.class)
|
25
|
+
|
26
|
+
acceptable_method_detected(results, method, locator)
|
27
|
+
end
|
28
|
+
|
29
|
+
def correct_method_detected(results)
|
30
|
+
all = []
|
31
|
+
begin
|
32
|
+
results[0].wait_until(timeout: @cold_time, &:present?)
|
33
|
+
rescue StandardError
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
results.each { |item| all.push item if item.present? }
|
37
|
+
return all unless all.empty?
|
38
|
+
return nil if all.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
def acceptable_method_detected(results, method, locator)
|
42
|
+
warn_acceptable_type(method)
|
43
|
+
the_class = results.class
|
44
|
+
results = engine.elements(locator)
|
45
|
+
.to_a
|
46
|
+
.select { |item| item.to_subtype.class == the_class }
|
47
|
+
correct_method_detected(results)
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Getting elements by tag
|
52
|
+
def find_by_tag(hash, vars, depth = 0)
|
53
|
+
correction = '//*' if depth.to_i > 0
|
54
|
+
xpath = "//*[self::#{process_string(hash['value'], vars)}]"
|
55
|
+
find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Getting elements by text
|
60
|
+
def find_by_text(hash, vars, depth = 0)
|
61
|
+
correction = '//*' if depth.to_i > 0
|
62
|
+
value = process_string(hash['value'], vars)
|
63
|
+
xpath = "//*[contains(text(), '#{value}')]"
|
64
|
+
find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Getting elements by attribute
|
69
|
+
def find_by_attribute(hash, vars, depth = 0)
|
70
|
+
correction = '//*' if depth.to_i > 0
|
71
|
+
full_part = '//*[@*'
|
72
|
+
hash['name'].split('_').each do |part|
|
73
|
+
full_part += "[contains(name(), '#{part}')]"
|
74
|
+
end
|
75
|
+
value = process_string(hash['value'], vars)
|
76
|
+
xpath = full_part + "[contains(., '#{value}')]]"
|
77
|
+
find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Getting all the elements via stored information
|
82
|
+
def find_by_data(data, vars)
|
83
|
+
find_by_locator(xpath: generate_xpath(data, vars))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Locatine
|
2
|
+
module ForSearch
|
3
|
+
##
|
4
|
+
# Logic for finding lost element
|
5
|
+
module FindByMagic
|
6
|
+
private
|
7
|
+
|
8
|
+
##
|
9
|
+
# Getting all the elements via black magic
|
10
|
+
def find_by_magic(name, scope, data, vars, exact)
|
11
|
+
warn_element_lost(name, scope)
|
12
|
+
@cold_time = 0
|
13
|
+
all = all_options(data, vars)
|
14
|
+
@cold_time = nil
|
15
|
+
raise_not_found(name, scope) if all.empty? && !exact
|
16
|
+
suggest_by_all(all, data, vars, name, scope, exact)
|
17
|
+
end
|
18
|
+
|
19
|
+
def similar_enough(data, attributes)
|
20
|
+
same = same_entries(data['0'], attributes, '0').length
|
21
|
+
all = data['0'].length
|
22
|
+
sameness = (same * 100) / all
|
23
|
+
sameness >= 100 - @current_t
|
24
|
+
end
|
25
|
+
|
26
|
+
def best_of_all(all, vars)
|
27
|
+
max = all.count(all.max_by { |i| all.count(i) })
|
28
|
+
suggest = (all.select { |i| all.count(i) == max }).uniq unless max.zero?
|
29
|
+
attributes = generate_data(suggest, vars) unless suggest.nil?
|
30
|
+
return suggest, attributes
|
31
|
+
end
|
32
|
+
|
33
|
+
def suggest_by_all(all, data, vars, name, scope, exact)
|
34
|
+
suggest, attributes = best_of_all(all, vars)
|
35
|
+
ok = similar_enough(data, attributes) unless suggest.nil?
|
36
|
+
spawn = !ok && !exact
|
37
|
+
raise_not_similar(name, scope) if spawn
|
38
|
+
if ok
|
39
|
+
warn_lost_found(name, scope)
|
40
|
+
return suggest, attributes
|
41
|
+
end
|
42
|
+
warn_not_found(name, scope)
|
43
|
+
return nil, nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def all_options(data, vars)
|
47
|
+
all = []
|
48
|
+
data.each_pair do |depth, array|
|
49
|
+
get_trusted(array).each do |hash|
|
50
|
+
all += one_option_array(hash, vars, depth).to_a
|
51
|
+
end
|
52
|
+
end
|
53
|
+
all += full_find_by_css(data, vars) if visual?
|
54
|
+
all += find_by_dimensions(data, vars) if visual?
|
55
|
+
all
|
56
|
+
end
|
57
|
+
|
58
|
+
def min_max_by_size(middle, size)
|
59
|
+
min = middle - (size.to_i * (200 - @current_t)) / 200
|
60
|
+
max = middle + (size.to_i * (200 - @current_t)) / 200
|
61
|
+
return min, max
|
62
|
+
end
|
63
|
+
|
64
|
+
def middle(sizes)
|
65
|
+
x = sizes[0].to_i + (sizes[2].to_i / 2)
|
66
|
+
y = sizes[1].to_i + (sizes[3].to_i / 2)
|
67
|
+
return x, y
|
68
|
+
end
|
69
|
+
|
70
|
+
def dimension_search_field(sizes)
|
71
|
+
x, y = middle(sizes)
|
72
|
+
x_min, x_max = min_max_by_size(x, sizes[2])
|
73
|
+
y_min, y_max = min_max_by_size(y, sizes[3])
|
74
|
+
return x_min, x_max, y_min, y_max
|
75
|
+
end
|
76
|
+
|
77
|
+
def retrieve_mesures(data)
|
78
|
+
size = window_size
|
79
|
+
dimensions = data['0'].map do |i|
|
80
|
+
i if (i['type'] == 'dimensions') && (i['name'] == size)
|
81
|
+
end
|
82
|
+
dimensions.compact
|
83
|
+
end
|
84
|
+
|
85
|
+
def sizez_from_dimensions(dimensions, vars)
|
86
|
+
result = []
|
87
|
+
dimensions.first['value'].split('*').each do |value|
|
88
|
+
result.push(process_string(value, vars))
|
89
|
+
end
|
90
|
+
result
|
91
|
+
end
|
92
|
+
|
93
|
+
def find_by_dimensions(data, vars)
|
94
|
+
dimensions = retrieve_mesures(data)
|
95
|
+
if !dimensions.empty?
|
96
|
+
sizes = sizez_from_dimensions(dimensions, vars)
|
97
|
+
xmi, xma, ymi, yma = dimension_search_field(sizes)
|
98
|
+
script = File.read("#{HOME}/large_scripts/dimensions.js")
|
99
|
+
engine.execute_script(script, xmi, xma, ymi, yma).compact
|
100
|
+
else
|
101
|
+
[]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def one_option_array(hash, vars, depth)
|
106
|
+
case hash['type']
|
107
|
+
when 'tag'
|
108
|
+
find_by_tag(hash, vars, depth)
|
109
|
+
when 'text'
|
110
|
+
find_by_text(hash, vars, depth)
|
111
|
+
when 'attribute'
|
112
|
+
find_by_attribute(hash, vars, depth)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|