locatine 0.02327 → 0.02637
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +148 -3
- data/bin/locatine-daemon.rb +8 -0
- data/lib/locatine.rb +1 -0
- data/lib/locatine/app/background.js +0 -1
- data/lib/locatine/app/content.css +1 -6
- data/lib/locatine/app/content.js +21 -17
- data/lib/locatine/app/manifest.json +1 -1
- data/lib/locatine/app/popup.js +4 -2
- data/lib/locatine/daemon.rb +93 -0
- data/lib/locatine/daemon_helpers.rb +52 -0
- data/lib/locatine/for_search/data_generate.rb +12 -45
- data/lib/locatine/for_search/data_logic.rb +32 -10
- data/lib/locatine/for_search/defaults.rb +40 -0
- data/lib/locatine/for_search/dialog_logic.rb +31 -8
- data/lib/locatine/for_search/element_selection.rb +1 -1
- data/lib/locatine/for_search/file_work.rb +0 -7
- data/lib/locatine/for_search/find_by_guess.rb +40 -38
- data/lib/locatine/for_search/find_by_locator.rb +0 -30
- data/lib/locatine/for_search/find_by_magic.rb +32 -83
- data/lib/locatine/for_search/find_logic.rb +6 -2
- data/lib/locatine/for_search/helpers.rb +13 -11
- data/lib/locatine/for_search/listening.rb +2 -1
- data/lib/locatine/for_search/page_work.rb +126 -0
- data/lib/locatine/for_search/public.rb +30 -24
- data/lib/locatine/for_search/saying.rb +23 -7
- data/lib/locatine/for_search/xpath_generator.rb +12 -11
- data/lib/locatine/large_scripts/element.js +30 -0
- data/lib/locatine/large_scripts/page.js +60 -0
- data/lib/locatine/search.rb +6 -3
- data/lib/locatine/version.rb +1 -1
- metadata +23 -16
- data/lib/locatine/for_search/find_by_css.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d969a9d3fc96c105d69b1d41f7ff8df92198d6d
|
4
|
+
data.tar.gz: 93ec07af0558fd08a13224686c9844775f3b36c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f7d7af25a50b8aeb293f3795574999e87debe5adfd3149bb3e9855257a5cf4f47c2f980c57a8582b7b65890abafc665c3d96ab39604eb4ae615bdc636489d11
|
7
|
+
data.tar.gz: 3883f1e882b88f038dcacd6520d408126e9c82b9178a5cfb2d5069d4b14a7327e25651d08a45ab447f8b4a0366341482aefc7414668d06e08aeebaa13ef2ffd0
|
data/README.md
CHANGED
@@ -16,7 +16,11 @@ That's it.
|
|
16
16
|
|
17
17
|
## Stage of development:
|
18
18
|
|
19
|
-
Version of Locatine is **0.
|
19
|
+
Version of Locatine is **0.02637** only. It means so far this is an alfa. You can use it in a real project if you are a risky person.
|
20
|
+
|
21
|
+
## Attention
|
22
|
+
|
23
|
+
Beginning with the next version locatine (especially locatine-daemon) will be refactored dramatically. It is highly possible that the next version will be not completable with that one.
|
20
24
|
|
21
25
|
## Installation
|
22
26
|
|
@@ -98,7 +102,8 @@ Locatine::Search.new(json: "./Locatine_files/default.json",
|
|
98
102
|
visual_search: false,
|
99
103
|
no_fail: false,
|
100
104
|
trusted: [],
|
101
|
-
untrusted: []
|
105
|
+
untrusted: [],
|
106
|
+
autolearn: nil)
|
102
107
|
```
|
103
108
|
|
104
109
|
### json
|
@@ -155,6 +160,18 @@ If you are sure that some attribute (or something) is not good(generated by rand
|
|
155
160
|
|
156
161
|
On the other hand you can force locatine to always trust something with trusted.
|
157
162
|
|
163
|
+
### autolearn
|
164
|
+
|
165
|
+
Determines wether Locatine will study elements by default or not.
|
166
|
+
|
167
|
+
If true Locatine will always check element for changes even if it is found properly (to catch for example adding of a new attribute). This is slow.
|
168
|
+
|
169
|
+
If false Locatine will study element only in case when it is lost.
|
170
|
+
|
171
|
+
If not stated Locatine will use false until it is not facing any lost element. After the first lost element it will be studying everything (true).
|
172
|
+
|
173
|
+
Notice that if autolearn is false Locatine is not bumping the stability values of attributes for elements which were found normally.
|
174
|
+
|
158
175
|
## Changing options on fly
|
159
176
|
|
160
177
|
You can get or set these values on fly. Like:
|
@@ -229,7 +246,7 @@ vars = {tag: random_tag} # The tag
|
|
229
246
|
vars = {attribute_name: random_attr} # If attribute is dynamic (use name of the attribute)
|
230
247
|
# And two lines work with visual_search == true only
|
231
248
|
vars = {css_option: random_value} # If your css is dynamic
|
232
|
-
vars = {x: random_x} # x, y
|
249
|
+
vars = {x: random_x} # x, y for element position
|
233
250
|
```
|
234
251
|
|
235
252
|
And if you do not like it you can do:
|
@@ -361,3 +378,131 @@ s.exact(name: "something") == s.find(name: "something", exact: true)
|
|
361
378
|
s.check(name: "something") == s.find(name: "something", tolerance: 0)
|
362
379
|
s.check_collection(name: "something") == s.collect(name: "something", tolerance: 0)
|
363
380
|
```
|
381
|
+
|
382
|
+
## Using as a daemon
|
383
|
+
|
384
|
+
Locatine daemon is a web server based on sinatra. You can run it from your code like:
|
385
|
+
|
386
|
+
```ruby
|
387
|
+
require 'locatine'
|
388
|
+
Locatine::Daemon.set :port, 7733 #Your port goes here
|
389
|
+
Locatine::Daemon.run!
|
390
|
+
```
|
391
|
+
|
392
|
+
Also you can do it with terminal:
|
393
|
+
|
394
|
+
```bash
|
395
|
+
locatine-daemon.rb -port=7733
|
396
|
+
```
|
397
|
+
|
398
|
+
You can see a python3 example in the [example](https://github.com/sseleznevqa/locatine/tree/master/example) folder. Main idea is
|
399
|
+
|
400
|
+
1. Run daemon
|
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.
|
409
|
+
|
410
|
+
### API
|
411
|
+
|
412
|
+
#### GET call to /app
|
413
|
+
|
414
|
+
returns path to locatine application in order to start chrome with it.
|
415
|
+
|
416
|
+
Example of response:
|
417
|
+
|
418
|
+
```
|
419
|
+
{"app": "/some/path/to/app"}
|
420
|
+
```
|
421
|
+
|
422
|
+
#### GET call to /stop
|
423
|
+
|
424
|
+
stops Locatine daemon.
|
425
|
+
|
426
|
+
Returns:
|
427
|
+
|
428
|
+
```
|
429
|
+
{"result": "dead"}
|
430
|
+
```
|
431
|
+
|
432
|
+
#### POST call to /connect
|
433
|
+
|
434
|
+
allows Locatine Daemon to connect existing browser instance
|
435
|
+
|
436
|
+
POST data:
|
437
|
+
|
438
|
+
```
|
439
|
+
{'browser': 'chrome', 'session_id': session_id, 'url': 'http://whatever_is_browser_ip:port_opened_by_browser_for_selenium', 'proxy': 'optionally' }
|
440
|
+
```
|
441
|
+
|
442
|
+
Answer:
|
443
|
+
|
444
|
+
```
|
445
|
+
{"result": "true"}
|
446
|
+
```
|
447
|
+
|
448
|
+
#### POST call to /set
|
449
|
+
|
450
|
+
is to control options of locatine search. Sending to set data ==
|
451
|
+
|
452
|
+
```
|
453
|
+
{"learn": "true"}
|
454
|
+
```
|
455
|
+
|
456
|
+
Answer:
|
457
|
+
|
458
|
+
```
|
459
|
+
{"result": "true"}
|
460
|
+
```
|
461
|
+
|
462
|
+
is the same as
|
463
|
+
|
464
|
+
```ruby
|
465
|
+
search.learn = true
|
466
|
+
```
|
467
|
+
|
468
|
+
#### POST call to /lctr
|
469
|
+
|
470
|
+
is to find and return locator of an element found by locatine
|
471
|
+
|
472
|
+
POST data just the same as for find or lctr method. It's like:
|
473
|
+
|
474
|
+
```
|
475
|
+
{"name": "some name", "scope": "Default", "exact": "false" ...}
|
476
|
+
```
|
477
|
+
|
478
|
+
Answer:
|
479
|
+
|
480
|
+
```
|
481
|
+
{"xpath": "//YOUR[@xpath='goes here']"}
|
482
|
+
```
|
483
|
+
|
484
|
+
### GET /chromedriver || /geckodriver || /iedriver
|
485
|
+
|
486
|
+
returns path to the binary retrieved by locatine (using webdrivers gem)
|
487
|
+
|
488
|
+
Answer:
|
489
|
+
|
490
|
+
```
|
491
|
+
{"path": "path/to/the/binary"}
|
492
|
+
```
|
493
|
+
|
494
|
+
### POST call to /chromedriver || /geckodriver || /iedriver
|
495
|
+
|
496
|
+
is to force locatine to use your webdriver (for example for using old version of browser)
|
497
|
+
|
498
|
+
POST data:
|
499
|
+
|
500
|
+
```
|
501
|
+
{"version": "2.46"}
|
502
|
+
```
|
503
|
+
|
504
|
+
Answer:
|
505
|
+
|
506
|
+
```
|
507
|
+
{"version": "2.46"}
|
508
|
+
```
|
@@ -0,0 +1,8 @@
|
|
1
|
+
#!Locatine-daemon...
|
2
|
+
require 'locatine'
|
3
|
+
args = Hash[ ARGV.join(' ').scan(/--?([^=\s]+)(?:=(\S+))?/) ]
|
4
|
+
args = args.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
5
|
+
args.each_pair do |key, value|
|
6
|
+
Locatine::Daemon.set key, value
|
7
|
+
end
|
8
|
+
Locatine::Daemon.run!
|
data/lib/locatine.rb
CHANGED
@@ -20,7 +20,7 @@ div[locatinestyle=true] {
|
|
20
20
|
display: block;
|
21
21
|
z-index: 2147483646;
|
22
22
|
color: #FF99AA;
|
23
|
-
font-size:
|
23
|
+
font-size: 4vw;
|
24
24
|
text-align: center;
|
25
25
|
cursor: default;
|
26
26
|
}
|
@@ -30,11 +30,6 @@ div[locatinestyle=false] {
|
|
30
30
|
width: 0%;
|
31
31
|
}
|
32
32
|
|
33
|
-
div[locatinestyle=blocked] {
|
34
|
-
height: 0%;
|
35
|
-
width: 0%;
|
36
|
-
}
|
37
|
-
|
38
33
|
[locatineclass=foundbylocatine]
|
39
34
|
{animation: locatine_found 6s infinite;
|
40
35
|
-webkit-appearance: none;
|
data/lib/locatine/app/content.js
CHANGED
@@ -20,6 +20,7 @@ async function creatingDiv(){
|
|
20
20
|
locatine_create_element(document.body, "div", options, "");
|
21
21
|
const magic_cover = document.getElementById('locatine_magic_div');
|
22
22
|
magic_cover.onclick = function(e) {locatine_magic_click(e)};
|
23
|
+
await set_value('locatine_confirm', 'new')
|
23
24
|
document.body.onkeypress = async function(e) {
|
24
25
|
if (e.which == 13) {
|
25
26
|
await set_value('locatine_confirm', true)
|
@@ -45,21 +46,24 @@ async function setTitleHint(magicDiv){
|
|
45
46
|
await set_value('locatine_title', magicDiv.getAttribute("locatinetitle"));
|
46
47
|
await set_value('locatine_hint', magicDiv.getAttribute("locatinehint"));
|
47
48
|
magicDiv.setAttribute("locatinetitle", "ok");
|
48
|
-
let
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
49
|
+
let status = await get_value('magic_div');
|
50
|
+
if (status) {
|
51
|
+
let op = 1;
|
52
|
+
magicDiv.innerHTML = await get_value("locatine_title");
|
53
|
+
let timer = setInterval(function () {
|
54
|
+
if ((magicDiv.style.opacity == 1) && (op < 0.97)) {
|
55
|
+
clearInterval(timer);// If other process changed opacity.
|
56
|
+
};
|
57
|
+
if (op <= 0.2) {
|
58
|
+
clearInterval(timer);
|
59
|
+
magicDiv.style.opacity = 0;
|
60
|
+
magicDiv.innerHTML = "";
|
61
|
+
}
|
62
|
+
magicDiv.style.opacity = op;
|
63
|
+
magicDiv.style.filter = 'alpha(opacity=' + op * 100 + ")";
|
64
|
+
op -= op * 0.03;
|
65
|
+
}, 50);
|
66
|
+
}
|
63
67
|
}
|
64
68
|
}
|
65
69
|
|
@@ -116,7 +120,7 @@ async function getSelected(value){
|
|
116
120
|
};
|
117
121
|
|
118
122
|
async function locatine_magic_click(e) {
|
119
|
-
document.getElementById("locatine_magic_div").setAttribute("locatinestyle", "
|
123
|
+
document.getElementById("locatine_magic_div").setAttribute("locatinestyle", "false");
|
120
124
|
const value = document.elementFromPoint(e.clientX, e.clientY);
|
121
125
|
document.getElementById("locatine_magic_div").setAttribute("locatinestyle", "true");
|
122
126
|
const tagName = value.tagName;
|
@@ -139,7 +143,7 @@ function locatine_create_element(dom, tag, attrs, inner) {
|
|
139
143
|
|
140
144
|
setInterval(async function(){
|
141
145
|
if (document.getElementById("locatine_magic_div")) {
|
142
|
-
if (document.getElementById("locatine_magic_div").getAttribute("locatinestyle") != "
|
146
|
+
if (document.getElementById("locatine_magic_div").getAttribute("locatinestyle") != "false") {
|
143
147
|
await refreshData()
|
144
148
|
}
|
145
149
|
} else {
|
data/lib/locatine/app/popup.js
CHANGED
@@ -20,8 +20,10 @@ async function correct_buttons() {
|
|
20
20
|
} else {
|
21
21
|
document.getElementById("mode").setAttribute("value", "You are in single selection mode")
|
22
22
|
};
|
23
|
-
|
24
|
-
|
23
|
+
if (await get_value("locatine_title")) {
|
24
|
+
document.getElementById("mainTitle").innerText = await get_value("locatine_title");
|
25
|
+
document.getElementById("hint").innerText = await get_value("locatine_hint");
|
26
|
+
}
|
25
27
|
if ((document.getElementById("nameHandler").value != await get_value("locatineName")) && (!document.hasFocus())){
|
26
28
|
document.getElementById("nameHandler").value = (await get_value("locatineName") || "");
|
27
29
|
}
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'json'
|
3
|
+
require 'locatine/daemon_helpers'
|
4
|
+
|
5
|
+
module Locatine
|
6
|
+
#
|
7
|
+
# Locatine daemon based on sinatra
|
8
|
+
#
|
9
|
+
# run Locatine::Daemon.run!
|
10
|
+
class Daemon < Sinatra::Base
|
11
|
+
include Locatine::DaemonHelpers
|
12
|
+
configure do
|
13
|
+
set :search, nil
|
14
|
+
end
|
15
|
+
|
16
|
+
get '/app' do
|
17
|
+
{ app: File.join(Locatine::HOME, 'app').to_s }.to_json
|
18
|
+
end
|
19
|
+
|
20
|
+
get '/' do
|
21
|
+
redirect 'https://github.com/sseleznevqa/locatine#using-as-a-daemon'
|
22
|
+
end
|
23
|
+
|
24
|
+
get '/stop' do
|
25
|
+
Locatine::Daemon.quit!
|
26
|
+
{ result: 'dead' }.to_json
|
27
|
+
end
|
28
|
+
|
29
|
+
post '/chromedriver' do
|
30
|
+
Webdrivers::Chromedriver.required_version = params['version']
|
31
|
+
{ version: Webdrivers::Chromedriver.required_version }.to_json
|
32
|
+
end
|
33
|
+
|
34
|
+
get '/chromedriver' do
|
35
|
+
{ path: Webdrivers::Chromedriver.update }.to_json
|
36
|
+
end
|
37
|
+
|
38
|
+
post '/geckodriver' do
|
39
|
+
Webdrivers::Geckodriver.required_version = params['version']
|
40
|
+
{ version: Webdrivers::Geckodriver.required_version }.to_json
|
41
|
+
end
|
42
|
+
|
43
|
+
get '/geckodriver' do
|
44
|
+
{ path: Webdrivers::Geckodriver.update }.to_json
|
45
|
+
end
|
46
|
+
|
47
|
+
post 'iedriver' do
|
48
|
+
Webdrivers::IEdriver.required_version = params['version']
|
49
|
+
{ version: Webdrivers::IEdriver.required_version }.to_json
|
50
|
+
end
|
51
|
+
|
52
|
+
get '/iedriver' do
|
53
|
+
{ path: Webdrivers::IEdriver.update }.to_json
|
54
|
+
end
|
55
|
+
|
56
|
+
post '/connect' do
|
57
|
+
steal
|
58
|
+
{ result: true }.to_json
|
59
|
+
end
|
60
|
+
|
61
|
+
post '/lctr' do
|
62
|
+
data = Hash[params.map { |k, v| [k.to_sym, v] }]
|
63
|
+
data.each { |k, v| data[k] = false if v == 'false' }
|
64
|
+
search.lctr(data).to_json
|
65
|
+
end
|
66
|
+
|
67
|
+
post '/set' do
|
68
|
+
hash = params
|
69
|
+
search.json = hash['json'] if hash['json']
|
70
|
+
warn 'You cannot set browser like this. Use /connect' if hash['browser']
|
71
|
+
params.each_pair do |key, value|
|
72
|
+
unless (key == 'browser') || (key == 'json')
|
73
|
+
value = false if value == 'false'
|
74
|
+
search.instance_variable_set("@#{key}", value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
{ result: true }.to_json
|
78
|
+
end
|
79
|
+
|
80
|
+
def search
|
81
|
+
return settings.search unless settings.search.nil?
|
82
|
+
|
83
|
+
settings.search = Locatine::Search.new
|
84
|
+
settings.search.browser.quit
|
85
|
+
settings.search
|
86
|
+
end
|
87
|
+
|
88
|
+
def params
|
89
|
+
request.body.rewind
|
90
|
+
JSON.parse request.body.read
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Locatine
|
2
|
+
#
|
3
|
+
# Usefull things daemon can do
|
4
|
+
module DaemonHelpers
|
5
|
+
private
|
6
|
+
|
7
|
+
def steal
|
8
|
+
cast_ghost_browser
|
9
|
+
disguise_session
|
10
|
+
disguise_server_url
|
11
|
+
disguise_http
|
12
|
+
disguise_proxy unless params['proxy'].to_s.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def bridge
|
16
|
+
search.browser.wd.send(:bridge)
|
17
|
+
end
|
18
|
+
|
19
|
+
def b_http
|
20
|
+
bridge.send(:http)
|
21
|
+
end
|
22
|
+
|
23
|
+
def disguise_session
|
24
|
+
bridge.instance_variable_set('@session_id', params['session_id'])
|
25
|
+
end
|
26
|
+
|
27
|
+
def disguise_server_url
|
28
|
+
uri = URI.parse(params['url'])
|
29
|
+
b_http.instance_variable_set('@server_url', uri)
|
30
|
+
end
|
31
|
+
|
32
|
+
def disguise_http
|
33
|
+
b_http.instance_variable_set('@http', make_net)
|
34
|
+
end
|
35
|
+
|
36
|
+
def disguise_proxy
|
37
|
+
b_http.instance_variable_set('@proxy', params['proxy'])
|
38
|
+
end
|
39
|
+
|
40
|
+
def make_net
|
41
|
+
parsed = URI.parse(params['url'])
|
42
|
+
path = parsed.path == '/' ? '' : parsed.path
|
43
|
+
Net::HTTP.new("#{parsed.host}#{path}", parsed.port)
|
44
|
+
end
|
45
|
+
|
46
|
+
def cast_ghost_browser
|
47
|
+
search.browser = Watir::Browser.new(params['browser'].to_sym)
|
48
|
+
search.browser.quit
|
49
|
+
search.browser.instance_variable_set('@closed', false)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|