locatine 0.02539 → 0.02710
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +271 -296
- data/bin/locatine-daemon.rb +4 -2
- data/lib/locatine.rb +13 -2
- data/lib/locatine/daemon.rb +42 -60
- data/lib/locatine/daemon_helpers/methods.rb +85 -0
- data/lib/locatine/element.rb +32 -0
- data/lib/locatine/logger.rb +62 -0
- data/lib/locatine/results.rb +118 -0
- data/lib/locatine/results_helpers/common.rb +68 -0
- data/lib/locatine/results_helpers/find_by_magic.rb +118 -0
- data/lib/locatine/results_helpers/guess.rb +76 -0
- data/lib/locatine/results_helpers/info_generator.rb +79 -0
- data/lib/locatine/{for_search → results_helpers}/xpath_generator.rb +18 -11
- data/lib/locatine/scripts/element.js +40 -0
- data/lib/locatine/scripts/page.js +53 -0
- data/lib/locatine/scripts/parent.js +6 -0
- data/lib/locatine/session.rb +98 -0
- data/lib/locatine/version.rb +4 -2
- metadata +39 -49
- data/lib/locatine/app/background.js +0 -9
- data/lib/locatine/app/content.css +0 -43
- data/lib/locatine/app/content.js +0 -148
- data/lib/locatine/app/devtools.html +0 -1
- data/lib/locatine/app/devtools.js +0 -3
- data/lib/locatine/app/manifest.json +0 -20
- data/lib/locatine/app/popup.css +0 -47
- data/lib/locatine/app/popup.html +0 -19
- data/lib/locatine/app/popup.js +0 -63
- data/lib/locatine/daemon_helpers.rb +0 -52
- data/lib/locatine/for_search.rb +0 -6
- data/lib/locatine/for_search/data_generate.rb +0 -67
- data/lib/locatine/for_search/data_logic.rb +0 -98
- data/lib/locatine/for_search/defaults.rb +0 -40
- data/lib/locatine/for_search/dialog_logic.rb +0 -85
- data/lib/locatine/for_search/element_selection.rb +0 -80
- data/lib/locatine/for_search/file_work.rb +0 -67
- data/lib/locatine/for_search/find_by_guess.rb +0 -68
- data/lib/locatine/for_search/find_by_locator.rb +0 -59
- data/lib/locatine/for_search/find_by_magic.rb +0 -65
- data/lib/locatine/for_search/find_logic.rb +0 -79
- data/lib/locatine/for_search/helpers.rb +0 -107
- data/lib/locatine/for_search/highlight.rb +0 -41
- data/lib/locatine/for_search/listening.rb +0 -47
- data/lib/locatine/for_search/merge.rb +0 -40
- data/lib/locatine/for_search/name_helper.rb +0 -51
- data/lib/locatine/for_search/page_work.rb +0 -126
- data/lib/locatine/for_search/public.rb +0 -179
- data/lib/locatine/for_search/saying.rb +0 -196
- data/lib/locatine/large_scripts/css.js +0 -21
- data/lib/locatine/large_scripts/dimensions.js +0 -17
- data/lib/locatine/large_scripts/element.js +0 -31
- data/lib/locatine/large_scripts/page.js +0 -60
- data/lib/locatine/scope.rb +0 -88
- data/lib/locatine/search.rb +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 56487180200c449f68c037e000f60aa54165623f2fa8ccfab887d8756c7e848c
|
4
|
+
data.tar.gz: 8cc1c4a8edffdc0bab1dc2ca4f32038f106412a3bc4864d11547bc27ddcf091e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: edb0be42a2a0b1d624a53975cf0ace45688df57b20b8e75bfaf6eca1c1adf992a64848b94ef984517ca8de8f14856c6795738b0ef14c4b5928727b11b91da595
|
7
|
+
data.tar.gz: e20848ead9b6346734b19062568d70025d579f314773fed3ee66c2104732c83c30dce86f1b0e0101df51b5831ffbae4fa79b5b048ee9688f17416bc8a84486e8
|
data/README.md
CHANGED
@@ -1,22 +1,24 @@
|
|
1
1
|
# Locatine
|
2
2
|
|
3
|
-
|
3
|
+
Locatine is a proxy between your code and selenium.
|
4
4
|
|
5
|
-
|
5
|
+
It remembers element when you are finding it via selenium.
|
6
6
|
|
7
|
-
It
|
7
|
+
It stores the findings to the json file for the future use.
|
8
8
|
|
9
|
-
|
9
|
+
On the next search if element is lost Locatine will try to find it anyway using previously collected information.
|
10
10
|
|
11
|
-
|
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.
|
17
|
+
Version of Locatine is **0.02710**. The 3rd version since rewriting. 10-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,442 @@ 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.
|
40
|
-
2.
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
52
|
+
4. Run the locatine daemon
|
50
53
|
|
51
|
-
|
54
|
+
```
|
55
|
+
$ SELENIUM=http://localhost:4444 locatine-daemon.rb --port=7733
|
56
|
+
```
|
52
57
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
64
|
+
## Session
|
59
65
|
|
60
|
-
|
66
|
+
Each time when you initializing new selenium session, locatine session is created as well.
|
61
67
|
|
62
|
-
|
68
|
+
It is used to store default options for search.
|
63
69
|
|
64
|
-
|
70
|
+
There are two ways to set options of the session:
|
65
71
|
|
66
|
-
|
72
|
+
The most simple is to send it via desired capabilities like (ruby example again)
|
67
73
|
|
68
|
-
|
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
|
-
|
81
|
+
This way is recommended because of the simplicity.
|
71
82
|
|
72
|
-
|
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
|
-
|
85
|
+
## Settings to pass
|
75
86
|
|
76
|
-
###
|
87
|
+
### json
|
77
88
|
|
78
|
-
|
89
|
+
Provide a string here.
|
79
90
|
|
80
|
-
|
91
|
+
Default is 'locatine-working-dir/locatine_files/default.json'
|
81
92
|
|
82
|
-
|
93
|
+
**json** is the path of the file that will be used to store data collected about elements by locatine-daemon.
|
83
94
|
|
84
|
-
|
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
|
-
|
97
|
+
**NOTE! Only unix filesystems are supported so far.**
|
87
98
|
|
88
|
-
|
99
|
+
### depth
|
89
100
|
|
90
|
-
|
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
|
-
|
103
|
+
Default is 3
|
106
104
|
|
107
|
-
|
105
|
+
**depth** value shows how deeply locatine will research the element.
|
108
106
|
|
109
|
-
|
107
|
+
0 - means that only the retrieved element will be remembered.
|
110
108
|
|
111
|
-
|
109
|
+
```html
|
110
|
+
<div id="element to find"></div>
|
111
|
+
```
|
112
112
|
|
113
|
-
-
|
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
|
-
|
115
|
+
```html
|
116
|
+
<div id="ancestor">
|
117
|
+
<div id="element to find"></div>
|
118
|
+
</div>
|
119
|
+
```
|
118
120
|
|
119
|
-
|
121
|
+
2 - means that two ancestors will be remembered.
|
120
122
|
|
121
|
-
|
123
|
+
And so on and so forth.
|
122
124
|
|
123
|
-
|
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
|
-
|
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
|
-
|
129
|
+
Read more about [finding elements](https://github.com/sseleznevqa/locatine#finding-elements)
|
128
130
|
|
129
|
-
|
131
|
+
**NOTE! Taking additional information (larger depth) costs an additional time while retrieving element and when looking for the lost one**
|
130
132
|
|
131
|
-
|
133
|
+
### trusted
|
132
134
|
|
133
|
-
|
135
|
+
Provide an array of strings here.
|
134
136
|
|
135
|
-
|
137
|
+
Default is []
|
136
138
|
|
137
|
-
|
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
|
-
|
141
|
+
But locatine will always use for search for element something that is listed as trusted here.
|
140
142
|
|
141
|
-
|
143
|
+
Use attribute name (like ['id']) for id attribute, use ['text'] for text and ['tag'] to trust the tag of element.
|
142
144
|
|
143
|
-
|
145
|
+
**NOTE! ['text'] will affect both - text of element and attribute of element that is named 'text'**
|
144
146
|
|
145
|
-
|
147
|
+
### untrusted
|
146
148
|
|
147
|
-
|
149
|
+
Provide an array of strings here.
|
148
150
|
|
149
|
-
|
151
|
+
Default is []
|
150
152
|
|
151
|
-
|
153
|
+
Working completely opposite to [trusted](https://github.com/sseleznevqa/locatine#trusted)
|
152
154
|
|
153
|
-
|
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
|
-
|
157
|
+
Use attribute name (like ['id']) for id attribute, use ['text'] for text and ['tag'] to untrust the tag of element.
|
156
158
|
|
157
|
-
|
159
|
+
**NOTE! ['text'] will affect both - text of element and attribute of element that is named 'text'**
|
158
160
|
|
159
|
-
###
|
161
|
+
### stability
|
160
162
|
|
161
|
-
|
163
|
+
Provide a positive integer here.
|
162
164
|
|
163
|
-
|
165
|
+
Default is 10
|
164
166
|
|
165
|
-
|
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
|
-
|
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
|
-
|
171
|
+
### tolerance
|
170
172
|
|
171
|
-
|
173
|
+
Provide an integer in a range from 0 to 100
|
172
174
|
|
173
|
-
|
175
|
+
Default is 50
|
174
176
|
|
175
|
-
|
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
|
-
|
179
|
+
Example:
|
182
180
|
|
183
|
-
```
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
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
187
|
|
200
|
-
|
188
|
+
5 pieces of information will be collected about an old element (tag == div, id == too, class == old, class ==one, text == element)
|
201
189
|
|
202
|
-
|
190
|
+
4 parts are staying the same after changes. So similarity will be counted like (4*100/5 == 80)
|
203
191
|
|
204
|
-
|
192
|
+
Since similarity(80)>=100-tolerance(50) the new element will be returned.
|
205
193
|
|
206
|
-
|
194
|
+
But for the case:
|
207
195
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
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
|
-
|
203
|
+
Similarity will be only 40 which is less than 100-50. It means that no element will be returned.
|
215
204
|
|
216
|
-
|
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
|
-
|
207
|
+
Only data of the element itself is counted here.
|
219
208
|
|
220
|
-
|
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
|
-
|
211
|
+
### timeout
|
225
212
|
|
226
|
-
|
227
|
-
random_string == "qljcrt24jh"
|
228
|
-
```
|
213
|
+
Provide an positive integer here (up to 25 is recommended)
|
229
214
|
|
230
|
-
|
215
|
+
Default is 25
|
231
216
|
|
232
|
-
|
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
|
-
|
219
|
+
Since default net timeout for most selenium implementations is 30 seconds, 25 is a good idea.
|
238
220
|
|
239
|
-
|
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.**
|
247
222
|
|
248
|
-
|
223
|
+
## Finding elements
|
224
|
+
|
225
|
+
All the requests that are retrieving elements are wrapped by locatine-daemon.
|
249
226
|
|
250
227
|
```ruby
|
251
|
-
|
252
|
-
|
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
|
-
|
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
|
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.
|
260
245
|
|
261
|
-
|
246
|
+
### Magic comments
|
262
247
|
|
263
|
-
|
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.
|
264
249
|
|
265
|
-
|
250
|
+
Just add name at the end of xpath like ['*name*'] or like /\**name*\*/ after css selector. For example:
|
266
251
|
|
267
|
-
|
268
|
-
|
269
|
-
|
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
|
-
|
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
|
-
|
259
|
+
Once defined with name it can be called without locator part at all:
|
274
260
|
|
275
|
-
|
261
|
+
```ruby
|
262
|
+
element = driver.find_element(xpath: "['test element']")
|
263
|
+
element = driver.find_element(css: "/*test element*/")
|
264
|
+
```
|
276
265
|
|
277
|
-
|
266
|
+
**NOTE! Locators above will work only with locatine!**
|
278
267
|
|
279
|
-
###
|
268
|
+
### Dynamic locators
|
280
269
|
|
281
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
280
|
+
### Zero tolerance shortcut
|
288
281
|
|
289
|
-
If you
|
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
|
-
|
293
|
-
|
294
|
-
#
|
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
|
-
|
290
|
+
**NOTE! Zero tolerance will be used for that particular search only. Other searches will use session values**
|
291
|
+
|
292
|
+
### Other ways to pass data to locatine
|
300
293
|
|
301
|
-
|
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
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
#
|
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
|
-
|
304
|
+
**NOTE! Those requests will provide same results as previous because they have identical meaning**
|
317
305
|
|
318
|
-
|
306
|
+
Like that you can set for each search any custom options (except json)
|
319
307
|
|
320
|
-
|
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)
|
330
309
|
|
331
|
-
|
310
|
+
Additionally you can provide a custom locator inside of the comment json string.
|
311
|
+
|
312
|
+
We are using 'json' library to make json string here.
|
332
313
|
|
333
314
|
```ruby
|
334
|
-
|
335
|
-
|
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
|
-
|
326
|
+
For more information about locators read about [locator strategies](https://www.w3.org/TR/webdriver/#locator-strategies)
|
339
327
|
|
340
|
-
|
328
|
+
### locatine locator strategy
|
341
329
|
|
342
|
-
|
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.
|
346
331
|
|
347
|
-
|
332
|
+
See it's done for ruby [here](https://github.com/sseleznevqa/locatine/tree/master/spec/e2e_spec.rb#L5-L11)
|
333
|
+
|
334
|
+
When it's done you can use:
|
348
335
|
|
349
336
|
```ruby
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
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
|
-
|
352
|
+
### Locatine locators
|
359
353
|
|
360
|
-
|
354
|
+
In some cases you can even forget about classic locators
|
361
355
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
370
|
+
Right now there is a Locatine Naming App that is in pending review status in the Chrome extension shop. This app is for creating good locatine locators.
|
381
371
|
|
382
|
-
|
383
|
-
require 'locatine'
|
384
|
-
Locatine::Daemon.set :port, 7733 #Your port goes here
|
385
|
-
Locatine::Daemon.run!
|
386
|
-
```
|
372
|
+
If you wanna try it before it is published - code is in the app folder of this repository.
|
387
373
|
|
388
|
-
|
374
|
+
**NOTE! Locatine locators case insensitive.**
|
389
375
|
|
390
|
-
|
391
|
-
|
392
|
-
|
376
|
+
**NOTE! Locatine does not count text while looking for element.**
|
377
|
+
|
378
|
+
**NOTE! Locatine tends to think that the last word of your locator is a tag**
|
393
379
|
|
394
|
-
|
380
|
+
## Locatine daemon API
|
395
381
|
|
396
|
-
|
397
|
-
|
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.
|
382
|
+
When locatine-daemon is started it is reacting to several requests:
|
383
|
+
Almost all post data should be transfered as a valid json.
|
405
384
|
|
406
|
-
###
|
385
|
+
### GET to '/'
|
407
386
|
|
408
|
-
|
387
|
+
Redirect to this page.
|
409
388
|
|
410
|
-
|
389
|
+
### GET to '/locatine/stop'
|
411
390
|
|
412
|
-
|
391
|
+
Stops locatine-daemon
|
392
|
+
|
393
|
+
Returns
|
413
394
|
|
414
395
|
```
|
415
|
-
{"
|
396
|
+
{"result": "dead"}
|
416
397
|
```
|
417
398
|
|
418
|
-
|
399
|
+
### POST to '/locatine/session/%session_id%'
|
419
400
|
|
420
|
-
|
421
|
-
|
422
|
-
Returns:
|
401
|
+
Data to post (example):
|
423
402
|
|
424
403
|
```
|
425
|
-
{"
|
404
|
+
"{\"json\":\"./daemon.json\"}"
|
426
405
|
```
|
427
406
|
|
428
|
-
|
407
|
+
That will force session with *%session_id%* number to read\write data using ./daemon.json file.
|
429
408
|
|
430
|
-
|
409
|
+
For more information about possible options read [here](https://github.com/sseleznevqa/locatine#session)
|
431
410
|
|
432
|
-
|
411
|
+
Response:
|
433
412
|
|
434
413
|
```
|
435
|
-
{
|
414
|
+
{ \"results\": {\"json\":\"./daemon.json\"} }
|
436
415
|
```
|
437
416
|
|
438
|
-
|
417
|
+
### POST to '/wd/hub/session'
|
418
|
+
|
419
|
+
Just the same rules as for [usual selenium session](https://www.w3.org/TR/webdriver/#new-session-0)
|
420
|
+
|
421
|
+
The only change that you can set locatine defaults via providing it in desired capabilities like:
|
439
422
|
|
440
423
|
```
|
441
|
-
{
|
424
|
+
{...
|
425
|
+
"desiredCapabilities": {
|
426
|
+
...
|
427
|
+
"locatine": {"json": "./daemon.json"},
|
428
|
+
...
|
429
|
+
}
|
430
|
+
}
|
442
431
|
```
|
443
432
|
|
444
|
-
|
433
|
+
That will force new session to read\write data using ./daemon.json file.
|
445
434
|
|
446
|
-
|
435
|
+
For more information about possible options read [here](https://github.com/sseleznevqa/locatine#session)
|
447
436
|
|
448
|
-
|
449
|
-
{"learn": "true"}
|
450
|
-
```
|
437
|
+
### POST to '/wd/hub/session/%session_id%/element'
|
451
438
|
|
452
|
-
|
439
|
+
That will try to return element using %session_id%.
|
453
440
|
|
454
|
-
|
455
|
-
{"result": "true"}
|
456
|
-
```
|
441
|
+
Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-element)
|
457
442
|
|
458
|
-
|
443
|
+
But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
|
459
444
|
|
460
|
-
|
461
|
-
search.learn = true
|
462
|
-
```
|
445
|
+
More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
|
463
446
|
|
464
|
-
|
447
|
+
### POST to '/wd/hub/session/%session_id%/element/%element_id%/element'
|
465
448
|
|
466
|
-
|
449
|
+
That will try to return element under %element_id% using %session_id%.
|
467
450
|
|
468
|
-
|
451
|
+
Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-element-from-element)
|
469
452
|
|
470
|
-
|
471
|
-
{"name": "some name", "scope": "Default", "exact": "false" ...}
|
472
|
-
```
|
453
|
+
But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
|
473
454
|
|
474
|
-
|
455
|
+
More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
|
475
456
|
|
476
|
-
|
477
|
-
{"xpath": "//YOUR[@xpath='goes here']"}
|
478
|
-
```
|
457
|
+
### POST to '/wd/hub/session/%session_id%/elements'
|
479
458
|
|
480
|
-
|
459
|
+
That will try to return element using %session_id%.
|
481
460
|
|
482
|
-
|
461
|
+
Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-elements)
|
483
462
|
|
484
|
-
|
463
|
+
But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
|
485
464
|
|
486
|
-
|
487
|
-
{"path": "path/to/the/binary"}
|
488
|
-
```
|
465
|
+
More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
|
489
466
|
|
490
|
-
### POST
|
467
|
+
### POST to '/wd/hub/session/%session_id%/element/%element_id%/elements'
|
491
468
|
|
492
|
-
|
469
|
+
That will try to return element under %element_id% using %session_id%.
|
493
470
|
|
494
|
-
|
471
|
+
Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-elements-from-element)
|
495
472
|
|
496
|
-
|
497
|
-
{"version": "2.46"}
|
498
|
-
```
|
473
|
+
But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
|
499
474
|
|
500
|
-
|
475
|
+
More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
|
501
476
|
|
502
|
-
|
503
|
-
|
504
|
-
|
477
|
+
### Other calls to /wd/hub...
|
478
|
+
|
479
|
+
Any other call will be simply redirected to selenium webdriver hub.
|