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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: df3f8d995c895faf833681632462dcd884e73bce
4
- data.tar.gz: 8885ecd8b1513df7cac86761a22e02acdb692f03
2
+ SHA256:
3
+ metadata.gz: 457cb5d21eae999673da17f8c5c200181755f846946e81c81d9a23bbafa85528
4
+ data.tar.gz: f3ae98ffc268889f4781126b71106ffc99c29c73f9cd4e8321743388fb56bf70
5
5
  SHA512:
6
- metadata.gz: 0234243bf852972ac60752c0be0232a2c427ce0f40f21fefaaa2cf8e7a32403e2c33f8761fcaa28712ffd8bd0960b1d2c46f5f3846e45c56e51edf5b5dc2831e
7
- data.tar.gz: ec7071e6b671a03d6cf2fe034b510f914af84e403248ddcd6a3d230a9c8cf9ba4f2c291ffe9722a5a58436d3208754b5898d1a9dc94d00f9016772fcf2a6b117
6
+ metadata.gz: ed6f3ad8a5e29ea3b3e672b5a5cbd006571fa9536821dbc0b1467b005cf0998efc19425ba17f166a608cf84b5a884908c1d718275dbbebd0a56372a85f10d988
7
+ data.tar.gz: a7e5b86fe05b8710fd5bbd675733937dab017f8c27d8e27e4dbd5865da9313211775877c931a56c36414e0f1a3d94d3c66365a511f543daad4022fb00be91b14
data/README.md CHANGED
@@ -1,22 +1,24 @@
1
1
  # Locatine
2
2
 
3
- Element location tool based on Watir.
3
+ Locatine is a proxy between your code and selenium.
4
4
 
5
- You are asking Locatine to find element for you.
5
+ It remembers element when you are finding it via selenium.
6
6
 
7
- It is asking you what element do you mean.
7
+ It stores the findings to the json file for the future use.
8
8
 
9
- It is remembering your answer and collecting information about selected element.
9
+ On the next search if element is lost Locatine will try to find it anyway using previously collected information.
10
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.
11
+ So your locator will be a little bit more stable than before.
14
12
 
15
13
  That's it.
16
14
 
17
15
  ## Stage of development:
18
16
 
19
- Version of Locatine is **0.02542** only. It means so far this is an alfa. You can use it in a real project if you are a risky person.
17
+ Version of Locatine is **0.02878**. The 4th version since rewriting. 5-15 next versions is dedicated to bug fixing, tweaking.
18
+
19
+ ## Attention
20
+
21
+ This version of Locatine is not compatible to previous.
20
22
 
21
23
  ## Installation
22
24
 
@@ -36,469 +38,440 @@ Or install it yourself as:
36
38
 
37
39
  ## Usage
38
40
 
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
+ 1. Be sure that you have [Chrome browser](https://www.google.com/chrome/browser/desktop/) installed.
42
+ 2. Be sure that you have [chromedriver](https://chromedriver.chromium.org/) installed.
43
+ 3. Write the code (using your language - ruby is an example)
41
44
 
42
45
  ```ruby
43
- require 'locatine'
44
- s = Locatine::Search.new
45
- s.browser.goto("yourpage.com.com")
46
- s.find(name: "element", scope: "Main").click
46
+ driver = Selenium::WebDriver.for :remote, url: "http://localhost:7733/wd/hub", desired_capabilities: :chrome
47
+ driver.navigate.to("yourpage.com.com")
48
+ driver.find_element(xpath: "//*[@id = 'element']")
49
+ driver.quit
47
50
  ```
48
51
 
49
- 3. Run it in terminal with parameter LEARN=1 approximately like:
52
+ 4. Run the locatine daemon
50
53
 
51
- $ LEARN=1 ruby path_to_your_test.rb
54
+ ```
55
+ $ SELENIUM=http://localhost:4444 locatine-daemon.rb --port=7733
56
+ ```
52
57
 
53
- 4. It will open the browser and transfer you to the yourpage.com.com
54
- 5. Click Locatine application icon at the browser panel
55
- 6. Select element to represent *element* in the *Main* scope (you can click on it or select it in devtools)
56
- 7. And confirm the selection
58
+ 5. SELENIUM - is for url where selenium hub is started, port is the port for your code to connect. 4444 and 7733 are defaults.
59
+ 6. Run your code
60
+ 7. Data of element will be stored to ./default.json file.
61
+ 8. Now if id of your element is changed on the page Locatine will show a warning and gonna try to retrieve it.
62
+ 9. See [example](https://github.com/sseleznevqa/locatine/tree/master/examples) to see how it really works.
57
63
 
58
- ![U can see an image here. On github)](readme/567.png)
64
+ ## Session
59
65
 
60
- 8. Now you can run the test without LEARN parameter and it will work.
66
+ Each time when you initializing new selenium session, locatine session is created as well.
61
67
 
62
- ## Locatine app window
68
+ It is used to store default options for search.
63
69
 
64
- ### Element name
70
+ There are two ways to set options of the session:
65
71
 
66
- You can ask the app to save element with any name. This name should be used for element finding later.
72
+ The most simple is to send it via desired capabilities like (ruby example again)
67
73
 
68
- ### Waiting for click
74
+ ```ruby
75
+ caps = Selenium::WebDriver::Remote::Capabilities.
76
+ chrome('locatine' => {'json' => '/your/path/elements.json'})
77
+ driver = Selenium::WebDriver.
78
+ for :remote, url: "http://localhost:7733/wd/hub", desired_capabilities: caps
79
+ ```
69
80
 
70
- 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.
81
+ This way is recommended because of the simplicity.
71
82
 
72
- ### Single\\Collection mode
83
+ Another way is to set options after the session was created by making [POST request to '/locatine/session/%session_id%'](https://github.com/sseleznevqa/locatine#post-to-wdhubsession)
73
84
 
74
- 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
85
+ ## Settings to pass
75
86
 
76
- ### Clear selection
87
+ ### json
77
88
 
78
- Click it to start element selection process from the very beginning.
89
+ Provide a string here.
79
90
 
80
- ### Abort selection
91
+ Default is 'locatine-working-dir/locatine_files/default.json'
81
92
 
82
- 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.
93
+ **json** is the path of the file that will be used to store data collected about elements by locatine-daemon.
83
94
 
84
- ### Confirm selection
95
+ It is recommended to use a different json for every test (or test group) in order to have lots of small and easily readable files and not the giant one.
85
96
 
86
- When you've selected a correct element - confirm it in order to save.
97
+ **NOTE! Only unix filesystems are supported so far.**
87
98
 
88
- ## Locatine::Search options
99
+ ### depth
89
100
 
90
- ```ruby
91
- Locatine::Search.new(json: "./Locatine_files/default.json",
92
- depth: 3,
93
- browser: nil,
94
- learn: ENV['LEARN'].nil? ? false : true,
95
- stability_limit: 1000,
96
- scope: "Default",
97
- tolerance: 33,
98
- visual_search: false,
99
- no_fail: false,
100
- trusted: [],
101
- untrusted: [],
102
- autolearn: nil)
103
- ```
101
+ Provide a non negative integer here.
104
102
 
105
- ### json
103
+ Default is 3
106
104
 
107
- the file where data collected about elements will be stored
105
+ **depth** value shows how deeply locatine will research the element.
108
106
 
109
- ### depth
107
+ 0 - means that only the retrieved element will be remembered.
110
108
 
111
- shows how many info will be stored about each element
109
+ ```html
110
+ <div id="element to find"></div>
111
+ ```
112
112
 
113
- - 0 = everything about the element
114
- - 1 = everything about the element and the parent of it
115
- - 2 = everything about the element and the parent of it + one more parent
113
+ 1 - means that the retrieved element and its ancestor will be examined:
116
114
 
117
- ### browser
115
+ ```html
116
+ <div id="ancestor">
117
+ <div id="element to find"></div>
118
+ </div>
119
+ ```
118
120
 
119
- if not provided new Watir::Browser will be started. Do not provide browser if you are going to use learn mode
121
+ 2 - means that two ancestors will be remembered.
120
122
 
121
- ### learn
123
+ And so on and so forth.
122
124
 
123
- mode is used to train locatine to search your elements. By default is false. But if you are starting your test like:
125
+ The higher depth the more easily locatine-daemon will find the element including the case when the element is lost (attributes are changed).
124
126
 
125
- $ LEARN=true ruby path_to_your_test.rb
127
+ On the other side large depth is making internal locator more unstable since it is requires stability of all the ancestors as well.
126
128
 
127
- it will turn learn to true by default.
129
+ Read more about [finding elements](https://github.com/sseleznevqa/locatine#finding-elements)
128
130
 
129
- ### scope
131
+ **NOTE! Taking additional information (larger depth) costs an additional time while retrieving element and when looking for the lost one**
130
132
 
131
- is a setting that is representing default scope (group) where elements will be stored by default
133
+ ### trusted
132
134
 
133
- ### stability_limit
135
+ Provide an array of strings here.
134
136
 
135
- 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.
137
+ Default is []
136
138
 
137
- ### tolerance
139
+ Usually if some attribute or tag or text is changing locatine is marking it as untrusted data and not using it in search till it appears enough times to be considered stable again.
138
140
 
139
- 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).
141
+ But locatine will always use for search for element something that is listed as trusted here.
140
142
 
141
- ### visual_search
143
+ Use attribute name (like ['id']) for id attribute, use ['text'] for text and ['tag'] to trust the tag of element.
142
144
 
143
- 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.
145
+ **NOTE! ['text'] will affect both - text of element and attribute of element that is named 'text'**
144
146
 
145
- 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.
147
+ ### untrusted
146
148
 
147
- Be careful! Set true only if appearance of your page is pretty stable.
149
+ Provide an array of strings here.
148
150
 
149
- ### no_fail
151
+ Default is []
150
152
 
151
- When element is lost and no_fail is true you will get nil for single element and [] for collection. If no_fail is false (which is default) and locatine cannot find something you will face an error.
153
+ Working completely opposite to [trusted](https://github.com/sseleznevqa/locatine#trusted)
152
154
 
153
- ### trusted/untrusted
155
+ Locatine will never consider reliable attributes or text or tag if it is listed as untrusted. It will be never used to search elements.
154
156
 
155
- If you are sure that some attribute (or something) is not good(generated by random, not uniq, etc.) you can forbid to use it in search. You can write attribute name, "text", "tag", or css attribute name (if you are using visual_search)
157
+ Use attribute name (like ['id']) for id attribute, use ['text'] for text and ['tag'] to untrust the tag of element.
156
158
 
157
- On the other hand you can force locatine to always trust something with trusted.
159
+ **NOTE! ['text'] will affect both - text of element and attribute of element that is named 'text'**
158
160
 
159
- ### autolearn
161
+ ### stability
160
162
 
161
- Determines wether Locatine will study elements by default or not.
163
+ Provide a positive integer here.
162
164
 
163
- If true Locatine will always check element for changes even if it is found properly (to catch for example adding of a new attribute). This is slow.
165
+ Default is 10
164
166
 
165
- If false Locatine will study element only in case when it is lost.
167
+ At first locatine trusts everything except [untrusted](https://github.com/sseleznevqa/locatine#untrusted). But sometimes attribute value, text or tag changes. In that case those new values will be not used in search anymore.
166
168
 
167
- If not stated Locatine will use false until it is not facing any lost element. After the first lost element it will be studying everything (true).
169
+ **stability** shows how much times new attribute or text or tag should be found without changes to be considered reliable to be used for search once again.
168
170
 
169
- Notice that if autolearn is false Locatine is not bumping the stability values of attributes for elements which were found normally.
171
+ ### tolerance
170
172
 
171
- ## Changing options on fly
173
+ Provide an integer in a range from 0 to 100
172
174
 
173
- You can get or set these values on fly. Like:
175
+ Default is 50
174
176
 
175
- ```ruby
176
- s = Locatine::Search.new(learn: true)
177
- s.learn #=> true
178
- s.learn = false
179
- ```
177
+ If your element is changed locatine is trying to find it anyway. Tolerance shows how similar the new element should be to the ild one to be returned.
180
178
 
181
- ## Locatine::Search find options
179
+ Example:
182
180
 
183
- ```ruby
184
- s.find(name: "some name",
185
- scope: "Default",
186
- exact: false,
187
- locator: {},
188
- vars: {},
189
- look_in: nil,
190
- iframe: nil,
191
- return_locator: false,
192
- collection: false,
193
- tolerance: nil,
194
- no_fail: nil,
195
- trusted: [],
196
- untrusted: [])
181
+ ```html
182
+ <!--Old element-->
183
+ <div id="too" class="old one">element</div>
184
+ <!--New element-->
185
+ <div id="too" class="new one">element</div>
197
186
  ```
198
- ### name
199
-
200
- 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.
201
187
 
202
- ### scope
188
+ 5 pieces of information will be collected about an old element (tag == div, id == too, class == old, class ==one, text == element)
203
189
 
204
- group of elements. Must be uniq per file. This is to help to store elements with same names from different pages in one file
190
+ 4 parts are staying the same after changes. So similarity will be counted like (4*100/5 == 80)
205
191
 
206
- ### locator
192
+ Since similarity(80)>=100-tolerance(50) the new element will be returned.
207
193
 
208
- you may provide your own locator to use. Same syntax as in Watir:
194
+ But for the case:
209
195
 
210
- ```ruby
211
- find(name: "element with custom locator", locator: {xpath: "//custom"})
196
+ ```html
197
+ <!--Old element-->
198
+ <div id="too" class="old one">element</div>
199
+ <!--New element-->
200
+ <div id="lost" class="new two">element</div>
212
201
  ```
213
202
 
214
- ### vars
203
+ Similarity will be only 40 which is less than 100-50. It means that no element will be returned.
215
204
 
216
- are used to pass dynamic attributes.
205
+ So default tolerance == 50 means that at least 50% of element data should be equal to stored data for element to be found.
217
206
 
218
- For example you have created an account on your site with
207
+ Only data of the element itself is counted here.
219
208
 
220
- ```ruby
221
- name == "stablePart_qljcrt24jh"
222
- ```
209
+ **NOTE! 0 (zero tolerance) means that locatine will not even try to find the lost element. 100 tolerance is too opportunistic**
223
210
 
224
- where
211
+ ### timeout
225
212
 
226
- ```ruby
227
- random_string == "qljcrt24jh"
228
- ```
213
+ Provide an positive integer here (up to 25 is recommended)
229
214
 
230
- was generated by random. Now you need to find the element with this part on the page. You can do
215
+ Default is 25
231
216
 
232
- ```ruby
233
- random_string #=> "qljcrt24jh"
234
- find(name: "account name", vars: {text: random_string})
235
- ```
217
+ **timeout** shows the maximum amount of seconds locatine will try to find something.
236
218
 
237
- Next time when your test will generate another random_string it will use new value.
219
+ Since default net timeout for most selenium implementations is 30 seconds, 25 is a good idea.
238
220
 
239
- ```ruby
240
- vars = {text: random_substring} # If you want the text of element to be dynamic
241
- vars = {tag: random_tag} # The tag
242
- vars = {attribute_name: random_attr} # If attribute is dynamic (use name of the attribute)
243
- # And two lines work with visual_search == true only
244
- vars = {css_option: random_value} # If your css is dynamic
245
- vars = {x: random_x} # x, y for element position
246
- ```
221
+ **NOTE! It's not an exact time. When timeout is reached it means for locatine that it is time to finish the party. But it cannot be finished instantly and the speed of the process may slightly vary.**
222
+
223
+ ## Finding elements
247
224
 
248
- And if you do not like it you can do:
225
+ All the requests that are retrieving elements are wrapped by locatine-daemon.
249
226
 
250
227
  ```ruby
251
- random_string #=> "qljcrt24jh"
252
- find(name: "account name", locator:{text: "stablePart_#{random_string}")
228
+ caps = Selenium::WebDriver::Remote::Capabilities.chrome('locatine' =>
229
+ {'json' => "#{Dir.pwd}/elements.json"})
230
+ driver = Selenium::WebDriver.for :remote,
231
+ url: "http://localhost:7733/wd/hub",
232
+ desired_capabilities: caps
233
+ # Page that has <div id='element' class='1 2 3'>Text</div>
234
+ driver.navigate.to page 1
235
+ # Getting element for the first ешьу
236
+ element = driver.find_element(xpath: "//*[@id='element']")
237
+ # We are changing id of the element
238
+ driver.execute_script("arguments[0].setAttribute('id', 'lost')", element)
239
+ # Element is gonna be found. Even with locator that is broken
240
+ expect(driver.find_element(xpath: "//*[@id='element']").text).to eq "Text"
241
+ driver.quit
253
242
  ```
254
243
 
255
- ### look_in
256
-
257
- 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.
258
-
259
- ### iframe
260
-
261
- that is in order to find element inside of an iframe
244
+ When locatine sees some locator for the first time it is not only returning the element& It is collecting some info about it. As the result if locator will suddenly become broken locatine will make an attempt to find the element using the data collected.
262
245
 
263
- ### return_locator
246
+ ### Magic comments
264
247
 
265
- 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.
248
+ If the usual locator only is provided locatine will treat it like a name for element. But if you want you can force locatine to remember it by name defined by you.
266
249
 
267
- ### collection
250
+ Just add name at the end of xpath like ['*name*'] or like /\**name*\*/ after css selector. For example:
268
251
 
269
- if true array of elements will be returned. If false only the one element (the first one found) will be returned.
252
+ ```ruby
253
+ element = driver.find_element(xpath: "//*[@id='element']['test element']")
254
+ element = driver.find_element(css: "#element/*test element*/")
255
+ ```
270
256
 
271
- ### tolerance
257
+ **NOTE! Those locators are valid. If you will switch back to selenium-webdriver it will work normally. The 'test element' text will be treated like a comment that is not affecting the locator body.**
272
258
 
273
- You can state custom tolerance for the element.
259
+ Once defined with name it can be called without locator part at all:
274
260
 
275
- ### exact
261
+ ```ruby
262
+ element = driver.find_element(xpath: "['test element']")
263
+ element = driver.find_element(css: "/*test element*/")
264
+ ```
276
265
 
277
- It is disabling attempts to find element by advanced algorithms. If locator is provided find method will use only locator. If there is no locator only the basic search will be performed.
266
+ **NOTE! Locators above will work only with locatine!**
278
267
 
279
- ### no_fail
268
+ ### Dynamic locators
280
269
 
281
- no_fail option that will work for that search only.
270
+ Always add names to dynamic locators. For example if you have some account_id which is new for every test and goes to an id attribute do
282
271
 
283
- ### trusted//untrusted
272
+ ```ruby
273
+ account_id #=> 1234567890
274
+ element = driver.find_element(xpath: "//*[@id='#{account_id}']['test element']")
275
+ element = driver.find_element(css: "##{account_id}/*test element*/")
276
+ ```
284
277
 
285
- You can set trusted elements just for search
278
+ **NOTE! If there will be no name for the element that is changing locator for each run locatine will treat it like a new element each time. That will lead to overcrowding of your json file**
286
279
 
287
- ## Scope
280
+ ### Zero tolerance shortcut
288
281
 
289
- If you want to define a whole bunch of elements at once you can do:
282
+ If you need to check that element exists or not most probably you do not want locatine to look for the similar one. You can set zero tolerance (return only 100% same element) by adding word 'exactly' to the name.
290
283
 
291
284
  ```ruby
292
- search = Locatine::Search.new(learn: true)
293
- search.get_scope(name: "Name of scope") # Will ask you about all the elements in scope
294
- # or
295
- scope = Locatine::Scope.new('Name of scope', search)
296
- scope.define
285
+ element = driver.
286
+ find_element(xpath: "//*[@id='element']['exactly test element']")
287
+ element = driver.find_element(css: "#element/*exactly test element*/")
297
288
  ```
298
289
 
299
- 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.
290
+ **NOTE! Zero tolerance will be used for that particular search only. Other searches will use session values**
300
291
 
301
- You can force use dynamic variables on define where is possible (same rules as for find):
292
+ ### Other ways to pass data to locatine
293
+
294
+ There is another way to pass data to locatine. You can provide a json string as a comment.
302
295
 
303
296
  ```ruby
304
- vars = {text: "dynamic text",
305
- tag: "span",
306
- attrName: "part of dynamic attr-value"}
307
- scope.define(vars) # Will ask you about all the elements in scope
308
- # Same
309
- search.get_scope(name: "Name of scope", vars: vars) # Will ask you...
310
- # Finally when scope is defined
311
- search.find(scope: "Name of scope",
312
- name: "Name of element in scope",
313
- vars: vars # Necessary if elements were defined with vars)
297
+ require 'json' # That is to make everything a little bit simpler
298
+ params = {name: "test element", tolerance: 0}.to_json
299
+ #=> {\"name\":\"test element\",\"tolerance\":0}
300
+ element = driver.find_element(xpath: "//*[@id='element'][#{params}']")
301
+ element = driver.find_element(css: "#element/*#{params}*/")
314
302
  ```
315
303
 
316
- ### Methods of scope
304
+ **NOTE! Those requests will provide same results as previous because they have identical meaning**
317
305
 
318
- If you want to get a hash with all elements that are defined in scope:
306
+ Like that you can set for each search any custom options (except json)
319
307
 
320
- ```ruby
321
- # Lost elements will be found if possible!
322
- search.get_scope(name: "Name of scope").all
323
- # => {"element name": {
324
- # elements: Array of Watir::Element,
325
- # locator: valid xpath locator
326
- # },
327
- # "next element name":...
328
- # }
329
- ```
308
+ For more information about possible options read [here](https://github.com/sseleznevqa/locatine#session)
309
+
310
+ Additionally you can provide a custom locator inside of the comment json string.
330
311
 
331
- If you want to check presence of all elements:
312
+ We are using 'json' library to make json string here.
332
313
 
333
314
  ```ruby
334
- # Will raise an error if something lost!
335
- search.get_scope(name: "Name of scope").check
315
+ require 'json'
316
+ xpath_params = {name: "test element",
317
+ tolerance: 0,
318
+ locator: {using: "xpath", value: "//*[@id='element']"}}.to_json
319
+ css_params = {name: "test element",
320
+ tolerance: 0,
321
+ locator: {using: "css selector", value: "#element"}}.to_json
322
+ element = driver.find_element(xpath: "['#{xpath_params}']")
323
+ element = driver.find_element(css: "/*#{css_params}*/")
336
324
  ```
337
325
 
338
- ## Other ways to use find
326
+ For more information about locators read about [locator strategies](https://www.w3.org/TR/webdriver/#locator-strategies)
339
327
 
340
- If the scope is set and you do not want to provide any additional options you can do:
328
+ ### locatine locator strategy
341
329
 
342
- ```ruby
343
- s = Locatine::Search.new
344
- s.find("just name of element")
345
- ```
330
+ Locatine also provides its own locator strategy == 'locatine'. In order to use it you need to inject it to the code of selenium-webdriver implementation.
331
+
332
+ See it's done for ruby [here](https://github.com/sseleznevqa/locatine/tree/master/spec/e2e_spec.rb#L5-L11)
346
333
 
347
- Also you can do:
334
+ When it's done you can use:
348
335
 
349
336
  ```ruby
350
- s = Locatine::Search.new
351
- s.browser.button(s.lctr("name of the button"))
352
- # or
353
- s.browser.button(s.lctr(name: "name of the button", scope: "Some form"))
354
- # or
355
- s.browser.button(s.lctr("name of the button", scope: "Some form"))
337
+ require 'json'
338
+ xpath_params = {name: "test element",
339
+ tolerance: 0,
340
+ locator: {using: "xpath", value: "//*[@id='element']"}}.to_json
341
+ css_params = {name: "test element",
342
+ tolerance: 0,
343
+ locator: {using: "css selector", value: "#element"}}.to_json
344
+ element = driver.find_element(locatine: xpath_params)
345
+ element = driver.find_element(locatine: css_params)
346
+ # As well as
347
+ element = driver.find_element(locatine: "test element")
348
+ # And also
349
+ element = driver.find_element(locatine: "exactly test element")
356
350
  ```
357
351
 
358
- That may be helpful in case of migration from plain watir to watir + locatine
352
+ ### Locatine locators
359
353
 
360
- If you want to find collection of elements you can use:
354
+ In some cases you can even forget about classic locators
361
355
 
362
- ```ruby
363
- s = Locatine::Search.new
364
- s.collect("group of elements") # Will return an array
365
- # or
366
- s.collect(name: "group of elements")
356
+ For example have element
357
+
358
+ ```html
359
+ <input id="important" type="button" value="click me"></input>
367
360
  ```
368
361
 
369
- Also:
362
+ Let's pretend that id == important is a uniq attribute for the page (it should be so). In that case you can do:
370
363
 
371
364
  ```ruby
372
- s.exact_collection(name: "something") == s.collect(exact: true, name: "something")
373
- s.exact(name: "something") == s.find(name: "something", exact: true)
374
- s.check(name: "something") == s.find(name: "something", tolerance: 0)
375
- s.check_collection(name: "something") == s.collect(name: "something", tolerance: 0)
365
+ element = driver.find_element(css: "/*important input*/")
376
366
  ```
377
367
 
378
- ## Using as a daemon
368
+ Locatine will try to find it by those two words. If the id is really uniq it will return the desired element.
379
369
 
380
- Locatine daemon is a web server based on sinatra. You can run it from your code like:
370
+ There is a [Locatine Name Helper chrome extension](https://chrome.google.com/webstore/detail/locatine-locator-helper/heeoaalghiamfjphdlieoblmodpcficg). This app is for creating good locatine locators (it is creating a pair - most uniq attribute value + tag for selected element, elements). Note that the app is an early draft. It's gonne be better with time.
381
371
 
382
- ```ruby
383
- require 'locatine'
384
- Locatine::Daemon.set :port, 7733 #Your port goes here
385
- Locatine::Daemon.run!
386
- ```
372
+ **NOTE! Locatine locators case insensitive.**
387
373
 
388
- Also you can do it with terminal:
374
+ **NOTE! Locatine does not count text while looking for element.**
389
375
 
390
- ```bash
391
- locatine-daemon.rb -port=7733
392
- ```
376
+ **NOTE! Locatine tends to think that the last word of your locator is a tag**
393
377
 
394
- You can see a python3 example in the [example](https://github.com/sseleznevqa/locatine/tree/master/example) folder. Main idea is
378
+ ## Locatine daemon API
395
379
 
396
- 1. Run daemon
397
- 2. Ask daemon for the app path
398
- 3. Run your browser with the app as extension
399
- 4. Turn on the learn
400
- 5. Provide data to the daemon for connect (browser name, session_id, connect url, proxy)
401
- 6. Use API calls to teach daemon how to find elements
402
- 7. After that you can start browser without the app
403
- 8. Provide data for connect
404
- 9. Now you can ask daemon to find your element via API call. And it will answer with a valid xpath you can use.
380
+ When locatine-daemon is started it is reacting to several requests:
381
+ Almost all post data should be transfered as a valid json.
405
382
 
406
- ### API
383
+ ### GET to '/'
407
384
 
408
- #### GET call to /app
385
+ Redirect to this page.
409
386
 
410
- returns path to locatine application in order to start chrome with it.
387
+ ### GET to '/locatine/stop'
411
388
 
412
- Example of response:
389
+ Stops locatine-daemon
390
+
391
+ Returns
413
392
 
414
393
  ```
415
- {"app": "/some/path/to/app"}
394
+ {"result": "dead"}
416
395
  ```
417
396
 
418
- #### GET call to /stop
397
+ ### POST to '/locatine/session/%session_id%'
419
398
 
420
- stops Locatine daemon.
421
-
422
- Returns:
399
+ Data to post (example):
423
400
 
424
401
  ```
425
- {"result": "dead"}
402
+ "{\"json\":\"./daemon.json\"}"
426
403
  ```
427
404
 
428
- #### POST call to /connect
405
+ That will force session with *%session_id%* number to read\write data using ./daemon.json file.
429
406
 
430
- allows Locatine Daemon to connect existing browser instance
407
+ For more information about possible options read [here](https://github.com/sseleznevqa/locatine#session)
431
408
 
432
- POST data:
409
+ Response:
433
410
 
434
411
  ```
435
- {'browser': 'chrome', 'session_id': session_id, 'url': 'http://whatever_is_browser_ip:port_opened_by_browser_for_selenium', 'proxy': 'optionally' }
412
+ { \"results\": {\"json\":\"./daemon.json\"} }
436
413
  ```
437
414
 
438
- Answer:
415
+ ### POST to '/wd/hub/session'
416
+
417
+ Just the same rules as for [usual selenium session](https://www.w3.org/TR/webdriver/#new-session-0)
418
+
419
+ The only change that you can set locatine defaults via providing it in desired capabilities like:
439
420
 
440
421
  ```
441
- {"result": "true"}
422
+ {...
423
+ "desiredCapabilities": {
424
+ ...
425
+ "locatine": {"json": "./daemon.json"},
426
+ ...
427
+ }
428
+ }
442
429
  ```
443
430
 
444
- #### POST call to /set
431
+ That will force new session to read\write data using ./daemon.json file.
445
432
 
446
- is to control options of locatine search. Sending to set data ==
433
+ For more information about possible options read [here](https://github.com/sseleznevqa/locatine#session)
447
434
 
448
- ```
449
- {"learn": "true"}
450
- ```
435
+ ### POST to '/wd/hub/session/%session_id%/element'
451
436
 
452
- Answer:
437
+ That will try to return element using %session_id%.
453
438
 
454
- ```
455
- {"result": "true"}
456
- ```
439
+ Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-element)
457
440
 
458
- is the same as
441
+ But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
459
442
 
460
- ```ruby
461
- search.learn = true
462
- ```
443
+ More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
463
444
 
464
- #### POST call to /lctr
445
+ ### POST to '/wd/hub/session/%session_id%/element/%element_id%/element'
465
446
 
466
- is to find and return locator of an element found by locatine
447
+ That will try to return element under %element_id% using %session_id%.
467
448
 
468
- POST data just the same as for find or lctr method. It's like:
449
+ Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-element-from-element)
469
450
 
470
- ```
471
- {"name": "some name", "scope": "Default", "exact": "false" ...}
472
- ```
451
+ But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
473
452
 
474
- Answer:
453
+ More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
475
454
 
476
- ```
477
- {"xpath": "//YOUR[@xpath='goes here']"}
478
- ```
455
+ ### POST to '/wd/hub/session/%session_id%/elements'
479
456
 
480
- ### GET /chromedriver || /geckodriver || /iedriver
457
+ That will try to return element using %session_id%.
481
458
 
482
- returns path to the binary retrieved by locatine (using webdrivers gem)
459
+ Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-elements)
483
460
 
484
- Answer:
461
+ But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
485
462
 
486
- ```
487
- {"path": "path/to/the/binary"}
488
- ```
463
+ More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
489
464
 
490
- ### POST call to /chromedriver || /geckodriver || /iedriver
465
+ ### POST to '/wd/hub/session/%session_id%/element/%element_id%/elements'
491
466
 
492
- is to force locatine to use your webdriver (for example for using old version of browser)
467
+ That will try to return element under %element_id% using %session_id%.
493
468
 
494
- POST data:
469
+ Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-elements-from-element)
495
470
 
496
- ```
497
- {"version": "2.46"}
498
- ```
471
+ But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
499
472
 
500
- Answer:
473
+ More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
501
474
 
502
- ```
503
- {"version": "2.46"}
504
- ```
475
+ ### Other calls to /wd/hub...
476
+
477
+ Any other call will be simply redirected to selenium webdriver hub.