locatine 0.02542 → 0.02878

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +269 -296
  3. data/bin/locatine-daemon.rb +4 -2
  4. data/lib/locatine.rb +14 -2
  5. data/lib/locatine/daemon.rb +48 -56
  6. data/lib/locatine/daemon_helpers/methods.rb +85 -0
  7. data/lib/locatine/element.rb +32 -0
  8. data/lib/locatine/error.rb +14 -0
  9. data/lib/locatine/logger.rb +69 -0
  10. data/lib/locatine/results.rb +128 -0
  11. data/lib/locatine/results_helpers/common.rb +68 -0
  12. data/lib/locatine/results_helpers/find_by_magic.rb +121 -0
  13. data/lib/locatine/results_helpers/guess.rb +76 -0
  14. data/lib/locatine/results_helpers/info_generator.rb +79 -0
  15. data/lib/locatine/{for_search → results_helpers}/xpath_generator.rb +18 -11
  16. data/lib/locatine/scripts/element.js +40 -0
  17. data/lib/locatine/scripts/page.js +54 -0
  18. data/lib/locatine/scripts/parent.js +6 -0
  19. data/lib/locatine/session.rb +107 -0
  20. data/lib/locatine/version.rb +4 -2
  21. metadata +40 -49
  22. data/lib/locatine/app/background.js +0 -8
  23. data/lib/locatine/app/content.css +0 -43
  24. data/lib/locatine/app/content.js +0 -149
  25. data/lib/locatine/app/devtools.html +0 -1
  26. data/lib/locatine/app/devtools.js +0 -3
  27. data/lib/locatine/app/manifest.json +0 -20
  28. data/lib/locatine/app/popup.css +0 -47
  29. data/lib/locatine/app/popup.html +0 -19
  30. data/lib/locatine/app/popup.js +0 -65
  31. data/lib/locatine/daemon_helpers.rb +0 -52
  32. data/lib/locatine/for_search.rb +0 -6
  33. data/lib/locatine/for_search/data_generate.rb +0 -67
  34. data/lib/locatine/for_search/data_logic.rb +0 -98
  35. data/lib/locatine/for_search/defaults.rb +0 -40
  36. data/lib/locatine/for_search/dialog_logic.rb +0 -107
  37. data/lib/locatine/for_search/element_selection.rb +0 -80
  38. data/lib/locatine/for_search/file_work.rb +0 -67
  39. data/lib/locatine/for_search/find_by_guess.rb +0 -67
  40. data/lib/locatine/for_search/find_by_locator.rb +0 -59
  41. data/lib/locatine/for_search/find_by_magic.rb +0 -65
  42. data/lib/locatine/for_search/find_logic.rb +0 -79
  43. data/lib/locatine/for_search/helpers.rb +0 -106
  44. data/lib/locatine/for_search/highlight.rb +0 -41
  45. data/lib/locatine/for_search/listening.rb +0 -48
  46. data/lib/locatine/for_search/merge.rb +0 -40
  47. data/lib/locatine/for_search/name_helper.rb +0 -51
  48. data/lib/locatine/for_search/page_work.rb +0 -126
  49. data/lib/locatine/for_search/public.rb +0 -179
  50. data/lib/locatine/for_search/saying.rb +0 -196
  51. data/lib/locatine/large_scripts/css.js +0 -21
  52. data/lib/locatine/large_scripts/dimensions.js +0 -17
  53. data/lib/locatine/large_scripts/element.js +0 -30
  54. data/lib/locatine/large_scripts/page.js +0 -60
  55. data/lib/locatine/scope.rb +0 -88
  56. data/lib/locatine/search.rb +0 -67
@@ -1,41 +0,0 @@
1
- module Locatine
2
- module ForSearch
3
- ##
4
- # Locatine can highlight elements
5
- module Highlight
6
- private
7
-
8
- ##
9
- # We can highlight an element
10
- def highlight(element)
11
- script = "arguments[0].setAttribute('locatineclass','foundbylocatine')"
12
- engine.execute_script(script, element)
13
- rescue StandardError
14
- warn_cannot_highlight(element.selector)
15
- end
16
-
17
- ##
18
- # We can unhighlight an element
19
- def unhighlight(element)
20
- script = "arguments[0].removeAttribute('locatineclass')"
21
- engine.execute_script(script, element)
22
- rescue StandardError
23
- false
24
- # watir is not allowing to play with attributes of some elements
25
- end
26
-
27
- ##
28
- # We can highlight\unhighlight tons of elements at once
29
- def mass_highlight_turn(mass, turn_on = true)
30
- warn_much_highlight(mass.length) if turn_on && mass.length > 50
31
- mass[0..49].each do |element|
32
- if turn_on
33
- highlight element
34
- else
35
- unhighlight element
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,48 +0,0 @@
1
- module Locatine
2
- module ForSearch
3
- ##
4
- # Simple actions about communicating with chrome extension (and user)
5
- module Listening
6
- private
7
-
8
- ##
9
- # Getting attribute of locatine div (way to communicate)
10
- def get_from_app(what)
11
- fix_iframe
12
- result = engine.wd.execute_script(
13
- %[if (document.getElementById('locatine_magic_div')) {
14
- const magic_div = document.getElementById('locatine_magic_div');
15
- return magic_div.getAttribute("#{what}")}]
16
- )
17
- fix_iframe
18
- result
19
- end
20
-
21
- ##
22
- # Sending request to locatine app
23
- def start_listening(scope, name)
24
- send_to_app('locatinestyle', 'blocked', @browser) if @iframe
25
- send_to_app('locatinestyle', 'set_true')
26
- send_to_app('locatineconfirmed', 'ok')
27
- send_selecting(name, scope)
28
- sleep 0.5
29
- end
30
-
31
- def tag_index
32
- tag = get_from_app('tag')
33
- tag = tag.downcase unless tag.nil?
34
- index = get_from_app('index').to_i
35
- return tag, index
36
- end
37
-
38
- def response_action(element)
39
- send_to_app('locatineconfirmed', 'ok')
40
- send_has_response
41
- mass_highlight_turn(element, false) if element
42
- send_to_app('locatinestyle', 'set_false')
43
- send_to_app('locatinestyle', 'ok', @browser) if @iframe
44
- sleep 1
45
- end
46
- end
47
- end
48
- end
@@ -1,40 +0,0 @@
1
- module Locatine
2
- module ForSearch
3
- ##
4
- # Getting commons of two piles of elements data. To find all similar to them
5
- module Merge
6
- private
7
-
8
- def select_same(where, hash)
9
- where.select do |item|
10
- (item['name'] == hash['name']) &&
11
- (item['value'] == hash['value']) &&
12
- (item['type'] == hash['type'])
13
- end
14
- end
15
-
16
- def same_entries(array, second, depth, stability_up = false)
17
- result = []
18
- array.each do |hash|
19
- item = second[depth]
20
- to_add = item.nil? ? [] : select_same(second[depth], hash)
21
- max = max_stability(second[depth]).to_i + 1
22
- to_add = stability_bump(to_add, hash, max) if stability_up
23
- result += to_add
24
- end
25
- result
26
- end
27
-
28
- ##
29
- # Merging data of two elements (new data is to find both)
30
- def get_commons(first, second)
31
- second = first if second == {}
32
- final = Hash.new { |hash, key| hash[key] = [] }
33
- first.each_pair do |depth, array|
34
- final[depth] = same_entries(array, second, depth)
35
- end
36
- final
37
- end
38
- end
39
- end
40
- end
@@ -1,51 +0,0 @@
1
- module Locatine
2
- module ForSearch
3
- ##
4
- # We have a module that helps name elements
5
- module NameHelper
6
- private
7
-
8
- def good_name(main, vars)
9
- good = %w[name title id role text]
10
- tmp = main.select { |i| good.any? { |k| i['name'].include?(k) } }
11
- words = (tmp.map { |i| process_string(i['value'], vars) }).uniq
12
- words.sample
13
- end
14
-
15
- def so_so_name(main, vars)
16
- all = main.select { |i| i['type'] == 'attribute' }
17
- words = all.map { |i| process_string(i['value'], vars) }
18
- words.sample
19
- end
20
-
21
- def some_name(main, vars)
22
- result = good_name(main, vars)
23
- result = so_so_name(main, vars) if result.nil?
24
- result = "undescribed #{generate_word}" if result.nil?
25
- result
26
- end
27
-
28
- def suggest_name(name, attrs, vars)
29
- if name.to_s.empty?
30
- tag = attrs['0'].select { |i| i['type'] == 'tag' }
31
- tag = process_string(tag[0]['value'], vars)
32
- name = "#{some_name(attrs['0'], vars)} #{tag}"
33
- end
34
- suggest = name
35
- send_to_app('locatine_name', suggest)
36
- send_to_app('locatine_name_mark', 'true')
37
- suggest
38
- end
39
-
40
- def generate_word(pairs = 3)
41
- ss = 'qwrtpsdfghjklzxcvbnm'.split('')
42
- sa = 'eyuioa'.split('')
43
- str = ''
44
- pairs.times do
45
- str += ss.sample + sa.sample
46
- end
47
- str
48
- end
49
- end
50
- end
51
- end
@@ -1,126 +0,0 @@
1
- module Locatine
2
- module ForSearch
3
- ##
4
- # Methods about getting full information about opened page>
5
- # And methods for stalkibg around the page in oreder to find something.
6
- module PageWork
7
- private
8
-
9
- def matcher
10
- { 'tag' => ->(data) { take_by_tag(*data) },
11
- 'text' => ->(data) { take_by_text(*data) },
12
- 'attribute' => ->(data) { take_by_attribute(*data) },
13
- 'css' => ->(data) { take_by_css(*data) } }
14
- end
15
-
16
- def take_dom
17
- script = File.read("#{HOME}/large_scripts/page.js")
18
- engine.execute_script(script)
19
- end
20
-
21
- def select_from_page(page, data, vars)
22
- all = [] # No result is a valid result too
23
- data.each_pair do |depth, array|
24
- get_trusted(array).each do |hash|
25
- all += catch(page, hash, vars, depth)
26
- end
27
- end
28
- all
29
- end
30
-
31
- def catch(page, hash, vars, depth)
32
- all = []
33
- hash['value'] = process_string(hash['value'], vars)
34
- page.each do |element|
35
- all += take_match(element, depth, hash, vars)
36
- all += catch(element['children'], hash, vars, depth)
37
- end
38
- all.uniq
39
- end
40
-
41
- def take_match(element, depth, hash, vars)
42
- if hash['type'] == 'dimensions'
43
- return take_by_dimensions(hash, element, depth, vars)
44
- end
45
-
46
- matcher.fetch(hash['type']).call([hash, element, depth])
47
- end
48
-
49
- def take_by_tag(hash, elt, depth)
50
- return kids([elt], depth) if elt['tag'].downcase.include?(hash['value'])
51
-
52
- []
53
- end
54
-
55
- def take_by_text(hash, elt, depth)
56
- return kids([elt], depth) if elt['text'].include?(hash['value'])
57
-
58
- []
59
- end
60
-
61
- def take_attribute_check(hash, elt)
62
- if !hash['name'].to_s.empty? && !hash['value'].to_s.empty?
63
- return elt['attrs'][hash['name']].to_s
64
- end
65
-
66
- elt['attrs'].to_s
67
- end
68
-
69
- def take_by_attribute(hash, elt, depth)
70
- str = hash['value'].to_s.empty? ? hash['name'].to_s : hash['value'].to_s
71
- ok = take_attribute_check(hash, elt).include?(str)
72
- return kids([elt], depth) if ok
73
-
74
- []
75
- end
76
-
77
- def dimensions_for_search(hash, vars)
78
- values = hash['value'].split('*').map(&:to_i)
79
- values[0] = vars[:x].to_i if vars[:x]
80
- values[1] = vars[:y].to_i if vars[:y]
81
- values
82
- end
83
-
84
- def dimensions_from_page(elt)
85
- [elt['coordinates']['top'].to_i, elt['coordinates']['bottom'].to_i,
86
- elt['coordinates']['left'].to_i, elt['coordinates']['right'].to_i]
87
- end
88
-
89
- def take_by_dimensions(hash, elt, depth, vars)
90
- return [] if !visual? || hash['name'] != window_size
91
-
92
- return kids([elt], depth) if in_recatngle?(hash, elt, vars)
93
-
94
- []
95
- end
96
-
97
- def in_recatngle?(hash, elt, vars)
98
- cleft, ctop, cwidth, cheight = dimensions_for_search(hash, vars)
99
- top, bottom, left, right = dimensions_from_page(elt)
100
- (cleft >= left) && (cleft + cwidth <= right) &&
101
- (ctop >= top) && (ctop + cheight <= bottom)
102
- end
103
-
104
- def take_by_css(hash, elt, depth)
105
- return [] unless visual?
106
-
107
- string = "#{hash['name']}: #{hash['value']}"
108
- return kids([elt], depth) if elt['style'].include?(string)
109
-
110
- []
111
- end
112
-
113
- # If depth != 0 we should return all children subchildren.
114
- def kids(array, depth)
115
- answer = []
116
- return array if depth.to_i.zero?
117
-
118
- array.each do |one|
119
- answer += one['children']
120
- answer += kids(one['children'], depth)
121
- end
122
- answer
123
- end
124
- end
125
- end
126
- end
@@ -1,179 +0,0 @@
1
- module Locatine
2
- module ForSearch
3
- ##
4
- # Public methods of the Search class
5
- module Public
6
- ##
7
- # Creates a new instance of Search
8
- #
9
- # Params:
10
- #
11
- # +json+ is the name of file to store//read data. Default =>
12
- # "./Locatine_files/default.json"
13
- #
14
- # +depth+ shows how many data will be stored for element.
15
- #
16
- # +browser+ is the instance of Watir::Browser. Unless provided it gonna
17
- # be created with locatine-app onboard.
18
- #
19
- # +learn+ shows will locatine ask for assistance from user or will fail
20
- # on error. learn is true when LEARN parameter is set in environment.
21
- #
22
- # +stability_limit+ shows max times attribute should be present and
23
- # checked to consider it trusted.
24
- #
25
- # +scope+ will be used in search (if not provided) defaulkt is "Default"
26
- #
27
- # +tolerance+ Shows how similar must be an element found as alternative
28
- # to the lost one. Default is 67 which means that if less than 33% of
29
- # metrics of alternative elements are the same as of the lost element
30
- # will not be returned
31
- #
32
- # +visual_search+ locatine will use position and style if true
33
- #
34
- # +no_fail+ if true locatine is not producing errors on element loss.
35
- #
36
- # +trusted+ array of names of attributes and element params to use
37
- # in search always.
38
- #
39
- # +untrusted+ array of names of attributes and element params to use
40
- # in search never.
41
- #
42
- # +autolearn+ determines will locatine study an element or not. true means
43
- # locatine will always study it (slow). false means it won't study it
44
- # unless it was lost and found. If not stated locatine will turn set it
45
- # true if at least one element was lost.
46
- def initialize(config = {})
47
- init_config = default_init_config.merge(config)
48
- import_browser init_config.delete :browser
49
- import_file init_config.delete :json
50
- import_config init_config
51
- end
52
-
53
- ##
54
- # Looking for the element
55
- #
56
- # Params:
57
- #
58
- # +scope+ is a parameter that is used to get information about the
59
- # element from @data. Default is "Default"
60
- #
61
- # +name+ is a parameter that is used to get information about the
62
- # element from @data. Must not be nil.
63
- #
64
- # +exact+ if true locatine will be forced to use only basic search.
65
- # Default is false
66
- #
67
- # +locator+ if not empty it is used for the first attempt to find the
68
- # element. Default is {}
69
- #
70
- # +vars+ hash of variables that will be used for dynamic attributes.
71
- # See readme for example
72
- #
73
- # +look_in+ only elements of that kind will be used. Use Watir::Browser
74
- # methods returning collections (:text_fields, :links, :divs, etc.)
75
- #
76
- # +iframe+ if provided locatine will look for elements inside of it
77
- #
78
- # +return_locator+ is to return a valid locator of the result
79
- #
80
- # +collection+ when true an array will be returned. When false - a
81
- # single element
82
- #
83
- # +tolerance+ It is possible to set a custom tolerance for every find. See
84
- # examples in README
85
- #
86
- # +no_fail+ if true locatine is not producing errors on element loss.
87
- #
88
- # +trusted+ array of names of attributes and element params to use
89
- # in search always.
90
- #
91
- # +untrusted+ array of names of attributes and element params to use
92
- # in search never.
93
- def find(simple_name = nil,
94
- name: nil,
95
- scope: nil,
96
- exact: false,
97
- locator: {},
98
- vars: {},
99
- look_in: nil,
100
- iframe: nil,
101
- return_locator: false,
102
- collection: false,
103
- tolerance: nil,
104
- no_fail: nil,
105
- trusted: nil,
106
- untrusted: nil)
107
- name = set_name(simple_name, name)
108
- set_env_for_search(look_in, iframe, tolerance,
109
- no_fail, trusted, untrusted)
110
- scope ||= @scope.nil? ? 'Default' : @scope
111
- result, attributes = full_search(name, scope, vars, locator, exact)
112
- return { xpath: generate_xpath(attributes, vars) } if result &&
113
- return_locator
114
-
115
- to_subtype(result, collection)
116
- end
117
-
118
- ##
119
- # Find alias with return_locator option enforced
120
- def lctr(*args)
121
- enforce({ return_locator: true }, *args)
122
- end
123
-
124
- ##
125
- # Find alias with collection option enforced
126
- def collect(*args)
127
- enforce({ collection: true }, *args)
128
- end
129
-
130
- def json=(value)
131
- import_file(value)
132
- end
133
-
134
- def browser=(value)
135
- import_browser(value)
136
- end
137
-
138
- ##
139
- # Returns an instance of the Scope class. Starts define if learn == true
140
- #
141
- # Params:
142
- #
143
- # +name+ is a parameter that stores name of the scope.
144
- # Default is "Default"
145
- #
146
- # +vars+ is a hash which will be used to generate dynamic attributes.
147
- # See readme for explanation.
148
- def get_scope(name: 'Default', vars: {})
149
- answer = Scope.new(name, self)
150
- answer.define(vars) if @learn
151
- answer
152
- end
153
-
154
- ##
155
- # Find alias with zero tolerance option enforced
156
- def check(*args)
157
- enforce({ tolerance: 0 }, *args)
158
- end
159
-
160
- ##
161
- # Collection alias with zero tolerance option enforced
162
- def check_collection(*args)
163
- enforce({ tolerance: 0, collection: true }, *args)
164
- end
165
-
166
- ##
167
- # Collection alias with exact option on
168
- def exact_collection(*args)
169
- enforce({ exact: true, collection: true }, *args)
170
- end
171
-
172
- ##
173
- # Find alias with exact option on
174
- def exact(*args)
175
- enforce({ exact: true }, *args)
176
- end
177
- end
178
- end
179
- end