locatine 0.02637 → 0.03050
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +266 -297
- data/bin/locatine-daemon.rb +4 -2
- data/lib/locatine.rb +16 -2
- data/lib/locatine/daemon.rb +45 -59
- data/lib/locatine/daemon_helpers/methods.rb +93 -0
- data/lib/locatine/element.rb +46 -0
- data/lib/locatine/error.rb +14 -0
- data/lib/locatine/logger.rb +73 -0
- data/lib/locatine/results.rb +124 -0
- data/lib/locatine/results_helpers/common.rb +61 -0
- data/lib/locatine/results_helpers/comparing.rb +51 -0
- data/lib/locatine/results_helpers/config.rb +48 -0
- data/lib/locatine/results_helpers/find_by_magic.rb +123 -0
- data/lib/locatine/results_helpers/guess.rb +47 -0
- data/lib/locatine/results_helpers/info_generator.rb +77 -0
- data/lib/locatine/{for_search → results_helpers}/xpath_generator.rb +19 -18
- data/lib/locatine/scripts/element.js +40 -0
- data/lib/locatine/scripts/page.js +54 -0
- data/lib/locatine/scripts/parent.js +6 -0
- data/lib/locatine/session.rb +147 -0
- data/lib/locatine/version.rb +4 -2
- metadata +42 -49
- data/lib/locatine/app/background.js +0 -8
- data/lib/locatine/app/content.css +0 -38
- data/lib/locatine/app/content.js +0 -152
- 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 -65
- 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 -107
- 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 -67
- 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 -106
- data/lib/locatine/for_search/highlight.rb +0 -41
- data/lib/locatine/for_search/listening.rb +0 -48
- 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 -199
- 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 -30
- 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: 6ec7ffd6c0a45544ae5cbd20581f72190bbfa3ee5dd2c5e444740c1d03d7ba04
|
4
|
+
data.tar.gz: 7552e77cfc41106c4679a99554980f67ad4decc354348ee0d01479c9799687fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d42ad78b43ff2335357546b50daa98734e1d06527e26fc6608540135ffb73d4f1aebcf9b5e3fb44c74b3125a31045b3206a8ddabdc0c08211f28f71390fdc9f
|
7
|
+
data.tar.gz: 2b752ff4e3a7b60ae8eb12f585eef9df6445f3c659169e7470bcfbc18f848938762815a8a977ce4825be250f527a425b0c2ff1b96d52240db4223e9d1d8a201e
|
data/README.md
CHANGED
@@ -1,26 +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.03050**. The 4th version since rewriting. 5-15 next versions is dedicated to bug fixing, tweaking.
|
20
18
|
|
21
19
|
## Attention
|
22
20
|
|
23
|
-
|
21
|
+
This version of Locatine is not compatible to previous.
|
24
22
|
|
25
23
|
## Installation
|
26
24
|
|
@@ -40,469 +38,440 @@ Or install it yourself as:
|
|
40
38
|
|
41
39
|
## Usage
|
42
40
|
|
43
|
-
1. Be sure that you have [Chrome browser](https://www.google.com/chrome/browser/desktop/) installed.
|
44
|
-
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)
|
45
44
|
|
46
45
|
```ruby
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
51
50
|
```
|
52
51
|
|
53
|
-
|
52
|
+
4. Run the locatine daemon
|
54
53
|
|
55
|
-
|
54
|
+
```
|
55
|
+
$ SELENIUM=http://localhost:4444 locatine-daemon.rb --port=7733
|
56
|
+
```
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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.
|
61
63
|
|
62
|
-
|
64
|
+
## Session
|
63
65
|
|
64
|
-
|
66
|
+
Each time when you initializing new selenium session, locatine session is created as well.
|
65
67
|
|
66
|
-
|
68
|
+
It is used to store default options for search.
|
67
69
|
|
68
|
-
|
70
|
+
There are two ways to set options of the session:
|
69
71
|
|
70
|
-
|
72
|
+
The most simple is to send it via desired capabilities like (ruby example again)
|
71
73
|
|
72
|
-
|
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
|
+
```
|
73
80
|
|
74
|
-
|
81
|
+
This way is recommended because of the simplicity.
|
75
82
|
|
76
|
-
|
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)
|
77
84
|
|
78
|
-
|
85
|
+
## Settings to pass
|
79
86
|
|
80
|
-
###
|
87
|
+
### json
|
81
88
|
|
82
|
-
|
89
|
+
Provide a string here.
|
83
90
|
|
84
|
-
|
91
|
+
Default is 'locatine-working-dir/locatine_files/default.json'
|
85
92
|
|
86
|
-
|
93
|
+
**json** is the path of the file that will be used to store data collected about elements by locatine-daemon.
|
87
94
|
|
88
|
-
|
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.
|
89
96
|
|
90
|
-
|
97
|
+
**NOTE! Only unix filesystems are supported so far.**
|
91
98
|
|
92
|
-
|
99
|
+
### depth
|
93
100
|
|
94
|
-
|
95
|
-
Locatine::Search.new(json: "./Locatine_files/default.json",
|
96
|
-
depth: 3,
|
97
|
-
browser: nil,
|
98
|
-
learn: ENV['LEARN'].nil? ? false : true,
|
99
|
-
stability_limit: 1000,
|
100
|
-
scope: "Default",
|
101
|
-
tolerance: 33,
|
102
|
-
visual_search: false,
|
103
|
-
no_fail: false,
|
104
|
-
trusted: [],
|
105
|
-
untrusted: [],
|
106
|
-
autolearn: nil)
|
107
|
-
```
|
101
|
+
Provide a non negative integer here.
|
108
102
|
|
109
|
-
|
103
|
+
Default is 3
|
110
104
|
|
111
|
-
|
105
|
+
**depth** value shows how deeply locatine will research the element.
|
112
106
|
|
113
|
-
|
107
|
+
0 - means that only the retrieved element will be remembered.
|
114
108
|
|
115
|
-
|
109
|
+
```html
|
110
|
+
<div id="element to find"></div>
|
111
|
+
```
|
116
112
|
|
117
|
-
-
|
118
|
-
- 1 = everything about the element and the parent of it
|
119
|
-
- 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:
|
120
114
|
|
121
|
-
|
115
|
+
```html
|
116
|
+
<div id="ancestor">
|
117
|
+
<div id="element to find"></div>
|
118
|
+
</div>
|
119
|
+
```
|
122
120
|
|
123
|
-
|
121
|
+
2 - means that two ancestors will be remembered.
|
124
122
|
|
125
|
-
|
123
|
+
And so on and so forth.
|
126
124
|
|
127
|
-
|
125
|
+
The higher depth the more easily locatine-daemon will find the element including the case when the element is lost (attributes are changed).
|
128
126
|
|
129
|
-
|
127
|
+
On the other side large depth is making internal locator more unstable since it is requires stability of all the ancestors as well.
|
130
128
|
|
131
|
-
|
129
|
+
Read more about [finding elements](https://github.com/sseleznevqa/locatine#finding-elements)
|
132
130
|
|
133
|
-
|
131
|
+
**NOTE! Taking additional information (larger depth) costs an additional time while retrieving element and when looking for the lost one**
|
134
132
|
|
135
|
-
|
133
|
+
### trusted
|
136
134
|
|
137
|
-
|
135
|
+
Provide an array of strings here.
|
138
136
|
|
139
|
-
|
137
|
+
Default is []
|
140
138
|
|
141
|
-
|
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.
|
142
140
|
|
143
|
-
|
141
|
+
But locatine will always use for search for element something that is listed as trusted here.
|
144
142
|
|
145
|
-
|
143
|
+
Use attribute name (like ['id']) for id attribute, use ['text'] for text and ['tag'] to trust the tag of element.
|
146
144
|
|
147
|
-
|
145
|
+
**NOTE! ['text'] will affect both - text of element and attribute of element that is named 'text'**
|
148
146
|
|
149
|
-
|
147
|
+
### untrusted
|
150
148
|
|
151
|
-
|
149
|
+
Provide an array of strings here.
|
152
150
|
|
153
|
-
|
151
|
+
Default is []
|
154
152
|
|
155
|
-
|
153
|
+
Working completely opposite to [trusted](https://github.com/sseleznevqa/locatine#trusted)
|
156
154
|
|
157
|
-
|
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.
|
158
156
|
|
159
|
-
|
157
|
+
Use attribute name (like ['id']) for id attribute, use ['text'] for text and ['tag'] to untrust the tag of element.
|
160
158
|
|
161
|
-
|
159
|
+
**NOTE! ['text'] will affect both - text of element and attribute of element that is named 'text'**
|
162
160
|
|
163
|
-
###
|
161
|
+
### stability
|
164
162
|
|
165
|
-
|
163
|
+
Provide a positive integer here.
|
166
164
|
|
167
|
-
|
165
|
+
Default is 10
|
168
166
|
|
169
|
-
|
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.
|
170
168
|
|
171
|
-
|
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.
|
172
170
|
|
173
|
-
|
171
|
+
### tolerance
|
174
172
|
|
175
|
-
|
173
|
+
Provide an integer in a range from 0 to 100
|
176
174
|
|
177
|
-
|
175
|
+
Default is 50
|
178
176
|
|
179
|
-
|
180
|
-
s = Locatine::Search.new(learn: true)
|
181
|
-
s.learn #=> true
|
182
|
-
s.learn = false
|
183
|
-
```
|
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.
|
184
178
|
|
185
|
-
|
179
|
+
Example:
|
186
180
|
|
187
|
-
```
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
vars: {},
|
193
|
-
look_in: nil,
|
194
|
-
iframe: nil,
|
195
|
-
return_locator: false,
|
196
|
-
collection: false,
|
197
|
-
tolerance: nil,
|
198
|
-
no_fail: nil,
|
199
|
-
trusted: [],
|
200
|
-
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>
|
201
186
|
```
|
202
|
-
### name
|
203
|
-
|
204
|
-
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.
|
205
187
|
|
206
|
-
|
188
|
+
5 pieces of information will be collected about an old element (tag == div, id == too, class == old, class ==one, text == element)
|
207
189
|
|
208
|
-
|
190
|
+
4 parts are staying the same after changes. So similarity will be counted like (4*100/5 == 80)
|
209
191
|
|
210
|
-
|
192
|
+
Since similarity(80)>=100-tolerance(50) the new element will be returned.
|
211
193
|
|
212
|
-
|
194
|
+
But for the case:
|
213
195
|
|
214
|
-
```
|
215
|
-
|
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>
|
216
201
|
```
|
217
202
|
|
218
|
-
|
203
|
+
Similarity will be only 40 which is less than 100-50. It means that no element will be returned.
|
219
204
|
|
220
|
-
|
205
|
+
So default tolerance == 50 means that at least 50% of element data should be equal to stored data for element to be found.
|
221
206
|
|
222
|
-
|
207
|
+
Only data of the element itself is counted here.
|
223
208
|
|
224
|
-
|
225
|
-
name == "stablePart_qljcrt24jh"
|
226
|
-
```
|
209
|
+
**NOTE! 0 (zero tolerance) means that locatine will not even try to find the lost element. 100 tolerance is too opportunistic**
|
227
210
|
|
228
|
-
|
211
|
+
### timeout
|
229
212
|
|
230
|
-
|
231
|
-
random_string == "qljcrt24jh"
|
232
|
-
```
|
213
|
+
Provide an positive integer here (up to 25 is recommended)
|
233
214
|
|
234
|
-
|
215
|
+
Default is 25
|
235
216
|
|
236
|
-
|
237
|
-
random_string #=> "qljcrt24jh"
|
238
|
-
find(name: "account name", vars: {text: random_string})
|
239
|
-
```
|
217
|
+
**timeout** shows the maximum amount of seconds locatine will try to find something.
|
240
218
|
|
241
|
-
|
219
|
+
Since default net timeout for most selenium implementations is 30 seconds, 25 is a good idea.
|
242
220
|
|
243
|
-
|
244
|
-
vars = {text: random_substring} # If you want the text of element to be dynamic
|
245
|
-
vars = {tag: random_tag} # The tag
|
246
|
-
vars = {attribute_name: random_attr} # If attribute is dynamic (use name of the attribute)
|
247
|
-
# And two lines work with visual_search == true only
|
248
|
-
vars = {css_option: random_value} # If your css is dynamic
|
249
|
-
vars = {x: random_x} # x, y for element position
|
250
|
-
```
|
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.**
|
251
222
|
|
252
|
-
|
223
|
+
## Finding elements
|
224
|
+
|
225
|
+
All the requests that are retrieving elements are wrapped by locatine-daemon.
|
253
226
|
|
254
227
|
```ruby
|
255
|
-
|
256
|
-
|
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
|
257
242
|
```
|
258
243
|
|
259
|
-
|
260
|
-
|
261
|
-
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.
|
262
|
-
|
263
|
-
### 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.
|
264
245
|
|
265
|
-
|
246
|
+
### Magic comments
|
266
247
|
|
267
|
-
|
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.
|
268
249
|
|
269
|
-
|
250
|
+
Just add name at the end of xpath like ['*name*'] or like /\**name*\*/ after css selector. For example:
|
270
251
|
|
271
|
-
|
272
|
-
|
273
|
-
|
252
|
+
```ruby
|
253
|
+
element = driver.find_element(xpath: "//*[@id='element']['test element']")
|
254
|
+
element = driver.find_element(css: "#element/*test element*/")
|
255
|
+
```
|
274
256
|
|
275
|
-
|
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.**
|
276
258
|
|
277
|
-
|
259
|
+
Once defined with name it can be called without locator part at all:
|
278
260
|
|
279
|
-
|
261
|
+
```ruby
|
262
|
+
element = driver.find_element(xpath: "['test element']")
|
263
|
+
element = driver.find_element(css: "/*test element*/")
|
264
|
+
```
|
280
265
|
|
281
|
-
|
266
|
+
**NOTE! Locators above will work only with locatine!**
|
282
267
|
|
283
|
-
###
|
268
|
+
### Dynamic locators
|
284
269
|
|
285
|
-
|
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
|
286
271
|
|
287
|
-
|
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
|
+
```
|
288
277
|
|
289
|
-
|
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**
|
290
279
|
|
291
|
-
|
280
|
+
### Zero tolerance shortcut
|
292
281
|
|
293
|
-
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.
|
294
283
|
|
295
284
|
```ruby
|
296
|
-
|
297
|
-
|
298
|
-
#
|
299
|
-
scope = Locatine::Scope.new('Name of scope', search)
|
300
|
-
scope.define
|
285
|
+
element = driver.
|
286
|
+
find_element(xpath: "//*[@id='element']['exactly test element']")
|
287
|
+
element = driver.find_element(css: "#element/*exactly test element*/")
|
301
288
|
```
|
302
289
|
|
303
|
-
|
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
|
304
293
|
|
305
|
-
|
294
|
+
There is another way to pass data to locatine. You can provide a json string as a comment.
|
306
295
|
|
307
296
|
```ruby
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
#
|
313
|
-
search.get_scope(name: "Name of scope", vars: vars) # Will ask you...
|
314
|
-
# Finally when scope is defined
|
315
|
-
search.find(scope: "Name of scope",
|
316
|
-
name: "Name of element in scope",
|
317
|
-
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}*/")
|
318
302
|
```
|
319
303
|
|
320
|
-
|
304
|
+
**NOTE! Those requests will provide same results as previous because they have identical meaning**
|
321
305
|
|
322
|
-
|
306
|
+
Like that you can set for each search any custom options (except json)
|
323
307
|
|
324
|
-
|
325
|
-
# Lost elements will be found if possible!
|
326
|
-
search.get_scope(name: "Name of scope").all
|
327
|
-
# => {"element name": {
|
328
|
-
# elements: Array of Watir::Element,
|
329
|
-
# locator: valid xpath locator
|
330
|
-
# },
|
331
|
-
# "next element name":...
|
332
|
-
# }
|
333
|
-
```
|
308
|
+
For more information about possible options read [here](https://github.com/sseleznevqa/locatine#session)
|
334
309
|
|
335
|
-
|
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.
|
336
313
|
|
337
314
|
```ruby
|
338
|
-
|
339
|
-
|
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}*/")
|
340
324
|
```
|
341
325
|
|
342
|
-
|
326
|
+
For more information about locators read about [locator strategies](https://www.w3.org/TR/webdriver/#locator-strategies)
|
343
327
|
|
344
|
-
|
328
|
+
### locatine locator strategy
|
345
329
|
|
346
|
-
|
347
|
-
s = Locatine::Search.new
|
348
|
-
s.find("just name of element")
|
349
|
-
```
|
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.
|
350
331
|
|
351
|
-
|
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:
|
352
335
|
|
353
336
|
```ruby
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
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")
|
360
350
|
```
|
361
351
|
|
362
|
-
|
352
|
+
### Locatine locators
|
363
353
|
|
364
|
-
|
354
|
+
In some cases you can even forget about classic locators
|
365
355
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
s.collect(name: "group of elements")
|
356
|
+
For example have element
|
357
|
+
|
358
|
+
```html
|
359
|
+
<input id="important" type="button" value="click me"></input>
|
371
360
|
```
|
372
361
|
|
373
|
-
|
362
|
+
Let's pretend that id == important is a uniq attribute for the page (it should be so). In that case you can do:
|
374
363
|
|
375
364
|
```ruby
|
376
|
-
|
377
|
-
s.exact(name: "something") == s.find(name: "something", exact: true)
|
378
|
-
s.check(name: "something") == s.find(name: "something", tolerance: 0)
|
379
|
-
s.check_collection(name: "something") == s.collect(name: "something", tolerance: 0)
|
365
|
+
element = driver.find_element(css: "/*important input*/")
|
380
366
|
```
|
381
367
|
|
382
|
-
|
368
|
+
Locatine will try to find it by those two words. If the id is really uniq it will return the desired element.
|
383
369
|
|
384
|
-
Locatine
|
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.
|
385
371
|
|
386
|
-
|
387
|
-
require 'locatine'
|
388
|
-
Locatine::Daemon.set :port, 7733 #Your port goes here
|
389
|
-
Locatine::Daemon.run!
|
390
|
-
```
|
372
|
+
**NOTE! Locatine locators case insensitive.**
|
391
373
|
|
392
|
-
|
374
|
+
**NOTE! Locatine does not count text while looking for element.**
|
393
375
|
|
394
|
-
|
395
|
-
|
396
|
-
|
376
|
+
**NOTE! Locatine tends to think that the last word of your locator is a tag**
|
377
|
+
|
378
|
+
## Locatine daemon API
|
397
379
|
|
398
|
-
|
380
|
+
When locatine-daemon is started it is reacting to several requests:
|
381
|
+
Almost all post data should be transfered as a valid json.
|
399
382
|
|
400
|
-
|
401
|
-
2. Ask daemon for the app path
|
402
|
-
3. Run your browser with the app as extension
|
403
|
-
4. Turn on the learn
|
404
|
-
5. Provide data to the daemon for connect (browser name, session_id, connect url, proxy)
|
405
|
-
6. Use API calls to teach daemon how to find elements
|
406
|
-
7. After that you can start browser without the app
|
407
|
-
8. Provide data for connect
|
408
|
-
9. Now you can ask daemon to find your element via API call. And it will answer with a valid xpath you can use.
|
383
|
+
### GET to '/'
|
409
384
|
|
410
|
-
|
385
|
+
Redirect to this page.
|
411
386
|
|
412
|
-
|
387
|
+
### GET to '/locatine/stop'
|
413
388
|
|
414
|
-
|
389
|
+
Stops locatine-daemon
|
415
390
|
|
416
|
-
|
391
|
+
Returns
|
417
392
|
|
418
393
|
```
|
419
|
-
{"
|
394
|
+
{"result": "dead"}
|
420
395
|
```
|
421
396
|
|
422
|
-
|
423
|
-
|
424
|
-
stops Locatine daemon.
|
397
|
+
### POST to '/locatine/session/%session_id%'
|
425
398
|
|
426
|
-
|
399
|
+
Data to post (example):
|
427
400
|
|
428
401
|
```
|
429
|
-
{"
|
402
|
+
"{\"json\":\"./daemon.json\"}"
|
430
403
|
```
|
431
404
|
|
432
|
-
|
405
|
+
That will force session with *%session_id%* number to read\write data using ./daemon.json file.
|
433
406
|
|
434
|
-
|
407
|
+
For more information about possible options read [here](https://github.com/sseleznevqa/locatine#session)
|
435
408
|
|
436
|
-
|
409
|
+
Response:
|
437
410
|
|
438
411
|
```
|
439
|
-
{
|
412
|
+
{ \"results\": {\"json\":\"./daemon.json\"} }
|
440
413
|
```
|
441
414
|
|
442
|
-
|
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:
|
443
420
|
|
444
421
|
```
|
445
|
-
{
|
422
|
+
{...
|
423
|
+
"desiredCapabilities": {
|
424
|
+
...
|
425
|
+
"locatine": {"json": "./daemon.json"},
|
426
|
+
...
|
427
|
+
}
|
428
|
+
}
|
446
429
|
```
|
447
430
|
|
448
|
-
|
431
|
+
That will force new session to read\write data using ./daemon.json file.
|
449
432
|
|
450
|
-
|
433
|
+
For more information about possible options read [here](https://github.com/sseleznevqa/locatine#session)
|
451
434
|
|
452
|
-
|
453
|
-
{"learn": "true"}
|
454
|
-
```
|
435
|
+
### POST to '/wd/hub/session/%session_id%/element'
|
455
436
|
|
456
|
-
|
437
|
+
That will try to return element using %session_id%.
|
457
438
|
|
458
|
-
|
459
|
-
{"result": "true"}
|
460
|
-
```
|
439
|
+
Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-element)
|
461
440
|
|
462
|
-
|
441
|
+
But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
|
463
442
|
|
464
|
-
|
465
|
-
search.learn = true
|
466
|
-
```
|
443
|
+
More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
|
467
444
|
|
468
|
-
|
445
|
+
### POST to '/wd/hub/session/%session_id%/element/%element_id%/element'
|
469
446
|
|
470
|
-
|
447
|
+
That will try to return element under %element_id% using %session_id%.
|
471
448
|
|
472
|
-
|
449
|
+
Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-element-from-element)
|
473
450
|
|
474
|
-
|
475
|
-
{"name": "some name", "scope": "Default", "exact": "false" ...}
|
476
|
-
```
|
451
|
+
But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
|
477
452
|
|
478
|
-
|
453
|
+
More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
|
479
454
|
|
480
|
-
|
481
|
-
{"xpath": "//YOUR[@xpath='goes here']"}
|
482
|
-
```
|
455
|
+
### POST to '/wd/hub/session/%session_id%/elements'
|
483
456
|
|
484
|
-
|
457
|
+
That will try to return element using %session_id%.
|
485
458
|
|
486
|
-
|
459
|
+
Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-elements)
|
487
460
|
|
488
|
-
|
461
|
+
But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
|
489
462
|
|
490
|
-
|
491
|
-
{"path": "path/to/the/binary"}
|
492
|
-
```
|
463
|
+
More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
|
493
464
|
|
494
|
-
### POST
|
465
|
+
### POST to '/wd/hub/session/%session_id%/element/%element_id%/elements'
|
495
466
|
|
496
|
-
|
467
|
+
That will try to return element under %element_id% using %session_id%.
|
497
468
|
|
498
|
-
|
469
|
+
Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-elements-from-element)
|
499
470
|
|
500
|
-
|
501
|
-
{"version": "2.46"}
|
502
|
-
```
|
471
|
+
But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
|
503
472
|
|
504
|
-
|
473
|
+
More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
|
505
474
|
|
506
|
-
|
507
|
-
|
508
|
-
|
475
|
+
### Other calls to /wd/hub...
|
476
|
+
|
477
|
+
Any other call will be simply redirected to selenium webdriver hub.
|