locatine 0.02058 → 0.02539

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,27 +5,49 @@ module Locatine
5
5
  module DataLogic
6
6
  private
7
7
 
8
- def get_dynamic_attributes(element, vars)
8
+ def get_dynamic_attributes(data, vars)
9
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
10
+ data.each do |hash|
11
+ hash.each_pair do |key, full_value|
12
+ full_value.split(' ').each do |value|
13
+ next if key == 'locatineclass'
14
+
15
+ attrs.push some_attribute(value, key, vars)
16
+ end
17
+ end
14
18
  end
15
19
  attrs
16
20
  end
17
21
 
22
+ def some_attribute(value, key, vars)
23
+ replace = vars[key.to_sym]
24
+ push_hash(key,
25
+ replace ? value.gsub(replace, "\#{#{key}}") : value,
26
+ 'attribute')
27
+ end
28
+
29
+ def get_element_raw(element)
30
+ element = element.to_subtype.wd.wd if element.tag_name == 'iframe'
31
+ script = File.read("#{HOME}/large_scripts/element.js")
32
+ engine.execute_script(script, element)
33
+ end
34
+
18
35
  ##
19
36
  # Generating array of hashes representing data of the element
20
37
  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?
38
+ data = get_element_raw(element)
39
+ attrs = get_dynamic_attributes(data['attrs'], vars)
40
+ attrs.push get_dynamic_tag(data['tag'], vars)
41
+ attrs += get_dynamic_text(data['text'], vars)
42
+ attrs += get_dynamic_css(element, vars) if looking?(depth)
43
+ attrs.push get_dimensions(element) if looking?(depth)
26
44
  attrs
27
45
  end
28
46
 
47
+ def looking?(depth)
48
+ depth.to_i.zero? && visual?
49
+ end
50
+
29
51
  ##
30
52
  # Generating data for group of elements
31
53
  def generate_data(result, vars)
@@ -0,0 +1,40 @@
1
+ module Locatine
2
+ module ForSearch
3
+ ##
4
+ # Default settings for search are living here
5
+ module Defaults
6
+ private
7
+
8
+ def default_init_config
9
+ { json: './Locatine_files/default.json', depth: 3,
10
+ browser: nil, learn: ENV['LEARN'].nil? ? false : true,
11
+ stability_limit: 10, scope: 'Default',
12
+ tolerance: 67, visual_search: false,
13
+ no_fail: false, trusted: [],
14
+ untrusted: [], autolearn: nil }
15
+ end
16
+
17
+ def import_browser(browser)
18
+ selenium = browser.class.superclass == Selenium::WebDriver::Driver
19
+ b = right_browser unless browser
20
+ b = browser if browser.class == Watir::Browser
21
+ b = Watir::Browser.new(browser) if selenium
22
+ @browser = b
23
+ @default_styles = default_styles.to_a
24
+ end
25
+
26
+ def import_file(json)
27
+ @json = json
28
+ @folder = File.dirname(@json)
29
+ @name = File.basename(@json)
30
+ @data = read_create
31
+ end
32
+
33
+ def import_config(config)
34
+ config.each_pair do |key, value|
35
+ instance_variable_set("@#{key}", value)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -18,52 +18,9 @@ module Locatine
18
18
  return element, attributes
19
19
  end
20
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, attrs.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
21
  def what_was_selected(element, attributes, vars)
66
22
  tag, index = tag_index
23
+ # TODO: ELEMENT COULD BE ALREADY LOST HERE. WE HAVE BUG AROUND THAT CODE
67
24
  send_to_app('locatineconfirmed', 'ok')
68
25
  mass_highlight_turn(element, false) if element
69
26
  element, attributes = working_on_selected(tag, index, vars, attributes)
@@ -0,0 +1,80 @@
1
+ module Locatine
2
+ module ForSearch
3
+ ##
4
+ # Cooking element data for dialog
5
+ module ElementSelection
6
+ private
7
+
8
+ def add_selected_attributes(new_attributes, attributes)
9
+ if get_from_app('locatinecollection') == 'true'
10
+ get_commons(new_attributes, attributes.to_h)
11
+ else
12
+ new_attributes
13
+ end
14
+ end
15
+
16
+ def simple_attrs(tag, index, vars)
17
+ element = engine.elements(tag_name: tag)[index]
18
+ attrs = generate_data([element], vars).to_h
19
+ return element, attrs
20
+ end
21
+
22
+ def negative_need(element, vars, old_depth)
23
+ @depth = old_depth
24
+ warn_no_negatives
25
+ generate_data([element], vars).to_h
26
+ end
27
+
28
+ def complex_attrs(element, vars, old_depth = @depth)
29
+ attrs = get_family_info(element, vars).to_h
30
+ return negative_need(element, vars, old_depth) if attrs.length < @depth
31
+
32
+ if find_by_data(attrs, vars).length > 1
33
+ @depth += 1
34
+ return complex_attrs(element, vars, old_depth)
35
+ end
36
+ @depth = old_depth
37
+ attrs
38
+ end
39
+
40
+ def selected_element_attributes(tag, index, vars)
41
+ element, attrs = simple_attrs(tag, index, vars)
42
+ length = find_by_data(attrs, vars).to_a.length
43
+ attrs = complex_attrs(element, vars) if length > 1
44
+ attrs
45
+ end
46
+
47
+ def selected_element(tag, index, vars, attributes)
48
+ new_attributes = selected_element_attributes(tag, index, vars)
49
+ new_attributes = add_selected_attributes(new_attributes, attributes)
50
+ element = find_by_data(new_attributes, vars)
51
+ return element, new_attributes
52
+ end
53
+
54
+ def working_on_selected(tag, index, vars, attributes)
55
+ send_working(tag, index)
56
+ element, new_attributes = selected_element(tag, index, vars, attributes)
57
+ warn_dropping(tag, index) unless element[0].locate.located?
58
+
59
+ warn_type(tag) if @type && !element
60
+
61
+ return_selected(element, attributes, new_attributes, vars)
62
+ end
63
+
64
+ def return_old_selection(attrs, vars)
65
+ return find_by_data(attrs, vars).to_a, attrs.to_h if attrs.to_h != {}
66
+
67
+ return nil, {}
68
+ end
69
+
70
+ def return_selected(element, attributes, new_attributes, vars)
71
+ if !element && new_attributes.to_h != {}
72
+ send_lost
73
+ return return_old_selection(attributes, vars)
74
+
75
+ end
76
+ return element, new_attributes
77
+ end
78
+ end
79
+ end
80
+ end
@@ -17,13 +17,6 @@ module Locatine
17
17
  hash.merge(JSON.parse(File.read(@json))['data'])
18
18
  end
19
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
20
  def create_json_file
28
21
  f = File.new(@json, 'w')
29
22
  f.puts '{"data" : {}}'
@@ -35,6 +28,7 @@ module Locatine
35
28
  # Setting stability
36
29
  def set_stability(first, second)
37
30
  second = first if second.to_h == {}
31
+ first = second.merge first
38
32
  final = Hash.new { |hash, key| hash[key] = [] }
39
33
  first.each_pair do |depth, array|
40
34
  final[depth] = same_entries(array, second, depth, true).uniq
@@ -42,11 +36,18 @@ module Locatine
42
36
  final
43
37
  end
44
38
 
45
- def stability_bump(to_add, hash)
39
+ def stability_value(name, max, init = 0)
40
+ result = @trust_now.include?(name) ? max.to_s : (init.to_i + 1).to_s
41
+ result = '0' if @untrust_now.include?(name)
42
+ result
43
+ end
44
+
45
+ def stability_bump(to_add, hash, max)
46
46
  if to_add.empty? # new ones
47
- hash['stability'] = '1'
47
+ hash['stability'] = stability_value(hash['name'], max)
48
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
49
+ to_add[0]['stability'] = stability_value(to_add[0]['name'],
50
+ max, to_add[0]['stability'])
50
51
  end
51
52
  to_add.empty? ? [hash] : to_add
52
53
  end
@@ -8,57 +8,60 @@ module Locatine
8
8
  module FindByGuess
9
9
  private
10
10
 
11
- def main_guess(name)
11
+ def all_similar(name, page, vars)
12
12
  all = []
13
- name.split(' ').each do |part|
14
- all += guess_by_part(part)
13
+ array = generate_hash_array(name)
14
+ array.each do |hash|
15
+ all += catch(page, hash, vars, 0)
15
16
  end
16
17
  all
17
18
  end
18
19
 
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
20
+ def all_suggested(all, name, scope)
21
+ if all.empty?
22
+ send_no_guess(name, scope)
23
+ return nil
24
+ end
25
+ suggested = most_common_of(all).map do |element|
26
+ engine.elements(tag_name: element['tag'])[element['index'].to_i]
27
+ end
28
+ send_no_guess(name, scope) if suggested.length > 1
29
+ suggested
28
30
  end
29
31
 
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
32
+ def main_guess(name, scope, page, vars)
33
+ all = all_similar(name, page, vars)
34
+ all_suggested(all, name, scope)
38
35
  end
39
36
 
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)
37
+ def guessing(name, scope, page, vars)
38
+ suggested = main_guess(name, scope, page, vars)
39
+ suggest, attributes = final_of_all(suggested, vars) if suggested
40
+ return suggest, attributes
41
+ end
42
+
43
+ def find_by_guess(scope, name, vars, iteration = 0)
44
+ html = take_html
45
+ page = take_dom
46
+ suggest, attributes = guessing(name, scope, page, vars)
47
+ if html != take_html && iteration < 5
48
+ return find_by_guess(scope, name, vars, iteration + 1)
48
49
  end
49
- return guess, guess_data
50
+
51
+ warn_highly_unstable if iteration == 5
52
+ send_has_guess(name, scope) if suggest
53
+ return suggest, attributes.to_h
50
54
  end
51
55
 
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)
56
+ def generate_hash_array(name)
57
+ array = []
58
+ name.split(' ').each do |part|
59
+ array.push push_hash(part, '', 'attribute')
60
+ array.push push_hash('', part, 'attribute')
61
+ array.push push_hash('text', part, 'text')
62
+ array.push push_hash('tag', part, 'tag')
59
63
  end
60
- @cold_time = nil
61
- return guess, guess_data.to_h
64
+ array
62
65
  end
63
66
  end
64
67
  end
@@ -49,36 +49,6 @@ module Locatine
49
49
  correct_method_detected(results)
50
50
  end
51
51
 
52
- ##
53
- # Getting elements by tag
54
- def find_by_tag(hash, vars, depth = 0)
55
- correction = '//*' if depth.to_i > 0
56
- xpath = "//*[self::#{process_string(hash['value'], vars)}]"
57
- find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
58
- end
59
-
60
- ##
61
- # Getting elements by text
62
- def find_by_text(hash, vars, depth = 0)
63
- correction = '//*' if depth.to_i > 0
64
- value = process_string(hash['value'], vars)
65
- xpath = "//*[contains(text(), '#{value}')]"
66
- find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
67
- end
68
-
69
- ##
70
- # Getting elements by attribute
71
- def find_by_attribute(hash, vars, depth = 0)
72
- correction = '//*' if depth.to_i > 0
73
- full_part = '//*[@*'
74
- hash['name'].split('_').each do |part|
75
- full_part += "[contains(name(), '#{part}')]"
76
- end
77
- value = process_string(hash['value'], vars)
78
- xpath = full_part + "[contains(., '#{value}')]]"
79
- find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
80
- end
81
-
82
52
  ##
83
53
  # Getting all the elements via stored information
84
54
  def find_by_data(data, vars)
@@ -7,13 +7,34 @@ module Locatine
7
7
 
8
8
  ##
9
9
  # Getting all the elements via black magic
10
- def find_by_magic(name, scope, data, vars)
10
+ def find_by_magic(name, scope, data, vars, iteration = 0)
11
+ html = take_html
12
+ page = take_dom
13
+ suggested = magic_elements(name, scope, data, vars, page)
14
+ warn_unstable if page_changed?(page, html)
15
+ if html != take_html && iteration < 5
16
+ return find_by_magic(name, scope, data, vars, iteration + 1)
17
+ end
18
+
19
+ warn_highly_unstable if iteration == 5
20
+ suggest_by_all(suggested, data, vars, name, scope)
21
+ end
22
+
23
+ def page_changed?(page, html)
24
+ html != take_html || page != take_dom
25
+ end
26
+
27
+ ##
28
+ # We are taking every element that look at least a bit similar to one we
29
+ # are looking for
30
+ def magic_elements(name, scope, data, vars, page)
11
31
  warn_element_lost(name, scope)
12
- @cold_time = 0
13
- all = all_options(data, vars)
14
- @cold_time = nil
32
+ all = select_from_page(page, data, vars)
15
33
  raise_not_found(name, scope) if all.empty? && !@current_no_f
16
- suggest_by_all(all, data, vars, name, scope)
34
+ suggested = most_common_of(all).map do |element|
35
+ engine.elements(tag_name: element['tag'])[element['index'].to_i]
36
+ end
37
+ suggested
17
38
  end
18
39
 
19
40
  def similar_enough(data, attributes)
@@ -23,16 +44,14 @@ module Locatine
23
44
  sameness >= 100 - @current_t
24
45
  end
25
46
 
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?
47
+ def final_of_all(suggest, vars)
48
+ attributes = generate_data(suggest, vars) unless suggest.empty?
30
49
  return suggest, attributes
31
50
  end
32
51
 
33
52
  def suggest_by_all(all, data, vars, name, scope)
34
- suggest, attributes = best_of_all(all, vars)
35
- ok = similar_enough(data, attributes) unless suggest.nil?
53
+ suggest, attributes = final_of_all(all, vars)
54
+ ok = similar_enough(data, attributes) unless suggest.empty?
36
55
  raise_not_similar(name, scope) if !ok && !@current_no_f
37
56
  if ok
38
57
  warn_lost_found(name, scope)
@@ -41,76 +60,6 @@ module Locatine
41
60
  warn_not_found(name, scope)
42
61
  return nil, nil
43
62
  end
44
-
45
- def all_options(data, vars)
46
- all = []
47
- data.each_pair do |depth, array|
48
- get_trusted(array).each do |hash|
49
- all += one_option_array(hash, vars, depth).to_a
50
- end
51
- end
52
- all += full_find_by_css(data, vars) if visual?
53
- all += find_by_dimensions(data, vars) if visual?
54
- all
55
- end
56
-
57
- def min_max_by_size(middle, size)
58
- min = middle - (size.to_i * (200 - @current_t)) / 200
59
- max = middle + (size.to_i * (200 - @current_t)) / 200
60
- return min, max
61
- end
62
-
63
- def middle(sizes)
64
- x = sizes[0].to_i + (sizes[2].to_i / 2)
65
- y = sizes[1].to_i + (sizes[3].to_i / 2)
66
- return x, y
67
- end
68
-
69
- def dimension_search_field(sizes)
70
- x, y = middle(sizes)
71
- x_min, x_max = min_max_by_size(x, sizes[2])
72
- y_min, y_max = min_max_by_size(y, sizes[3])
73
- return x_min, x_max, y_min, y_max
74
- end
75
-
76
- def retrieve_mesures(data)
77
- size = window_size
78
- dimensions = data['0'].map do |i|
79
- i if (i['type'] == 'dimensions') && (i['name'] == size)
80
- end
81
- dimensions.compact
82
- end
83
-
84
- def sizez_from_dimensions(dimensions, vars)
85
- result = []
86
- dimensions.first['value'].split('*').each do |value|
87
- result.push(process_string(value, vars))
88
- end
89
- result
90
- end
91
-
92
- def find_by_dimensions(data, vars)
93
- dimensions = retrieve_mesures(data)
94
- if !dimensions.empty?
95
- sizes = sizez_from_dimensions(dimensions, vars)
96
- xmi, xma, ymi, yma = dimension_search_field(sizes)
97
- script = File.read("#{HOME}/large_scripts/dimensions.js")
98
- engine.execute_script(script, xmi, xma, ymi, yma).compact
99
- else
100
- []
101
- end
102
- end
103
-
104
- def one_option_array(hash, vars, depth)
105
- case hash['type']
106
- when 'tag'
107
- find_by_tag(hash, vars, depth)
108
- when 'text'
109
- find_by_text(hash, vars, depth)
110
- when 'attribute'
111
- find_by_attribute(hash, vars, depth)
112
- end
113
- end
114
63
  end
115
64
  end
116
65
  end