locatine 0.01822 → 0.01839

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c42ba5ac7959a4ab71aa728327a9c28370feb16a
4
- data.tar.gz: a36821ec021212fbf125680d449242efba9abd2e
3
+ metadata.gz: 6085cdba5bc5b209bf24330ded9e2458c045d3e3
4
+ data.tar.gz: '0678ca74613066d304d6d8408ec18ef2dc5575da'
5
5
  SHA512:
6
- metadata.gz: cfa093835faa43a741931e8d012b3800774c959d4779c2541b73803fec067b233a2bc262d84779b9b5ddd0f950ad19d1852ef46ac88759eac364e980b60fbdab
7
- data.tar.gz: a77d487a503ee587b9ad4ad1491d0cf046a64502d680f9ebcef07f22fe1172ae7cf97f67de0d568deef4e9e2b59438ab6a3a9044b731b9a81740efbd002ac28e
6
+ metadata.gz: 10b9daf2cdd2139ddaf3f3054957ff467ba607681c692c6c7f3ea12c04b9d77845ab4a216003ccacdd6a84a5de901675f2708b2a17df967889d2a808c7dfbcfd
7
+ data.tar.gz: dfb7c5746b8219d8c90215c239d8aab91de686959911cd087d442a23d92e8564a8ff917f339cf2c22303b5722542f8fd32d61fea292b06b8196426741c680609
data/README.md ADDED
@@ -0,0 +1,323 @@
1
+ # Locatine
2
+
3
+ Element location tool based on Watir.
4
+
5
+ You are asking Locatine to find element for you.
6
+
7
+ It is asking you what element do you mean.
8
+
9
+ It is remembering your answer and collecting information about selected element.
10
+
11
+ After that it is finding element by itself.
12
+
13
+ If your element will be lost (due to id change for example) locatine will locate the most similar element.
14
+
15
+ That's it.
16
+
17
+ ## Stage of development:
18
+
19
+ Version of Locatine is **0.01839** only. It means so far this is an early alfa. You can use it in a real project if you are really risky person.
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem 'locatine'
27
+ ```
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install locatine
36
+
37
+ ## Usage
38
+
39
+ 1. Be sure that you have [Chrome browser](https://www.google.com/chrome/browser/desktop/) installed. It should work with any browser but something you can do in Chrome only
40
+ 2. Write the code
41
+ ```ruby
42
+ require 'locatine'
43
+ s = Locatine::Search.new
44
+ s.browser.goto("yourpage.com.com")
45
+ s.find(name: "element", scope: "Main").click
46
+ ```
47
+ 3. Run it in terminal with parameter LEARN=1 approximately like:
48
+
49
+ $ LEARN=1 ruby path_to_your_test.rb
50
+
51
+ 4. It will open the browser and transfer you to the yourpage.com.com
52
+ 5. Select element to represent *element* in the *Main* scope (you can click on it or select it in devtools)
53
+ 6. Click Locatine application icon at the browser panel
54
+ 7. And confirm the selection
55
+
56
+ ![Steps 4-5-6](readme/567.png)
57
+
58
+ 8. Now you can run the test without LEARN parameter and it will work.
59
+
60
+ ## Locatine app window
61
+
62
+ ### Element name
63
+
64
+ You can ask the app to save element with any name. This name should be used for element finding later.
65
+
66
+ ### Waiting for click
67
+
68
+ If you need to do some actions on page for debug purposes before defining the element you can turn off waiting for click. If Locatine is waiting for click every click is gonna be counted as element selection.
69
+
70
+ ### Single\\Collection mode
71
+
72
+ If you need to find a collection of elements. Turn collection mode on. And click two elements of the kind. Locatine will automatically select all the elements that are similar to selected
73
+
74
+ ### Clear selection
75
+
76
+ Click it to start element selection process from the very beginning.
77
+
78
+ ### Abort selection
79
+
80
+ Will forcedly stop the selection process. Use with care since ruby methods will return nils and errors since element is not selected properly. Use it when you finish to define a scope.
81
+
82
+ ### Confirm selection
83
+
84
+ When you've selected a correct element - confirm it in order to save.
85
+
86
+ ## Locatine::Search options
87
+
88
+ ```ruby
89
+ Locatine::Search.new(json: "./Locatine_files/default.json",
90
+ depth: 3,
91
+ browser: nil,
92
+ learn: ENV['LEARN'].nil? ? false : true,
93
+ stability_limit: 1000,
94
+ scope: "Default",
95
+ tolerance: 33,
96
+ visual_search: false)
97
+ ```
98
+
99
+ ### json
100
+
101
+ the file where data collected about elements will be stored
102
+
103
+ ### depth
104
+
105
+ shows how many info will be stored about each element
106
+
107
+ - 0 = everything about the element
108
+ - 1 = everything about the element and the parent of it
109
+ - 2 = everything about the element and the parent of it + one more parent
110
+
111
+ ### browser
112
+
113
+ if not provided new Watir::Browser will be started. Do not provide browser if you are going to use learn mode
114
+
115
+ ### learn
116
+
117
+ mode is used to train locatine to search your elements. By default is false. But if you are starting your test like:
118
+
119
+ $ LEARN=true ruby path_to_your_test.rb
120
+
121
+ it will turn learn to true by default.
122
+
123
+ ### scope
124
+
125
+ is a setting that is representing default scope (group) where elements will be stored by default
126
+
127
+ ### stability_limit
128
+
129
+ shows how much times attribute should be present to be considered a trusted one. The extremely large value means that locatine will hardly trust your code. Extremely low means that locatine will always believe that nothing in the code gonna be changed.
130
+
131
+ ### tolerance
132
+
133
+ If stored metrics of element (including attributes, text, css values and tags) were changed Locatine will find and suggest the most similar one. Tolerance is showing how different in per cent new element may be to the old one. If 0 (zero tolerance) - locatine will find nothing if element lost. If 50 it is enough for element to have only half of parameters of old element we are looking for to be returned. If 100 - at least something is found - it goes. Default if 67 (means only 33% of element should stay in element to be found and returned).
134
+
135
+ ### visual_search
136
+
137
+ locatine will count css values and position of element only if true. In that case locatine will not only read html code (attributes, tags, texts) but it will get css stylesheet for element, its position and size. In the most common case locatine is using attributes+tag+text to find the element. It is starting to use css styles of element and position only if element is lost in order to provide a better result and to mesure the similarity of the lost element and one that is found.
138
+
139
+ Position and size for element will be stored for the current resolution only. Start with new browser resolution will lead to deletion of all previous location\\size data.
140
+
141
+ Be careful! Set true only if appearance of your page is pretty stable.
142
+
143
+ ## Changing options on fly
144
+
145
+ You can get or set these values on fly. Like:
146
+
147
+ ```ruby
148
+ s = Locatine::Search.new(learn: true)
149
+ s.learn #=> true
150
+ s.learn = false
151
+ ```
152
+
153
+ ## Locatine::Search find options
154
+
155
+ ```ruby
156
+ s.find(name: "some name",
157
+ scope: "Default",
158
+ exact: false,
159
+ locator: {},
160
+ vars: {},
161
+ look_in: nil,
162
+ iframe: nil,
163
+ return_locator: false,
164
+ collection: false,
165
+ tolerance: nil)
166
+ ```
167
+ ### name
168
+
169
+ should be always provided. Name of element to look for. Must be uniq one per scope. Ideally name should be made of 2-4 words separated by spaces describing its nature ("pay bill button", "search input", etc.) It will help Locatine to find them.
170
+
171
+ ### scope
172
+
173
+ group of elements. Must be uniq per file. This is to help to store elements with same names from different pages in one file
174
+
175
+ ### exact
176
+
177
+ unless it is true locatine will always try to find lost element using all the power it has. Use exact: true if you want element to be lost in case of any significant change. If it is impossible to find element when exact: true locatine will return nil.
178
+
179
+ Be carefull: exact is working only when element is stable (has at least one parameter persistent for stability_limit times == well known by locatine). If element is not stable yet locatine will search for it anyway and maybe it will find something. So if you want to ensure that element does not exist you should use locator and exact at the same time. You may also set zero tolerance. Check it:
180
+
181
+ ```ruby
182
+ # Will return nil if there is no element id = 'not welcome'
183
+ s.find(name: "unexpected element", locator:{id: "not welcome"}, exact: true)
184
+
185
+ # Will return nil if well known element "unexpected element" is not present
186
+ # Will try to find and return at least something if "unexpected element" is not stable (well known)
187
+ # If there is nothing similar to "unexpected element" returns nil
188
+ s.find(name: "unexpected something", exact: true)
189
+
190
+ # Will return element only if the same element is present
191
+ # Changing of any attribute which is trusted by locatine will produce nil
192
+ s.find(name: "unexpected something", exact: true, tolerance: 0)
193
+ ```
194
+
195
+ ### locator
196
+
197
+ you may provide your own locator to use. Same syntax as in Watir:
198
+
199
+ ```ruby
200
+ find(name: "element with custom locator", locator: {xpath: "//custom"})
201
+ ```
202
+
203
+ ### vars
204
+
205
+ are used to pass dynamic attributes.
206
+
207
+ For example you have created an account on your site with
208
+
209
+ ```ruby
210
+ name == "stablePart_qljcrt24jh"
211
+ ```
212
+
213
+ where
214
+
215
+ ```ruby
216
+ random_string == "qljcrt24jh"
217
+ ```
218
+
219
+ was generated by random. Now you need to find the element with this part on the page. You can do
220
+
221
+ ```ruby
222
+ random_string #=> "qljcrt24jh"
223
+ find(name: "account name", vars: {text: random_string})
224
+ ```
225
+
226
+ Next time when your test will generate another random_string it will use new value.
227
+
228
+ ```ruby
229
+ vars = {text: random_substring} # If you want the text of element to be dynamic
230
+ vars = {tag: random_tag} # The tag
231
+ vars = {attribute_name: random_attr} # If attribute is dynamic (use name of the attribute)
232
+ # And two lines work with visual_search == true only
233
+ vars = {css_option: random_value} # If your css is dynamic
234
+ vars = {x: random_x} # x, y, width, height for element size and position
235
+ ```
236
+
237
+ And if you do not like it you can do:
238
+
239
+ ```ruby
240
+ random_string #=> "qljcrt24jh"
241
+ find(name: "account name", locator:{text: "stablePart_#{random_string}")
242
+ ```
243
+
244
+ ### look_in
245
+
246
+ is for method name taken from Watir::Browser item. It should be a method that returns collection of elements like (text_fields, divs, links, etc.). If this option is stated locatine will look for your element only among elements of that kind. Be careful with it in a learn mode. If your look_in setting and real element are from different types. Locatine will be unable to find it.
247
+
248
+ ### iframe
249
+
250
+ that is in order to find element inside of an iframe
251
+
252
+ ### return_locator
253
+
254
+ true is returning the locator of the element instead of element. Use with care if attributes of your elements are dynamic and you are in a learning mode.
255
+
256
+ ### collection
257
+
258
+ if true array of elements will be returned. If false only the one element (the first one found) will be returned.
259
+
260
+ ### tolerance
261
+
262
+ You can state custom tolerance for the element.
263
+
264
+ ## Scope
265
+
266
+ If you want to define a whole bunch of elements at once you can do:
267
+
268
+ ```ruby
269
+ search = Locatine::Search.new(learn: true)
270
+ search.get_scope(name: "Name of scope") # Will ask you about all the elements in scope
271
+ # or
272
+ scope = Locatine::Scope.new('Name of scope', search)
273
+ scope.define
274
+ ```
275
+
276
+ You will be able to select all the elements and collections for scope one by one. When it is finished click "Abort Selection" button to exit the loop.
277
+
278
+ ```ruby
279
+ # You can force use dynamic variables on define where is possible (same rules as for find)
280
+ vars = {text: "dynamic text",
281
+ tag: "span",
282
+ attrName: "part of dynamic attr-value"}
283
+ scope.define(vars) # Will ask you about all the elements in scope
284
+ # Same
285
+ search.get_scope(name: "Name of scope", vars: vars) # Will ask you...
286
+ # Finally when scope is defined
287
+ search.find(scope: "Name of scope",
288
+ name: "Name of element in scope",
289
+ vars: vars # Necessary if elements were defined with vars)
290
+ ```
291
+
292
+ Scope itself is not very useful now. But we are looking forward.
293
+
294
+ ## Other ways to use find
295
+
296
+ If the scope is set and you do not want to provide any additional options you can do:
297
+
298
+ ```ruby
299
+ s = Locatine::Search.new
300
+ s.find("just name of element")
301
+ ```
302
+
303
+ Also you can do:
304
+
305
+ ```ruby
306
+ s = Locatine::Search.new
307
+ s.browser.button(s.lctr("name of the button"))
308
+ # or
309
+ s.browser.button(s.lctr(name: "name of the button", scope: "Some form"))
310
+ # or
311
+ s.browser.button(s.lctr("name of the button", scope: "Some form"))
312
+ ```
313
+
314
+ That may be helpful in case of migration from plain watir to watir + locatine
315
+
316
+ If you want to find collection of elements you can use:
317
+
318
+ ```ruby
319
+ s = Locatine::Search.new
320
+ s.collect("group of elements") # Will return an array
321
+ # or
322
+ s.collect(name: "group of elements")
323
+ ```
@@ -14,7 +14,8 @@ async function creatingDiv(){
14
14
  "id":"locatine_magic_div",
15
15
  "locatinestyle": await get_value('magic_div') || "false",
16
16
  "locatinetitle": "ok",
17
- "locatinehint": "ok"
17
+ "locatinehint": "ok",
18
+ "locatine_name": ""
18
19
  };
19
20
  locatine_create_element(document.body, "div", options, "");
20
21
  const magic_cover = document.getElementById('locatine_magic_div');
@@ -53,13 +54,27 @@ async function setConfirm(magicDiv) {
53
54
  magicDiv.setAttribute("locatineconfirmed", confirmed);
54
55
  }
55
56
 
57
+ async function setName(magicDiv) {
58
+ const selectionName = magicDiv.getAttribute("locatine_name");
59
+ const nameMark = magicDiv.getAttribute("locatine_name_mark");
60
+ if (nameMark != "true") {
61
+ magicDiv.setAttribute("locatine_name", await get_value("locatineName"));
62
+ }
63
+ if ((selectionName != "") && (nameMark == "true")){
64
+ await set_value("locatineName", selectionName);
65
+ magicDiv.setAttribute("locatine_name_mark", "");
66
+ }
67
+ }
68
+
56
69
  async function refreshData(){
57
70
  const magicDiv = document.getElementById("locatine_magic_div");
58
71
  if (!document.getElementById("locatine_magic_div")){
59
72
  creatingDiv();
73
+ set_value("locatineName", "");
60
74
  } else {
61
75
  setStyle(magicDiv.getAttribute("locatinestyle"), magicDiv);
62
76
  setTitleHint(magicDiv);
77
+ setName(magicDiv);
63
78
  magicDiv.setAttribute("locatinecollection", await get_value("locatine_collection"));
64
79
  setConfirm(magicDiv);
65
80
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Locatine app",
3
- "version": "0.01822",
3
+ "version": "0.01839",
4
4
  "description": "Messaging from browser to main app",
5
5
  "devtools_page": "devtools.html",
6
6
  "permissions": ["activeTab", "storage", "contextMenus", "tabs"],
@@ -10,6 +10,12 @@
10
10
  font-size: 16px;
11
11
  }
12
12
 
13
+ .field {
14
+ width: 100%;
15
+ height: 30px;
16
+ display: block;
17
+ }
18
+
13
19
  .green {
14
20
  background-color: #4CAF50
15
21
  }
@@ -7,10 +7,12 @@
7
7
  <h2 class="header" id="mainTitle">Right now you are defining nothing. So no button will work</h2>
8
8
  <h3 class="hint" id="hint">But you can click it anyway :)</h3>
9
9
  <div class="block">
10
- <input class="blue button" id="watchSwitch" type="button" value="Do not watch"/>
11
- <input class="blue button" id="mode" type="button" value="Adding mode is enabled"/>
12
- <input class="red button" id="clearMark" type="button" value="Clear selection"/>
13
- <input class="green button" id="confirm" type="button" value="Confirm selection"/>
10
+ <input title="You can set your own element name here. Do not forget to use it in your code!" class="usual field" id="nameHandler" type="text" placeholder="Element name" value=""/>
11
+ <input title="If you need to do some actions on page for debug purposes before defining the element you can turn off waiting for click. If Locatine is waiting for click every click is gonna be counted as element selection." class="blue button" id="watchSwitch" type="button" value="Do not watch"/>
12
+ <input title="If you need to find a collection of elements. Turn collection mode on. And click two elements of the kind. Locatine will automatically select all the elements that are similar to selected" class="blue button" id="mode" type="button" value="Adding mode is enabled"/>
13
+ <input title="Click it to start element selection process from the very beginning." class="red button" id="clearMark" type="button" value="Clear selection"/>
14
+ <input title="Will forcedly stop the selection process. Use with care since ruby methods will return nils and errors since element is not selected properly. Use it when you finish to define a scope." class="red button" id="abort" type="button" value="Abort selection"/>
15
+ <input title="When you've selected a correct element - confirm it in order to save." class="green button" id="confirm" type="button" value="Confirm selection"/>
14
16
  </div>
15
17
  <script src="popup.js"></script>
16
18
  </body>
@@ -22,6 +22,9 @@ async function correct_buttons() {
22
22
  };
23
23
  document.getElementById("mainTitle").innerText = await get_value("locatine_title");
24
24
  document.getElementById("hint").innerText = await get_value("locatine_hint");
25
+ if ((document.getElementById("nameHandler").value != await get_value("locatineName")) && (!document.hasFocus())){
26
+ document.getElementById("nameHandler").value = (await get_value("locatineName") || "");
27
+ }
25
28
  }
26
29
 
27
30
  async function watch() {
@@ -36,14 +39,24 @@ function confirm() {
36
39
  set_value("locatine_confirm", true);
37
40
  }
38
41
 
42
+ function abort() {
43
+ set_value("locatine_confirm", 'abort');
44
+ }
45
+
39
46
  async function mode() {
40
47
  await set_value("locatine_collection", !(await get_value("locatine_collection")));
41
48
  }
42
49
 
50
+ async function doName() {
51
+ await set_value("locatineName", document.getElementById("nameHandler").value);
52
+ }
53
+
43
54
  document.getElementById("watchSwitch").onclick = function() {watch()};
44
55
  document.getElementById("clearMark").onclick = function() {clear()};
45
56
  document.getElementById("confirm").onclick = function() {confirm()};
46
57
  document.getElementById("mode").onclick = function() {mode()};
58
+ document.getElementById("abort").onclick = function() {abort()};
59
+ document.getElementById("nameHandler").oninput = function() {doName()};
47
60
 
48
61
  setInterval(function(){
49
62
  correct_buttons();
@@ -37,12 +37,12 @@ module Locatine
37
37
  end
38
38
 
39
39
  def equal_elements?(one, another)
40
- good = true
40
+ good = true unless one == {}
41
41
  one.each_pair do |depth, array|
42
42
  trusted = get_trusted(array).map do |i|
43
43
  i.reject { |k| k == 'stability' }
44
44
  end
45
- good &&= (trusted - another[depth] == [])
45
+ good &&= ((trusted - another[depth] == []) && !trusted.empty?)
46
46
  end
47
47
  good
48
48
  end
@@ -48,7 +48,7 @@ module Locatine
48
48
  end
49
49
 
50
50
  def return_old_selection(attrs, vars)
51
- return find_by_data(attrs, vars).to_a, attrss.to_h if attrs.to_h != {}
51
+ return find_by_data(attrs, vars).to_a, attrs.to_h if attrs.to_h != {}
52
52
 
53
53
  return nil, {}
54
54
  end
@@ -62,12 +62,11 @@ module Locatine
62
62
  return element, new_attributes
63
63
  end
64
64
 
65
- def what_was_selected(element, attributes, vars, name, scope)
65
+ def what_was_selected(element, attributes, vars)
66
66
  tag, index = tag_index
67
67
  send_to_app('locatineconfirmed', 'ok')
68
68
  mass_highlight_turn(element, false) if element
69
69
  element, attributes = working_on_selected(tag, index, vars, attributes)
70
- show_element(element, attributes, name, scope) if element
71
70
  return element, attributes
72
71
  end
73
72
 
@@ -88,7 +87,9 @@ module Locatine
88
87
  def user_selection(els, attrs, vars, name, scope)
89
88
  case get_from_app('locatineconfirmed')
90
89
  when 'selected'
91
- els, attrs = what_was_selected(els, attrs, vars, name, scope)
90
+ els, attrs = what_was_selected(els, attrs, vars)
91
+ name = suggest_name(name, attrs, vars)
92
+ show_element(els, attrs, name, scope) if els
92
93
  when 'declined'
93
94
  els, attrs = decline(els, name, scope)
94
95
  end
@@ -96,13 +97,16 @@ module Locatine
96
97
  end
97
98
 
98
99
  def listening(els, attrs, vars, name, scope)
99
- until get_from_app('locatineconfirmed') == 'true'
100
+ until %w[true abort].include?(get_from_app('locatineconfirmed'))
100
101
  sleep(0.1)
101
102
  els, attrs = user_selection(els, attrs, vars, name, scope)
102
103
  end
103
- return els, attrs if els
104
+ result = get_from_app('locatineconfirmed')
105
+ return els, attrs if els && result != 'abort'
106
+
107
+ els, attrs = decline(els, name, scope)
108
+ return els, attrs if result == 'abort'
104
109
 
105
- decline(els, name, scope)
106
110
  listening(els, attrs, vars, name, scope)
107
111
  end
108
112
 
@@ -114,8 +118,10 @@ module Locatine
114
118
  @cold_time = 0
115
119
  element, attributes = listening(element, attributes, vars, name, scope)
116
120
  @cold_time = nil
121
+ name_from_app = get_from_app('locatine_name')
122
+ name = name_from_app unless name_from_app.to_s.empty?
117
123
  response_action(element)
118
- return element, attributes
124
+ { element: element, attributes: attributes, name: name }
119
125
  end
120
126
  end
121
127
  end
@@ -20,6 +20,11 @@ module Locatine
20
20
  # Getting all the elements matching a locator
21
21
  def find_by_locator(locator)
22
22
  method = @type.nil? ? :elements : @type
23
+ begin
24
+ engine.element(locator).wait_until(timeout: @cold_time, &:exists?)
25
+ rescue StandardError
26
+ return nil
27
+ end
23
28
  results = engine.send(method, locator)
24
29
  return correct_method_detected(results) if collection?(results.class)
25
30
 
@@ -27,15 +32,12 @@ module Locatine
27
32
  end
28
33
 
29
34
  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? }
35
+ return nil if results.empty?
36
+
37
+ all = results.reject(&:stale?)
37
38
  return all unless all.empty?
38
- return nil if all.empty?
39
+
40
+ nil
39
41
  end
40
42
 
41
43
  def acceptable_method_detected(results, method, locator)
@@ -47,7 +47,11 @@ module Locatine
47
47
  result, attributes = locator_search(locator, vars)
48
48
  ok = result || ((locator != {}) && exact)
49
49
  result, attributes = core_search(name, scope, vars, exact) unless ok
50
- result, attributes = ask(scope, name, result, vars) if @learn
50
+ if @learn
51
+ answer = ask(scope, name, result, vars)
52
+ result = answer[:element]
53
+ attributes = answer[:attributes]
54
+ end
51
55
  return result, attributes
52
56
  end
53
57
 
@@ -9,8 +9,7 @@ module Locatine
9
9
  # We can highlight an element
10
10
  def highlight(element)
11
11
  script = "arguments[0].setAttribute('locatineclass','foundbylocatine')"
12
- ok = !element.stale? && element.exists?
13
- engine.execute_script(script, element) if ok
12
+ engine.execute_script(script, element)
14
13
  rescue StandardError
15
14
  warn_cannot_highlight(element.selector)
16
15
  end
@@ -19,8 +18,7 @@ module Locatine
19
18
  # We can unhighlight an element
20
19
  def unhighlight(element)
21
20
  script = "arguments[0].removeAttribute('locatineclass')"
22
- ok = !element.stale? && element.exists?
23
- engine.execute_script(script, element) if ok
21
+ engine.execute_script(script, element)
24
22
  rescue StandardError
25
23
  false
26
24
  # watir is not allowing to play with attributes of some elements
@@ -29,7 +27,8 @@ module Locatine
29
27
  ##
30
28
  # We can highlight\unhighlight tons of elements at once
31
29
  def mass_highlight_turn(mass, turn_on = true)
32
- mass.each do |element|
30
+ warn_much_highlight if turn_on && mass.length > 50
31
+ mass[0..49].each do |element|
33
32
  if turn_on
34
33
  highlight element
35
34
  else
@@ -37,7 +37,7 @@ module Locatine
37
37
  def response_action(element)
38
38
  send_to_app('locatineconfirmed', 'ok')
39
39
  send_has_response
40
- mass_highlight_turn(element, false)
40
+ mass_highlight_turn(element, false) if element
41
41
  send_to_app('locatinestyle', 'set_false')
42
42
  send_to_app('locatinestyle', 'ok', @browser) if @iframe
43
43
  sleep 1
@@ -0,0 +1,51 @@
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
@@ -7,6 +7,7 @@ module Locatine
7
7
  # Creates a new instance of Search
8
8
  #
9
9
  # Params:
10
+ #
10
11
  # +json+ is the name of file to store//read data. Default =>
11
12
  # "./Locatine_files/default.json"
12
13
  #
@@ -24,7 +25,7 @@ module Locatine
24
25
  # +scope+ will be used in search (if not provided) defaulkt is "Default"
25
26
  #
26
27
  # +tolerance+ Shows how similar must be an element found as alternative
27
- # to the lost one. Default is 33 which means that if less than 33% of
28
+ # to the lost one. Default is 67 which means that if less than 33% of
28
29
  # metrics of alternative elements are the same as of the lost element
29
30
  # will not be returned
30
31
  def initialize(json: './Locatine_files/default.json',
@@ -74,6 +75,9 @@ module Locatine
74
75
  #
75
76
  # +collection+ when true an array will be returned. When false - a
76
77
  # single element
78
+ #
79
+ # +tolerance+ It is possible to set a custom tolerance for every find. See
80
+ # examples in README
77
81
  def find(simple_name = nil,
78
82
  name: nil,
79
83
  scope: nil,
@@ -113,6 +117,12 @@ module Locatine
113
117
  def browser=(value)
114
118
  import_browser(value)
115
119
  end
120
+
121
+ def get_scope(name: 'Default', vars: {})
122
+ answer = Scope.new(name, self)
123
+ answer.define(vars) if @learn
124
+ answer
125
+ end
116
126
  end
117
127
  end
118
128
  end
@@ -60,6 +60,7 @@ module Locatine
60
60
  end
61
61
 
62
62
  def send_clear(name, scope)
63
+ name = 'some element' if name.to_s.empty?
63
64
  push_title "Now nothing is selected as #{name} in #{scope}"
64
65
  end
65
66
 
@@ -72,6 +73,7 @@ module Locatine
72
73
  end
73
74
 
74
75
  def send_selecting(name, scope)
76
+ name = 'some element' if name.to_s.empty?
75
77
  push_title "You are selecting #{name} in #{scope}"
76
78
  send_to_app('locatinehint', 'Toggle single//collection mode button if '\
77
79
  'you need. If you want to do some actions on the page toggle'\
@@ -120,6 +122,10 @@ module Locatine
120
122
  send_warn "Something was found as #{data} but we cannot highlight it"
121
123
  end
122
124
 
125
+ def warn_much_highlight(size)
126
+ send_warn "Only the first 50 elements of #{size} were highlighted."
127
+ end
128
+
123
129
  def warn_lost_found(name, scope)
124
130
  send_warn "Something was found as #{name} in #{scope}."
125
131
  end
@@ -0,0 +1,20 @@
1
+ module Locatine
2
+ ##
3
+ # Scope is the class representing group of elements
4
+ #
5
+ # Locatine has scopes
6
+ class Scope
7
+ def initialize(scope, search)
8
+ @search = search
9
+ @scope = scope
10
+ end
11
+
12
+ def define(vars = {})
13
+ item = @search.send(:ask, @scope, '', nil, vars)
14
+ return if item[:element].nil?
15
+
16
+ @search.send(:store, item[:attributes], @scope, item[:name])
17
+ define(vars)
18
+ end
19
+ end
20
+ end
@@ -9,15 +9,16 @@ require 'locatine/for_search/public'
9
9
  require 'locatine/for_search/saying'
10
10
  require 'locatine/for_search/helpers'
11
11
  require 'locatine/for_search/file_work'
12
+ require 'locatine/for_search/listening'
12
13
  require 'locatine/for_search/highlight'
13
14
  require 'locatine/for_search/data_logic'
14
15
  require 'locatine/for_search/find_logic'
15
16
  require 'locatine/for_search/find_by_css'
17
+ require 'locatine/for_search/name_helper'
16
18
  require 'locatine/for_search/dialog_logic'
17
19
  require 'locatine/for_search/find_by_magic'
18
20
  require 'locatine/for_search/find_by_guess'
19
21
  require 'locatine/for_search/data_generate'
20
- require 'locatine/for_search/listening'
21
22
  require 'locatine/for_search/xpath_generator'
22
23
  require 'locatine/for_search/find_by_locator'
23
24
 
@@ -37,6 +38,7 @@ module Locatine
37
38
  include Locatine::ForSearch::FindLogic
38
39
  include Locatine::ForSearch::Highlight
39
40
  include Locatine::ForSearch::FindByCss
41
+ include Locatine::ForSearch::NameHelper
40
42
  include Locatine::ForSearch::FindByMagic
41
43
  include Locatine::ForSearch::DialogLogic
42
44
  include Locatine::ForSearch::FindByGuess
@@ -1,6 +1,6 @@
1
1
  module Locatine
2
2
  # constants here...
3
- VERSION = '0.01822'.freeze
3
+ VERSION = '0.01839'.freeze
4
4
  NAME = 'locatine'.freeze
5
5
  HOME = if File.readable?("#{Dir.pwd}/lib/#{Locatine::NAME}")
6
6
  "#{Dir.pwd}/lib/#{Locatine::NAME}"
data/lib/locatine.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  require 'locatine/search'
2
+ require 'locatine/scope'
2
3
  require 'locatine/version'
data/readme/567.png ADDED
Binary file
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.01822'
4
+ version: '0.01839'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergei Seleznev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-28 00:00:00.000000000 Z
11
+ date: 2019-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -114,6 +114,7 @@ executables: []
114
114
  extensions: []
115
115
  extra_rdoc_files: []
116
116
  files:
117
+ - README.md
117
118
  - lib/locatine.rb
118
119
  - lib/locatine/app/background.js
119
120
  - lib/locatine/app/content.css
@@ -138,13 +139,16 @@ files:
138
139
  - lib/locatine/for_search/highlight.rb
139
140
  - lib/locatine/for_search/listening.rb
140
141
  - lib/locatine/for_search/merge.rb
142
+ - lib/locatine/for_search/name_helper.rb
141
143
  - lib/locatine/for_search/public.rb
142
144
  - lib/locatine/for_search/saying.rb
143
145
  - lib/locatine/for_search/xpath_generator.rb
144
146
  - lib/locatine/large_scripts/css.js
145
147
  - lib/locatine/large_scripts/dimensions.js
148
+ - lib/locatine/scope.rb
146
149
  - lib/locatine/search.rb
147
150
  - lib/locatine/version.rb
151
+ - readme/567.png
148
152
  homepage: https://github.com/sseleznevqa/locatine
149
153
  licenses:
150
154
  - MIT