locatine 0.02058 → 0.02539

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: 839233263a07aac6fda720392d0dbd920a5a9660
4
- data.tar.gz: b60a4fdc5d93b96abb65b49c128302eb73d5a9b6
3
+ metadata.gz: 63c1d452b58e6881483141749a4cd5fc572a1a34
4
+ data.tar.gz: 5436ddbbd222888ab16ef121750e871be2d0b330
5
5
  SHA512:
6
- metadata.gz: f6279a2237def4ac7799e8a1ed6f3d293251d92ad7e2a62e13fd98ac22b05c2d4bccaabd4be19cf9de97f27a28a98916d784236af6240109ccb61323481dd7be
7
- data.tar.gz: f1f87a3f394b2091d0391e53e3844067e6c929d51dfc68e2d526a0dd44dd588ce293752044e9c27602997f3d9b2d43c27e1fb657683387761079fae9b81d5f65
6
+ metadata.gz: 875b40b1ebc3294dc60868c4f029a3eb2c37b984509002c30fadecad20d7e26f0df207eab8ed3466cc7021777d9a89baa6a0a6c4ba7dc655bea1109b573031cb
7
+ data.tar.gz: 9c36756f4c0388acf60d1009ed79ebed732b2401daa387930a3f61c8c97b745f2c1bc0bdeeced30e300543d88b09459c7bdf0f7320ef4630dbd47e83c9b58550
data/README.md CHANGED
@@ -16,7 +16,7 @@ That's it.
16
16
 
17
17
  ## Stage of development:
18
18
 
19
- Version of Locatine is **0.02058** 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.02539** only. It means so far this is an alfa. You can use it in a real project if you are a risky person.
20
20
 
21
21
  ## Installation
22
22
 
@@ -96,7 +96,10 @@ Locatine::Search.new(json: "./Locatine_files/default.json",
96
96
  scope: "Default",
97
97
  tolerance: 33,
98
98
  visual_search: false,
99
- no_fail: false)
99
+ no_fail: false,
100
+ trusted: [],
101
+ untrusted: [],
102
+ autolearn: nil)
100
103
  ```
101
104
 
102
105
  ### json
@@ -147,6 +150,24 @@ Be careful! Set true only if appearance of your page is pretty stable.
147
150
 
148
151
  When element is lost and no_fail is true you will get nil for single element and [] for collection. If no_fail is false (which is default) and locatine cannot find something you will face an error.
149
152
 
153
+ ### trusted/untrusted
154
+
155
+ If you are sure that some attribute (or something) is not good(generated by random, not uniq, etc.) you can forbid to use it in search. You can write attribute name, "text", "tag", or css attribute name (if you are using visual_search)
156
+
157
+ On the other hand you can force locatine to always trust something with trusted.
158
+
159
+ ### autolearn
160
+
161
+ Determines wether Locatine will study elements by default or not.
162
+
163
+ 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.
164
+
165
+ If false Locatine will study element only in case when it is lost.
166
+
167
+ 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).
168
+
169
+ Notice that if autolearn is false Locatine is not bumping the stability values of attributes for elements which were found normally.
170
+
150
171
  ## Changing options on fly
151
172
 
152
173
  You can get or set these values on fly. Like:
@@ -170,7 +191,9 @@ s.find(name: "some name",
170
191
  return_locator: false,
171
192
  collection: false,
172
193
  tolerance: nil,
173
- no_fail: nil)
194
+ no_fail: nil,
195
+ trusted: [],
196
+ untrusted: [])
174
197
  ```
175
198
  ### name
176
199
 
@@ -219,7 +242,7 @@ vars = {tag: random_tag} # The tag
219
242
  vars = {attribute_name: random_attr} # If attribute is dynamic (use name of the attribute)
220
243
  # And two lines work with visual_search == true only
221
244
  vars = {css_option: random_value} # If your css is dynamic
222
- vars = {x: random_x} # x, y, width, height for element size and position
245
+ vars = {x: random_x} # x, y for element position
223
246
  ```
224
247
 
225
248
  And if you do not like it you can do:
@@ -257,6 +280,10 @@ It is disabling attempts to find element by advanced algorithms. If locator is p
257
280
 
258
281
  no_fail option that will work for that search only.
259
282
 
283
+ ### trusted//untrusted
284
+
285
+ You can set trusted elements just for search
286
+
260
287
  ## Scope
261
288
 
262
289
  If you want to define a whole bunch of elements at once you can do:
@@ -347,3 +374,131 @@ s.exact(name: "something") == s.find(name: "something", exact: true)
347
374
  s.check(name: "something") == s.find(name: "something", tolerance: 0)
348
375
  s.check_collection(name: "something") == s.collect(name: "something", tolerance: 0)
349
376
  ```
377
+
378
+ ## Using as a daemon
379
+
380
+ Locatine daemon is a web server based on sinatra. You can run it from your code like:
381
+
382
+ ```ruby
383
+ require 'locatine'
384
+ Locatine::Daemon.set :port, 7733 #Your port goes here
385
+ Locatine::Daemon.run!
386
+ ```
387
+
388
+ Also you can do it with terminal:
389
+
390
+ ```bash
391
+ locatine-daemon.rb -port=7733
392
+ ```
393
+
394
+ You can see a python3 example in the [example](https://github.com/sseleznevqa/locatine/tree/master/example) folder. Main idea is
395
+
396
+ 1. Run daemon
397
+ 2. Ask daemon for the app path
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.
405
+
406
+ ### API
407
+
408
+ #### GET call to /app
409
+
410
+ returns path to locatine application in order to start chrome with it.
411
+
412
+ Example of response:
413
+
414
+ ```
415
+ {"app": "/some/path/to/app"}
416
+ ```
417
+
418
+ #### GET call to /stop
419
+
420
+ stops Locatine daemon.
421
+
422
+ Returns:
423
+
424
+ ```
425
+ {"result": "dead"}
426
+ ```
427
+
428
+ #### POST call to /connect
429
+
430
+ allows Locatine Daemon to connect existing browser instance
431
+
432
+ POST data:
433
+
434
+ ```
435
+ {'browser': 'chrome', 'session_id': session_id, 'url': 'http://whatever_is_browser_ip:port_opened_by_browser_for_selenium', 'proxy': 'optionally' }
436
+ ```
437
+
438
+ Answer:
439
+
440
+ ```
441
+ {"result": "true"}
442
+ ```
443
+
444
+ #### POST call to /set
445
+
446
+ is to control options of locatine search. Sending to set data ==
447
+
448
+ ```
449
+ {"learn": "true"}
450
+ ```
451
+
452
+ Answer:
453
+
454
+ ```
455
+ {"result": "true"}
456
+ ```
457
+
458
+ is the same as
459
+
460
+ ```ruby
461
+ search.learn = true
462
+ ```
463
+
464
+ #### POST call to /lctr
465
+
466
+ is to find and return locator of an element found by locatine
467
+
468
+ POST data just the same as for find or lctr method. It's like:
469
+
470
+ ```
471
+ {"name": "some name", "scope": "Default", "exact": "false" ...}
472
+ ```
473
+
474
+ Answer:
475
+
476
+ ```
477
+ {"xpath": "//YOUR[@xpath='goes here']"}
478
+ ```
479
+
480
+ ### GET /chromedriver || /geckodriver || /iedriver
481
+
482
+ returns path to the binary retrieved by locatine (using webdrivers gem)
483
+
484
+ Answer:
485
+
486
+ ```
487
+ {"path": "path/to/the/binary"}
488
+ ```
489
+
490
+ ### POST call to /chromedriver || /geckodriver || /iedriver
491
+
492
+ is to force locatine to use your webdriver (for example for using old version of browser)
493
+
494
+ POST data:
495
+
496
+ ```
497
+ {"version": "2.46"}
498
+ ```
499
+
500
+ Answer:
501
+
502
+ ```
503
+ {"version": "2.46"}
504
+ ```
@@ -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,6 @@
1
1
  {
2
2
  "name": "Locatine app",
3
- "version": "0.02058",
3
+ "version": "0.02539",
4
4
  "description": "Messaging from browser to main app",
5
5
  "devtools_page": "devtools.html",
6
6
  "permissions": ["activeTab", "storage", "contextMenus", "tabs"],
@@ -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
@@ -5,53 +5,36 @@ module Locatine
5
5
  module DataGenerate
6
6
  private
7
7
 
8
- def real_text_of(element)
9
- element.text == element.inner_html ? element.text : ''
10
- end
11
-
12
8
  def mesure(element)
13
9
  xy = element.location
14
10
  wh = element.size
15
11
  return xy.x, xy.y, wh.width, wh.height
16
12
  end
17
13
 
18
- def get_dynamic_tag(element, vars)
19
- tag = element.tag_name
20
- tag = "\#{tag}" if vars[:tag] == tag
14
+ def get_dynamic_tag(tag, vars)
15
+ tag = "\#{tag}" if vars[:tag].to_s.casecmp(tag).zero?
21
16
  push_hash('tag', tag, 'tag')
22
17
  end
23
18
 
24
- def get_dynamic_text(element, vars)
25
- attrs = []
26
- real_text_of(element).split(/['" ]/).each do |word|
19
+ def text_array(text)
20
+ text.to_s.tr("\n", ' ').split(/['" ]/)
21
+ end
22
+
23
+ def get_dynamic_text(text, vars)
24
+ attrs = text_array(text).map do |word|
27
25
  final = if !vars[:text].to_s.strip.empty?
28
26
  word.gsub(vars[:text].to_s, "\#{text}")
29
27
  else
30
28
  word
31
29
  end
32
- attrs.push push_hash('text', final, 'text') unless final.empty?
30
+ push_hash('text', final, 'text') unless final.empty?
33
31
  end
34
- attrs
35
- end
36
-
37
- def process_dimension(name, value, vars)
38
- s_name = name.to_s
39
- value = value.to_s.gsub(vars[name], "\#{#{s_name}}") if vars[name]
40
- value
32
+ attrs.compact
41
33
  end
42
34
 
43
- def processed_dimensions(element, vars)
44
- x, y, width, height = mesure(element)
45
- x = process_dimension(:x, x, vars)
46
- y = process_dimension(:y, y, vars)
47
- width = process_dimension(:width, width, vars)
48
- height = process_dimension(:height, height, vars)
49
- return x, y, width, height
50
- end
51
-
52
- def get_dimensions(element, vars)
35
+ def get_dimensions(element)
53
36
  resolution = window_size
54
- x, y, w, h = processed_dimensions(element, vars)
37
+ x, y, w, h = mesure(element)
55
38
  push_hash(resolution, "#{x}*#{y}*#{w}*#{h}", 'dimensions')
56
39
  end
57
40
 
@@ -79,22 +62,6 @@ module Locatine
79
62
  end
80
63
  attrs
81
64
  end
82
-
83
- ##
84
- # Collecting attributes of the element
85
- def get_attributes(element)
86
- attributes = element.attributes
87
- array = []
88
- attributes.each_pair do |name, value|
89
- next if name.to_s == 'locatineclass' # Should never happen
90
-
91
- value.split(/['" ]/).reject(&:empty?).uniq.each do |part|
92
- array.push('name' => name.to_s, 'type' => 'attribute',
93
- 'value' => part)
94
- end
95
- end
96
- array
97
- end
98
65
  end
99
66
  end
100
67
  end