locatine 0.02327 → 0.02637

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a584853859a41d1442f3037bef100dec0bb1d09e
4
- data.tar.gz: 298cabc4969b4e454bb3d6bd9f5f2b5d091ff53c
3
+ metadata.gz: 8d969a9d3fc96c105d69b1d41f7ff8df92198d6d
4
+ data.tar.gz: 93ec07af0558fd08a13224686c9844775f3b36c9
5
5
  SHA512:
6
- metadata.gz: 4a317d9efb1aab542d551d90272ee912edb9b7ee36df13ad74292d1ac377848995d19a786104a5db89480f636bf14d77c3b3f1271d4b408732729d8f0498baa8
7
- data.tar.gz: 99dbade69774c044b519d78e5c3ec3b0ba7469eb803e9cff80eee1fa3549bd566460ffaaf2c3c95e7a7817bd83c6dd2254101ef50666a76503a91a19a06b117f
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.02327** only. It means so far this is an alfa. You can use it in a real project if you are a risky person.
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, width, height for element size and position
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
@@ -1,3 +1,4 @@
1
1
  require 'locatine/search'
2
2
  require 'locatine/scope'
3
3
  require 'locatine/version'
4
+ require 'locatine/daemon'
@@ -1,6 +1,5 @@
1
1
  chrome.browserAction.onClicked.addListener(
2
2
  function(tab) {
3
- console.log("WAS here");
4
3
  chrome.windows.create( {'url': 'popup.html',
5
4
  'type': 'popup',
6
5
  'width': 640,
@@ -20,7 +20,7 @@ div[locatinestyle=true] {
20
20
  display: block;
21
21
  z-index: 2147483646;
22
22
  color: #FF99AA;
23
- font-size: 45px;
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;
@@ -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 op = 1;
49
- magicDiv.innerHTML = await get_value("locatine_title");
50
- let timer = setInterval(function () {
51
- if ((magicDiv.style.opacity == 1) && (op < 0.97)) {
52
- clearInterval(timer);// If other process changed opacity.
53
- };
54
- if (op <= 0.2) {
55
- clearInterval(timer);
56
- magicDiv.style.opacity = 0;
57
- magicDiv.innerHTML = "";
58
- }
59
- magicDiv.style.opacity = op;
60
- magicDiv.style.filter = 'alpha(opacity=' + op * 100 + ")";
61
- op -= op * 0.03;
62
- }, 50);
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", "blocked");
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") != "blocked") {
146
+ if (document.getElementById("locatine_magic_div").getAttribute("locatinestyle") != "false") {
143
147
  await refreshData()
144
148
  }
145
149
  } else {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Locatine app",
3
- "version": "0.02327",
3
+ "version": "0.02637",
4
4
  "description": "Messaging from browser to main app",
5
5
  "devtools_page": "devtools.html",
6
6
  "permissions": ["activeTab", "storage", "contextMenus", "tabs"],
@@ -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
- document.getElementById("mainTitle").innerText = await get_value("locatine_title");
24
- document.getElementById("hint").innerText = await get_value("locatine_hint");
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