locatine 0.02542 → 0.02878
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +269 -296
- data/bin/locatine-daemon.rb +4 -2
- data/lib/locatine.rb +14 -2
- data/lib/locatine/daemon.rb +48 -56
- data/lib/locatine/daemon_helpers/methods.rb +85 -0
- data/lib/locatine/element.rb +32 -0
- data/lib/locatine/error.rb +14 -0
- data/lib/locatine/logger.rb +69 -0
- data/lib/locatine/results.rb +128 -0
- data/lib/locatine/results_helpers/common.rb +68 -0
- data/lib/locatine/results_helpers/find_by_magic.rb +121 -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 +54 -0
- data/lib/locatine/scripts/parent.js +6 -0
- data/lib/locatine/session.rb +107 -0
- data/lib/locatine/version.rb +4 -2
- metadata +40 -49
- data/lib/locatine/app/background.js +0 -8
- data/lib/locatine/app/content.css +0 -43
- data/lib/locatine/app/content.js +0 -149
- 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 -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 -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: 457cb5d21eae999673da17f8c5c200181755f846946e81c81d9a23bbafa85528
|
4
|
+
data.tar.gz: f3ae98ffc268889f4781126b71106ffc99c29c73f9cd4e8321743388fb56bf70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed6f3ad8a5e29ea3b3e672b5a5cbd006571fa9536821dbc0b1467b005cf0998efc19425ba17f166a608cf84b5a884908c1d718275dbbebd0a56372a85f10d988
|
7
|
+
data.tar.gz: a7e5b86fe05b8710fd5bbd675733937dab017f8c27d8e27e4dbd5865da9313211775877c931a56c36414e0f1a3d94d3c66365a511f543daad4022fb00be91b14
|
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.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.
|
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
|
-
|
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
|
-
|
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
|
-
|
190
|
+
4 parts are staying the same after changes. So similarity will be counted like (4*100/5 == 80)
|
205
191
|
|
206
|
-
|
192
|
+
Since similarity(80)>=100-tolerance(50) the new element will be returned.
|
207
193
|
|
208
|
-
|
194
|
+
But for the case:
|
209
195
|
|
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
|
-
|
241
|
-
|
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
|
-
|
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
|
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
|
-
###
|
246
|
+
### Magic comments
|
264
247
|
|
265
|
-
|
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
|
-
|
250
|
+
Just add name at the end of xpath like ['*name*'] or like /\**name*\*/ after css selector. For example:
|
268
251
|
|
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**
|
300
291
|
|
301
|
-
|
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
|
-
|
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
|
-
|
322
|
-
|
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
|
-
|
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
|
-
|
344
|
-
s
|
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
|
-
|
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
|
-
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.
|
381
371
|
|
382
|
-
|
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
|
-
|
374
|
+
**NOTE! Locatine does not count text while looking for element.**
|
389
375
|
|
390
|
-
|
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
|
-
|
378
|
+
## Locatine daemon API
|
395
379
|
|
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.
|
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
|
-
###
|
383
|
+
### GET to '/'
|
407
384
|
|
408
|
-
|
385
|
+
Redirect to this page.
|
409
386
|
|
410
|
-
|
387
|
+
### GET to '/locatine/stop'
|
411
388
|
|
412
|
-
|
389
|
+
Stops locatine-daemon
|
390
|
+
|
391
|
+
Returns
|
413
392
|
|
414
393
|
```
|
415
|
-
{"
|
394
|
+
{"result": "dead"}
|
416
395
|
```
|
417
396
|
|
418
|
-
|
397
|
+
### POST to '/locatine/session/%session_id%'
|
419
398
|
|
420
|
-
|
421
|
-
|
422
|
-
Returns:
|
399
|
+
Data to post (example):
|
423
400
|
|
424
401
|
```
|
425
|
-
{"
|
402
|
+
"{\"json\":\"./daemon.json\"}"
|
426
403
|
```
|
427
404
|
|
428
|
-
|
405
|
+
That will force session with *%session_id%* number to read\write data using ./daemon.json file.
|
429
406
|
|
430
|
-
|
407
|
+
For more information about possible options read [here](https://github.com/sseleznevqa/locatine#session)
|
431
408
|
|
432
|
-
|
409
|
+
Response:
|
433
410
|
|
434
411
|
```
|
435
|
-
{
|
412
|
+
{ \"results\": {\"json\":\"./daemon.json\"} }
|
436
413
|
```
|
437
414
|
|
438
|
-
|
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
|
-
{
|
422
|
+
{...
|
423
|
+
"desiredCapabilities": {
|
424
|
+
...
|
425
|
+
"locatine": {"json": "./daemon.json"},
|
426
|
+
...
|
427
|
+
}
|
428
|
+
}
|
442
429
|
```
|
443
430
|
|
444
|
-
|
431
|
+
That will force new session to read\write data using ./daemon.json file.
|
445
432
|
|
446
|
-
|
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
|
-
|
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
|
-
|
441
|
+
But you can provide magic locator comments for xpath and css. Or use 'locatine' element retrieve strategy.
|
459
442
|
|
460
|
-
|
461
|
-
search.learn = true
|
462
|
-
```
|
443
|
+
More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
|
463
444
|
|
464
|
-
|
445
|
+
### POST to '/wd/hub/session/%session_id%/element/%element_id%/element'
|
465
446
|
|
466
|
-
|
447
|
+
That will try to return element under %element_id% using %session_id%.
|
467
448
|
|
468
|
-
|
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
|
-
|
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
|
-
|
457
|
+
That will try to return element using %session_id%.
|
481
458
|
|
482
|
-
|
459
|
+
Rules are the same as for [usual selenium call](https://www.w3.org/TR/webdriver/#find-elements)
|
483
460
|
|
484
|
-
|
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
|
465
|
+
### POST to '/wd/hub/session/%session_id%/element/%element_id%/elements'
|
491
466
|
|
492
|
-
|
467
|
+
That will try to return element under %element_id% using %session_id%.
|
493
468
|
|
494
|
-
|
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
|
-
|
473
|
+
More information is [here](https://github.com/sseleznevqa/locatine#finding-elements)
|
501
474
|
|
502
|
-
|
503
|
-
|
504
|
-
|
475
|
+
### Other calls to /wd/hub...
|
476
|
+
|
477
|
+
Any other call will be simply redirected to selenium webdriver hub.
|