isomorfeus-puppetmaster 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/isomorfeus-puppetmaster.rb +1 -4
- data/lib/isomorfeus/puppetmaster/document.rb +1 -1
- data/lib/isomorfeus/puppetmaster/driver/puppeteer.rb +36 -31
- data/lib/isomorfeus/puppetmaster/driver/puppeteer_document.rb +26 -8
- data/lib/isomorfeus/puppetmaster/driver_registration.rb +0 -8
- data/lib/isomorfeus/puppetmaster/server.rb +13 -9
- data/lib/isomorfeus/puppetmaster/server/executor_middleware.rb +17 -8
- data/lib/isomorfeus/puppetmaster/version.rb +1 -1
- metadata +20 -9
- data/lib/isomorfeus/puppetmaster/driver/jsdom.rb +0 -373
- data/lib/isomorfeus/puppetmaster/driver/jsdom_document.rb +0 -917
- data/lib/isomorfeus/puppetmaster/driver/jsdom_node.rb +0 -842
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1a369c88fa52e50d5258aad78591bcd079723ae8b31c1060829113f4cfc5323
|
4
|
+
data.tar.gz: b420d2cce1ad70c3cf02e9afbe376e2d8ac4e8fda259a80d8b97bbdcdb5f5006
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f1fd308a029db3d5d278906ff4f12957388c6e6c0588aeecfa47e420af518817b53ef7077d9fba1f2bf02b5aa99dd651e05f459abc822f47114137542b3851e
|
7
|
+
data.tar.gz: d3c77ebab0d357c9aa6b1d47f18e66baed051fd4a9361c5636a3eba60a860841a5c13d479e4189d6440d6648657fbde71972f6a3c3758eb1db00912a16c41a7b
|
@@ -36,9 +36,6 @@ require 'isomorfeus/puppetmaster/iframe'
|
|
36
36
|
require 'isomorfeus/puppetmaster/driver/puppeteer_document'
|
37
37
|
require 'isomorfeus/puppetmaster/driver/puppeteer_node'
|
38
38
|
require 'isomorfeus/puppetmaster/driver/puppeteer'
|
39
|
-
require 'isomorfeus/puppetmaster/driver/jsdom_document'
|
40
|
-
require 'isomorfeus/puppetmaster/driver/jsdom_node'
|
41
|
-
require 'isomorfeus/puppetmaster/driver/jsdom'
|
42
39
|
require 'isomorfeus/puppetmaster/driver_registration'
|
43
40
|
require 'isomorfeus/puppetmaster/server/executor_middleware'
|
44
41
|
require 'isomorfeus/puppetmaster/server/middleware'
|
@@ -46,4 +43,4 @@ require 'isomorfeus/puppetmaster/server/checker'
|
|
46
43
|
require 'isomorfeus/puppetmaster/server'
|
47
44
|
require 'isomorfeus/puppetmaster/server_registration'
|
48
45
|
|
49
|
-
require 'isomorfeus/puppetmaster/dsl'
|
46
|
+
require 'isomorfeus/puppetmaster/dsl'
|
@@ -100,7 +100,7 @@ module Isomorfeus
|
|
100
100
|
start = Time.now
|
101
101
|
until have_result do
|
102
102
|
raise "await_ruby: execution timed out! Is Opal available?" if (Time.now - start) > 30
|
103
|
-
have_result = evaluate_script 'Opal.gvars.promise_resolved'
|
103
|
+
have_result = evaluate_script 'Opal ? Opal.gvars.promise_resolved : null'
|
104
104
|
sleep 0.1 unless have_result
|
105
105
|
end
|
106
106
|
result, exception = execute_script <<~JAVASCRIPT
|
@@ -196,18 +196,16 @@ module Isomorfeus
|
|
196
196
|
def await(script)
|
197
197
|
@context.eval <<~JAVASCRIPT
|
198
198
|
(async () => {
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
}
|
210
|
-
})()
|
199
|
+
LastExecutionFinished = false;
|
200
|
+
LastResult = null;
|
201
|
+
LastErr = null;
|
202
|
+
#{script}
|
203
|
+
LastExecutionFinished = true;
|
204
|
+
})().catch(function(err) {
|
205
|
+
LastResult = null;
|
206
|
+
LastErr = err;
|
207
|
+
LastExecutionFinished = true;
|
208
|
+
})
|
211
209
|
JAVASCRIPT
|
212
210
|
await_result
|
213
211
|
end
|
@@ -226,20 +224,23 @@ module Isomorfeus
|
|
226
224
|
JAVASCRIPT
|
227
225
|
end
|
228
226
|
|
229
|
-
def determine_error(
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
227
|
+
def determine_error(error)
|
228
|
+
message = "#{error['name']}: #{error['message']}"
|
229
|
+
exception = if message.include?('net::ERR_CERT_') || message.include?('SEC_ERROR_EXPIRED_CERTIFICATE')
|
230
|
+
Isomorfeus::Puppetmaster::CertificateError.new(message)
|
231
|
+
elsif message.include?('net::ERR_NAME_') || message.include?('NS_ERROR_UNKNOWN_HOST')
|
232
|
+
Isomorfeus::Puppetmaster::DNSError.new(message)
|
233
|
+
elsif message.include?('Unknown key: ')
|
234
|
+
Isomorfeus::Puppetmaster::KeyError.new(message)
|
235
|
+
elsif message.include?('Execution context was destroyed, most likely because of a navigation.')
|
236
|
+
Isomorfeus::Puppetmaster::ExecutionContextError.new(message)
|
237
|
+
elsif message.include?('Evaluation failed: DOMException:') || (message.include?('Evaluation failed:') && (message.include?('is not a valid selector') || message.include?('is not a legal expression')))
|
238
|
+
Isomorfeus::Puppetmaster::DOMException.new(message)
|
239
|
+
else
|
240
|
+
Isomorfeus::Puppetmaster::JavaScriptError.new(message)
|
241
|
+
end
|
242
|
+
exception.set_backtrace(error['stack'])
|
243
|
+
exception
|
243
244
|
end
|
244
245
|
|
245
246
|
def execution_finished?
|
@@ -247,8 +248,8 @@ module Isomorfeus
|
|
247
248
|
end
|
248
249
|
|
249
250
|
def get_result
|
250
|
-
res,
|
251
|
-
raise determine_error(
|
251
|
+
res, error = @context.eval 'GetLastResult()'
|
252
|
+
raise determine_error(error) if error && !error.empty?
|
252
253
|
res
|
253
254
|
end
|
254
255
|
|
@@ -307,11 +308,12 @@ module Isomorfeus
|
|
307
308
|
LastRes = null;
|
308
309
|
LastExecutionFinished = false;
|
309
310
|
|
310
|
-
if (err) { return [null, err.
|
311
|
+
if (err) { return [null, {name: err.name, message: err.message, stack: err.stack}]; }
|
311
312
|
else { return [res, null]; }
|
312
313
|
|
313
314
|
} else {
|
314
|
-
|
315
|
+
var new_err = new Error('Last command did not yet finish execution!');
|
316
|
+
return [null, {name: new_err.name, message: new_err.message, stack: new_err.stack}];
|
315
317
|
}
|
316
318
|
};
|
317
319
|
|
@@ -374,7 +376,10 @@ module Isomorfeus
|
|
374
376
|
LastErr = err;
|
375
377
|
LastExecutionFinished = true;
|
376
378
|
}
|
377
|
-
})()
|
379
|
+
})().catch(function(err) {
|
380
|
+
LastErr = err;
|
381
|
+
LastExecutionFinished = true;
|
382
|
+
});
|
378
383
|
JAVASCRIPT
|
379
384
|
end
|
380
385
|
|
@@ -310,17 +310,35 @@ module Isomorfeus
|
|
310
310
|
|
311
311
|
def document_evaluate_script(document, script, *args)
|
312
312
|
await <<~JAVASCRIPT
|
313
|
-
|
314
|
-
|
313
|
+
var result = await AllPageHandles[#{document.handle}].evaluate((arguments) => {
|
314
|
+
try {
|
315
|
+
var res = (function(arguments) {
|
316
|
+
return #{script.strip};
|
317
|
+
})(arguments);
|
318
|
+
return [res, null];
|
319
|
+
} catch (err) {
|
320
|
+
return [null, {name: err.name, message: err.message, stack: err.stack}];
|
321
|
+
}
|
315
322
|
}, #{args});
|
323
|
+
LastResult = result[0];
|
324
|
+
LastErr = result[1];
|
316
325
|
JAVASCRIPT
|
317
326
|
end
|
318
327
|
|
319
328
|
def document_execute_script(document, script, *args)
|
320
329
|
await <<~JAVASCRIPT
|
321
|
-
|
322
|
-
|
330
|
+
var result = await AllPageHandles[#{document.handle}].evaluate((arguments) => {
|
331
|
+
try {
|
332
|
+
var res = (function(arguments) {
|
333
|
+
#{script.strip};
|
334
|
+
})(arguments);
|
335
|
+
return [res, null];
|
336
|
+
} catch (err) {
|
337
|
+
return [null, {name: err.name, message: err.message, stack: err.stack}];
|
338
|
+
}
|
323
339
|
}, #{args});
|
340
|
+
LastResult = result[0];
|
341
|
+
LastErr = result[1];
|
324
342
|
JAVASCRIPT
|
325
343
|
end
|
326
344
|
|
@@ -454,7 +472,7 @@ module Isomorfeus
|
|
454
472
|
}
|
455
473
|
JAVASCRIPT
|
456
474
|
con_messages = messages.map {|m| Isomorfeus::Puppetmaster::ConsoleMessage.new(m)}
|
457
|
-
con_messages.each { |m| raise determine_error(m.text) if m.level == 'error' && !m.text.start_with?('Failed to load resource:') }
|
475
|
+
con_messages.each { |m| raise determine_error({ 'message' => m.text }) if m.level == 'error' && !m.text.start_with?('Failed to load resource:') }
|
458
476
|
if response_hash
|
459
477
|
response = Isomorfeus::Puppetmaster::Response.new(response_hash)
|
460
478
|
document.instance_variable_set(:@response, response)
|
@@ -491,7 +509,7 @@ module Isomorfeus
|
|
491
509
|
}
|
492
510
|
JAVASCRIPT
|
493
511
|
con_messages = messages.map {|m| Isomorfeus::Puppetmaster::ConsoleMessage.new(m)}
|
494
|
-
con_messages.each { |m| raise determine_error(m.text) if m.level == 'error' && !m.text.start_with?('Failed to load resource:') }
|
512
|
+
con_messages.each { |m| raise determine_error({ 'message' => m.text }) if m.level == 'error' && !m.text.start_with?('Failed to load resource:') }
|
495
513
|
if response_hash
|
496
514
|
response = Isomorfeus::Puppetmaster::Response.new(response_hash)
|
497
515
|
document.instance_variable_set(:@response, response)
|
@@ -532,7 +550,7 @@ module Isomorfeus
|
|
532
550
|
}
|
533
551
|
JAVASCRIPT
|
534
552
|
con_messages = messages.map {|m| Isomorfeus::Puppetmaster::ConsoleMessage.new(m)}
|
535
|
-
con_messages.each { |m| raise determine_error(m.text) if m.level == 'error' && !m.text.start_with?('Failed to load resource:') }
|
553
|
+
con_messages.each { |m| raise determine_error({ 'message' => m.text }) if m.level == 'error' && !m.text.start_with?('Failed to load resource:') }
|
536
554
|
if response_hash
|
537
555
|
response = Isomorfeus::Puppetmaster::Response.new(response_hash)
|
538
556
|
document.instance_variable_set(:@response, response)
|
@@ -610,7 +628,7 @@ module Isomorfeus
|
|
610
628
|
LastResult = [page_handle, result_response, ConsoleMessages[page_handle]];
|
611
629
|
JAVASCRIPT
|
612
630
|
con_messages = messages.map {|m| Isomorfeus::Puppetmaster::ConsoleMessage.new(m)}
|
613
|
-
con_messages.each { |m| raise determine_error(m.text) if m.level == 'error' && !m.text.start_with?('Failed to load resource:') }
|
631
|
+
con_messages.each { |m| raise determine_error({ 'message' => m.text }) if m.level == 'error' && !m.text.start_with?('Failed to load resource:') }
|
614
632
|
Isomorfeus::Puppetmaster::Document.new(self, handle, Isomorfeus::Puppetmaster::Response.new(response_hash))
|
615
633
|
end
|
616
634
|
|
@@ -9,11 +9,3 @@ end
|
|
9
9
|
Isomorfeus::Puppetmaster.register_driver(:chromium_debug) do |app|
|
10
10
|
Isomorfeus::Puppetmaster::Driver::Puppeteer.new(browser_type: :chromium, headless: false, devtools: true, app: app)
|
11
11
|
end
|
12
|
-
|
13
|
-
Isomorfeus::Puppetmaster.register_driver(:jsdom) do |app|
|
14
|
-
Isomorfeus::Puppetmaster::Driver::Jsdom.new(app: app)
|
15
|
-
end
|
16
|
-
|
17
|
-
Isomorfeus::Puppetmaster.register_driver(:jsdom_canvas) do |app|
|
18
|
-
Isomorfeus::Puppetmaster::Driver::Jsdom.new(app: app, canvas: true)
|
19
|
-
end
|
@@ -66,18 +66,22 @@ module Isomorfeus
|
|
66
66
|
ruby_source = Isomorfeus::Puppetmaster.block_source_code(&block) if block_given?
|
67
67
|
request_hash = { 'key' => @request_key, 'code' => ruby_source }
|
68
68
|
response = if using_ssl?
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
http = Net::HTTP.start(@host, @port, { use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE })
|
70
|
+
http.post('/__executor__', Oj.dump(request_hash, mode: :strict))
|
71
|
+
else
|
72
|
+
http = Net::HTTP.start(@host, @port)
|
73
|
+
http.post('/__executor__', Oj.dump(request_hash, mode: :strict))
|
74
|
+
end
|
75
75
|
if response.code == '200'
|
76
|
-
result_hash = Oj.load(response.body
|
77
|
-
|
76
|
+
result_hash = Oj.load(response.body)
|
77
|
+
if result_hash.has_key?('error')
|
78
|
+
error = RuntimeError.new(result_hash['error'])
|
79
|
+
error.set_backtrace(result_hash['backtrace'])
|
80
|
+
raise error
|
81
|
+
end
|
78
82
|
result_hash['result']
|
79
83
|
else
|
80
|
-
raise 'A error
|
84
|
+
raise 'A error occurred.'
|
81
85
|
end
|
82
86
|
end
|
83
87
|
|
@@ -14,18 +14,27 @@ module Isomorfeus
|
|
14
14
|
def call(env)
|
15
15
|
if env['PATH_INFO'] == '/__executor__' && env['REQUEST_METHOD'] == 'POST'
|
16
16
|
request = Rack::Request.new(env)
|
17
|
+
response = nil
|
17
18
|
unless request.body.nil?
|
18
|
-
request_hash = Oj.load(request.body.read,
|
19
|
+
request_hash = Oj.load(request.body.read, mode: :strict)
|
19
20
|
if request_hash['key'] != @@request_key
|
20
|
-
Rack::Response.new(Oj.dump({ 'error' => 'wrong key given, execution denied' }
|
21
|
+
response = Rack::Response.new(Oj.dump({ 'error' => 'wrong key given, execution denied' }),
|
22
|
+
401,
|
23
|
+
'Content-Type' => 'application/json')
|
24
|
+
else
|
25
|
+
begin
|
26
|
+
result = TOPLEVEL_BINDING.eval('self').instance_eval(request_hash['code']) if request_hash['code']
|
27
|
+
response = Rack::Response.new(Oj.dump({ 'result' => result }),
|
28
|
+
200,
|
29
|
+
'Content-Type' => 'application/json')
|
30
|
+
rescue Exception => e
|
31
|
+
response = Rack::Response.new(Oj.dump({ 'error' => "#{e.class}: #{e.message}", 'backtrace' => e.backtrace.join("\n") }),
|
32
|
+
200,
|
33
|
+
'Content-Type' => 'application/json')
|
34
|
+
end
|
21
35
|
end
|
22
|
-
begin
|
23
|
-
result = Object.instance_eval(request_hash['code']) if request_hash['code']
|
24
|
-
rescue Exception => e
|
25
|
-
Rack::Response.new(Oj.dump({ 'error' => "#{e.class}: #{e.message}" }, {}), 200, 'Content-Type' => 'application/json').finish
|
26
|
-
end
|
27
|
-
Rack::Response.new(Oj.dump({ 'result' => result }, {}), 200, 'Content-Type' => 'application/json').finish
|
28
36
|
end
|
37
|
+
response.finish
|
29
38
|
else
|
30
39
|
@app.call(env)
|
31
40
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: isomorfeus-puppetmaster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Biedermann
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-01-
|
11
|
+
date: 2020-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: oj
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.10.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.10.1
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: opal
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,14 +128,14 @@ dependencies:
|
|
114
128
|
requirements:
|
115
129
|
- - "~>"
|
116
130
|
- !ruby/object:Gem::Version
|
117
|
-
version: 2.11.
|
131
|
+
version: 2.11.7
|
118
132
|
type: :development
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
135
|
requirements:
|
122
136
|
- - "~>"
|
123
137
|
- !ruby/object:Gem::Version
|
124
|
-
version: 2.11.
|
138
|
+
version: 2.11.7
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: chunky_png
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -170,14 +184,14 @@ dependencies:
|
|
170
184
|
requirements:
|
171
185
|
- - "~>"
|
172
186
|
- !ruby/object:Gem::Version
|
173
|
-
version: 0.7.
|
187
|
+
version: 0.7.38
|
174
188
|
type: :development
|
175
189
|
prerelease: false
|
176
190
|
version_requirements: !ruby/object:Gem::Requirement
|
177
191
|
requirements:
|
178
192
|
- - "~>"
|
179
193
|
- !ruby/object:Gem::Version
|
180
|
-
version: 0.7.
|
194
|
+
version: 0.7.38
|
181
195
|
- !ruby/object:Gem::Dependency
|
182
196
|
name: irb
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -317,9 +331,6 @@ files:
|
|
317
331
|
- lib/isomorfeus/puppetmaster/console_message.rb
|
318
332
|
- lib/isomorfeus/puppetmaster/cookie.rb
|
319
333
|
- lib/isomorfeus/puppetmaster/document.rb
|
320
|
-
- lib/isomorfeus/puppetmaster/driver/jsdom.rb
|
321
|
-
- lib/isomorfeus/puppetmaster/driver/jsdom_document.rb
|
322
|
-
- lib/isomorfeus/puppetmaster/driver/jsdom_node.rb
|
323
334
|
- lib/isomorfeus/puppetmaster/driver/puppeteer.rb
|
324
335
|
- lib/isomorfeus/puppetmaster/driver/puppeteer_document.rb
|
325
336
|
- lib/isomorfeus/puppetmaster/driver/puppeteer_node.rb
|
@@ -1,373 +0,0 @@
|
|
1
|
-
module Isomorfeus
|
2
|
-
module Puppetmaster
|
3
|
-
module Driver
|
4
|
-
class Jsdom
|
5
|
-
include Isomorfeus::Puppetmaster::Driver::JsdomDocument
|
6
|
-
include Isomorfeus::Puppetmaster::Driver::JsdomNode
|
7
|
-
|
8
|
-
VIEWPORT_DEFAULT_WIDTH = 1024
|
9
|
-
VIEWPORT_DEFAULT_HEIGHT = 768
|
10
|
-
VIEWPORT_MAX_WIDTH = 1366
|
11
|
-
VIEWPORT_MAX_HEIGHT = 768
|
12
|
-
TIMEOUT = 30 # seconds
|
13
|
-
REACTION_TIMEOUT = 0.5
|
14
|
-
EVENTS = {
|
15
|
-
blur: ['FocusEvent', {}],
|
16
|
-
focus: ['FocusEvent', {}],
|
17
|
-
focusin: ['FocusEvent', { bubbles: true }],
|
18
|
-
focusout: ['FocusEvent', { bubbles: true }],
|
19
|
-
click: ['MouseEvent', { bubbles: true, cancelable: true }],
|
20
|
-
dblckick: ['MouseEvent', { bubbles: true, cancelable: true }],
|
21
|
-
mousedown: ['MouseEvent', { bubbles: true, cancelable: true }],
|
22
|
-
mouseup: ['MouseEvent', { bubbles: true, cancelable: true }],
|
23
|
-
mouseenter: ['MouseEvent', {}],
|
24
|
-
mouseleave: ['MouseEvent', {}],
|
25
|
-
mousemove: ['MouseEvent', { bubbles: true, cancelable: true }],
|
26
|
-
mouseover: ['MouseEvent', { bubbles: true, cancelable: true }],
|
27
|
-
mouseout: ['MouseEvent', { bubbles: true, cancelable: true }],
|
28
|
-
context_menu: ['MouseEvent', { bubble: true, cancelable: true }],
|
29
|
-
submit: ['Event', { bubbles: true, cancelable: true }],
|
30
|
-
change: ['Event', { bubbles: true, cacnelable: false }],
|
31
|
-
input: ['InputEvent', { bubbles: true, cacnelable: false }],
|
32
|
-
wheel: ['WheelEvent', { bubbles: true, cancelable: true }]
|
33
|
-
}.freeze
|
34
|
-
|
35
|
-
attr_accessor :default_document
|
36
|
-
|
37
|
-
def initialize(options = {})
|
38
|
-
@app = options.delete(:app)
|
39
|
-
@options = options.dup
|
40
|
-
@canvas = @options.delete(:canvas) { false }
|
41
|
-
@ignore_https_errors = !!@options.delete(:ignore_https_errors)
|
42
|
-
@max_width = @options.delete(:max_width) { VIEWPORT_MAX_WIDTH }
|
43
|
-
@max_height = @options.delete(:max_height) { VIEWPORT_MAX_HEIGHT }
|
44
|
-
@width = @options.delete(:width) { VIEWPORT_DEFAULT_WIDTH > @max_width ? @max_width : VIEWPORT_DEFAULT_WIDTH }
|
45
|
-
@height = @options.delete(:height) { VIEWPORT_DEFAULT_HEIGHT > @max_height ? @max_height : VIEWPORT_DEFAULT_HEIGHT }
|
46
|
-
@timeout = @options.delete(:timeout) { TIMEOUT }
|
47
|
-
@max_wait = @options.delete(:max_wait) { @timeout + 1 }
|
48
|
-
@reaction_timeout = @options.delete(:reaction_timeout) { REACTION_TIMEOUT }
|
49
|
-
@jsdom_timeout = @timeout * 1000
|
50
|
-
@jsdom_reaction_timeout = @reaction_timeout * 1000
|
51
|
-
@url_blacklist = @options.delete(:url_blacklist) { [] }
|
52
|
-
@context = ExecJS.permissive_compile(jsdom_launch)
|
53
|
-
page_handle, @browser = await_result
|
54
|
-
@default_document = Isomorfeus::Puppetmaster::Document.new(self, page_handle, Isomorfeus::Puppetmaster::Response.new('status' => 200))
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.document_handle_disposer(driver, handle)
|
58
|
-
cjs = <<~JAVASCRIPT
|
59
|
-
delete AllDomHandles[#{handle}];
|
60
|
-
delete ConsoleMessages[#{handle}];
|
61
|
-
JAVASCRIPT
|
62
|
-
proc { driver.execute_script(cjs) }
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.node_handle_disposer(driver, handle)
|
66
|
-
cjs = <<~JAVASCRIPT
|
67
|
-
if (AllElementHandles[#{handle}]) { AllElementHandles[#{handle}].dispose(); }
|
68
|
-
delete AllElementHandles[#{handle}];
|
69
|
-
JAVASCRIPT
|
70
|
-
proc { driver.execute_script(cjs) }
|
71
|
-
end
|
72
|
-
|
73
|
-
def browser
|
74
|
-
@browser
|
75
|
-
end
|
76
|
-
|
77
|
-
def document_handles
|
78
|
-
@context.eval 'Object.keys(AllDomHandles)'
|
79
|
-
end
|
80
|
-
|
81
|
-
##### frame, all todo
|
82
|
-
|
83
|
-
def frame_all_text(frame)
|
84
|
-
await <<~JAVASCRIPT
|
85
|
-
LastResult = await AllElementHandles[#{frame.handle}].executionContext().evaluate((frame) => {
|
86
|
-
return frame.contentDocument.documentElement.textContent;
|
87
|
-
}, AllElementHandles[#{frame.handle}]);
|
88
|
-
JAVASCRIPT
|
89
|
-
end
|
90
|
-
|
91
|
-
def frame_body(frame)
|
92
|
-
node_data = await <<~JAVASCRIPT
|
93
|
-
var tt = await AllElementHandles[#{frame.handle}].executionContext().evaluate((frame) => {
|
94
|
-
node = frame.contentDocument.body;
|
95
|
-
var name = node.nodeName;
|
96
|
-
var tag = node.tagName.toLowerCase();
|
97
|
-
var type = null;
|
98
|
-
if (tag === 'input') { type = node.getAttribute('type'); }
|
99
|
-
return [name, tag, type];
|
100
|
-
}, AllElementHandles[#{frame.handle}]);
|
101
|
-
LastResult = {handle: node_handle, name: tt[0], tag: tt[1], type: tt[2]};
|
102
|
-
JAVASCRIPT
|
103
|
-
if node_data
|
104
|
-
node_data[:css_selector] = 'body'
|
105
|
-
Isomorfeus::Puppetmaster::Node.new_by_tag(self, document, node_data)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def frame_focus(frame)
|
110
|
-
await <<~JAVASCRIPT
|
111
|
-
await AllElementHandles[#{frame.handle}].executionContext().evaluate((frame) => {
|
112
|
-
frame.contentDocument.documentElement.focus();
|
113
|
-
}, AllElementHandles[#{frame.handle}]);
|
114
|
-
JAVASCRIPT
|
115
|
-
end
|
116
|
-
|
117
|
-
def frame_head(frame)
|
118
|
-
node_data = await <<~JAVASCRIPT
|
119
|
-
var tt = await AllElementHandles[#{frame.handle}].executionContext().evaluate((frame) => {
|
120
|
-
node = frame.contentDocument.head;
|
121
|
-
var name = node.nodeName;
|
122
|
-
var tag = node.tagName.toLowerCase();
|
123
|
-
var type = null;
|
124
|
-
if (tag === 'input') { type = node.getAttribute('type'); }
|
125
|
-
return [name, tag, type];
|
126
|
-
}, AllElementHandles[#{frame.handle}]);
|
127
|
-
LastResult = {handle: node_handle, name: tt[0], tag: tt[1], type: tt[2]};
|
128
|
-
JAVASCRIPT
|
129
|
-
if node_data
|
130
|
-
node_data[:css_selector] = 'body'
|
131
|
-
Isomorfeus::Puppetmaster::Node.new_by_tag(self, document, node_data)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def frame_html(frame)
|
136
|
-
await <<~JAVASCRIPT
|
137
|
-
LastResult = await AllElementHandles[#{frame.handle}].executionContext().evaluate((frame) => {
|
138
|
-
return frame.contentDocument.documentElement.outerHTML;
|
139
|
-
}, AllElementHandles[#{frame.handle}]);
|
140
|
-
JAVASCRIPT
|
141
|
-
end
|
142
|
-
|
143
|
-
def frame_title(frame)
|
144
|
-
await <<~JAVASCRIPT
|
145
|
-
LastResult = await AllElementHandles[#{frame.handle}].executionContext().evaluate((frame) => {
|
146
|
-
return frame.contentDocument.title;
|
147
|
-
}, AllElementHandles[#{frame.handle}]);
|
148
|
-
JAVASCRIPT
|
149
|
-
end
|
150
|
-
|
151
|
-
def frame_url(frame)
|
152
|
-
await <<~JAVASCRIPT
|
153
|
-
LastResult = await AllElementHandles[#{frame.handle}].executionContext().evaluate((frame) => {
|
154
|
-
return frame.contentDocument.location.href;
|
155
|
-
}, AllElementHandles[#{frame.handle}]);
|
156
|
-
JAVASCRIPT
|
157
|
-
end
|
158
|
-
|
159
|
-
def frame_visible_text(frame)
|
160
|
-
# if node is AREA, check visibility of relevant image
|
161
|
-
text = await <<~JAVASCRIPT
|
162
|
-
LastResult = await AllElementHandles[#{frame.handle}].executionContext().evaluate((frame) => {
|
163
|
-
var node = frame.contentDocument.body;
|
164
|
-
var temp_node = node;
|
165
|
-
while (temp_node) {
|
166
|
-
style = window.getComputedStyle(node);
|
167
|
-
if (style.display === "none" || style.visibility === "hidden" || parseFloat(style.opacity) === 0) { return ''; }
|
168
|
-
temp_node = temp_node.parentElement;
|
169
|
-
}
|
170
|
-
if (node.nodeName == "TEXTAREA" || node instanceof SVGElement) { return node.textContent; }
|
171
|
-
else { return node.innerText; }
|
172
|
-
}, AllElementHandles[#{frame.handle}]);
|
173
|
-
JAVASCRIPT
|
174
|
-
text.gsub(/\A[[:space:]&&[^\u00a0]]+/, "").gsub(/[[:space:]&&[^\u00a0]]+\z/, "").gsub(/\n+/, "\n").tr("\u00a0", " ")
|
175
|
-
end
|
176
|
-
|
177
|
-
private
|
178
|
-
|
179
|
-
def need_alt?(modifiers)
|
180
|
-
(modifiers & %i[alt alt_left alt_right]).size > 0
|
181
|
-
end
|
182
|
-
|
183
|
-
def need_control?(modifiers)
|
184
|
-
(modifiers & %i[control control_left control_rigth]).size > 0
|
185
|
-
end
|
186
|
-
|
187
|
-
def need_meta?(modifiers)
|
188
|
-
(modifiers & %i[meta meta_left meta_right]).size > 0
|
189
|
-
end
|
190
|
-
|
191
|
-
def need_shift?(modifiers)
|
192
|
-
(modifiers & %i[shift shift_left shift_right]).size > 0
|
193
|
-
end
|
194
|
-
|
195
|
-
def await(script)
|
196
|
-
@context.eval <<~JAVASCRIPT
|
197
|
-
(async () => {
|
198
|
-
try {
|
199
|
-
LastExecutionFinished = false;
|
200
|
-
LastResult = null;
|
201
|
-
LastErr = null;
|
202
|
-
#{script}
|
203
|
-
LastExecutionFinished = true;
|
204
|
-
} catch(err) {
|
205
|
-
LastResult = null;
|
206
|
-
LastErr = err;
|
207
|
-
LastExecutionFinished = true;
|
208
|
-
}
|
209
|
-
})()
|
210
|
-
JAVASCRIPT
|
211
|
-
await_result
|
212
|
-
end
|
213
|
-
|
214
|
-
def await_result
|
215
|
-
start_time = Time.now
|
216
|
-
while !execution_finished? && !timed_out?(start_time)
|
217
|
-
sleep 0.01
|
218
|
-
end
|
219
|
-
get_result
|
220
|
-
end
|
221
|
-
|
222
|
-
def determine_error(message)
|
223
|
-
if message.include?('Error: certificate has expired')
|
224
|
-
Isomorfeus::Puppetmaster::CertificateError.new(message) unless @ignore_https_errors
|
225
|
-
elsif message.include?('Error: getaddrinfo')
|
226
|
-
Isomorfeus::Puppetmaster::DNSError.new(message)
|
227
|
-
elsif message.include?('Unknown key: ')
|
228
|
-
Isomorfeus::Puppetmaster::KeyError.new(message)
|
229
|
-
elsif message.include?('Execution context was destroyed, most likely because of a navigation.')
|
230
|
-
Isomorfeus::Puppetmaster::ExecutionContextError.new(message)
|
231
|
-
elsif message.include?('Unable to find ')
|
232
|
-
Isomorfeus::Puppetmaster::ElementNotFound.new(message)
|
233
|
-
elsif (message.include?('SyntaxError:') && (message.include?('unknown pseudo-class selector') || message.include?('is not a valid selector'))) || message.include?('invalid xpath query')
|
234
|
-
Isomorfeus::Puppetmaster::DOMException.new(message)
|
235
|
-
else
|
236
|
-
Isomorfeus::Puppetmaster::JavaScriptError.new(message)
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
def execution_finished?
|
241
|
-
@context.eval 'LastExecutionFinished'
|
242
|
-
end
|
243
|
-
|
244
|
-
def get_result
|
245
|
-
res, err_msg = @context.eval 'GetLastResult()'
|
246
|
-
raise determine_error(err_msg) if err_msg
|
247
|
-
res
|
248
|
-
end
|
249
|
-
|
250
|
-
def jsdom_launch
|
251
|
-
<<~JAVASCRIPT
|
252
|
-
#{"const canvas = require('canvas');" if @canvas}
|
253
|
-
const jsdom = require('jsdom');
|
254
|
-
const Cookie = jsdom.toughCookie.Cookie;
|
255
|
-
const MemoryCookieStore = jsdom.toughCookie.MemoryCookieStore;
|
256
|
-
const { JSDOM } = jsdom;
|
257
|
-
|
258
|
-
const JSDOMOptions = {pretendToBeVisual: true, resources: 'usable', runScripts: 'dangerously'};
|
259
|
-
|
260
|
-
var LastResponse = null;
|
261
|
-
var LastResult = null;
|
262
|
-
var LastErr = null;
|
263
|
-
var LastExecutionFinished = false;
|
264
|
-
var LastHandleId = 0;
|
265
|
-
|
266
|
-
var AllDomHandles = {};
|
267
|
-
var AllElementHandles = {};
|
268
|
-
var AllConsoleHandles = {};
|
269
|
-
var ConsoleMessages = {};
|
270
|
-
|
271
|
-
var ModalText = null;
|
272
|
-
var ModalTextMatched = false;
|
273
|
-
|
274
|
-
const GetLastResult = function() {
|
275
|
-
if (LastExecutionFinished === true) {
|
276
|
-
var err = LastErr;
|
277
|
-
var res = LastResult;
|
278
|
-
|
279
|
-
LastErr = null;
|
280
|
-
LastRes = null;
|
281
|
-
LastExecutionFinished = false;
|
282
|
-
|
283
|
-
if (err) { return [null, err.toString() + "\\n" + err.stack]; }
|
284
|
-
else { return [res, null]; }
|
285
|
-
|
286
|
-
} else {
|
287
|
-
return [null, (new Error('Last command did not yet finish execution!')).message];
|
288
|
-
}
|
289
|
-
};
|
290
|
-
|
291
|
-
const DialogAcceptHandler = async (dialog) => {
|
292
|
-
var msg = dialog.message()
|
293
|
-
ModalTextMatched = (ModalText === msg);
|
294
|
-
ModalText = msg;
|
295
|
-
await dialog.accept();
|
296
|
-
}
|
297
|
-
|
298
|
-
const DialogDismissHandler = async (dialog) => {
|
299
|
-
var msg = dialog.message()
|
300
|
-
ModalTextMatched = (ModalText === msg);
|
301
|
-
ModalText = msg;
|
302
|
-
await dialog.dismiss();
|
303
|
-
}
|
304
|
-
|
305
|
-
const RegisterElementHandle = function(element_handle) {
|
306
|
-
var entries = Object.entries(AllElementHandles);
|
307
|
-
for(var i = 0; i < entries.length; i++) {
|
308
|
-
if (entries[i][1] === element_handle) { return entries[i][0]; }
|
309
|
-
}
|
310
|
-
LastHandleId++;
|
311
|
-
AllElementHandles[LastHandleId] = element_handle;
|
312
|
-
return LastHandleId;
|
313
|
-
};
|
314
|
-
|
315
|
-
const RegisterElementHandleArray = function(element_handle_array) {
|
316
|
-
var registered_handles = [];
|
317
|
-
element_handle_array.forEach(function(handle){
|
318
|
-
registered_handles.push(RegisterElementHandle(handle));
|
319
|
-
});
|
320
|
-
return registered_handles;
|
321
|
-
};
|
322
|
-
|
323
|
-
const RegisterCon = function(con) {
|
324
|
-
var entries = Object.entries(ConsoleMessages);
|
325
|
-
for(var i = 0; i < entries.length; i++) {
|
326
|
-
if (entries[i][1] === con) { return entries[i][0]; }
|
327
|
-
}
|
328
|
-
LastHandleId++;
|
329
|
-
AllConsoleHandles[LastHandleId] = con;
|
330
|
-
ConsoleMessages[LastHandleId] = [];
|
331
|
-
return LastHandleId;
|
332
|
-
};
|
333
|
-
const RegisterDom = function(dom, handle_id) {
|
334
|
-
var entries = Object.entries(AllDomHandles);
|
335
|
-
for(var i = 0; i < entries.length; i++) {
|
336
|
-
if (entries[i][1] === dom) { return entries[i][0]; }
|
337
|
-
}
|
338
|
-
AllDomHandles[handle_id] = dom;
|
339
|
-
return handle_id;
|
340
|
-
};
|
341
|
-
|
342
|
-
(async () => {
|
343
|
-
try {
|
344
|
-
var con = new jsdom.VirtualConsole();
|
345
|
-
var jar = new jsdom.CookieJar(new MemoryCookieStore(), {rejectPublicSuffixes: false, looseMode: true});
|
346
|
-
var handle_id = RegisterCon(con);
|
347
|
-
con.on('error', (msg) => { ConsoleMessages[handle_id].push({level: 'error', location: '', text: msg}); });
|
348
|
-
con.on('warn', (msg) => { ConsoleMessages[handle_id].push({level: 'warn', location: '', text: msg}); });
|
349
|
-
con.on('info', (msg) => { ConsoleMessages[handle_id].push({level: 'info', location: '', text: msg}); });
|
350
|
-
con.on('log', (msg) => { ConsoleMessages[handle_id].push({level: 'dir', location: '', text: msg}); });
|
351
|
-
con.on('debug', (msg) => { ConsoleMessages[handle_id].push({level: 'dir', location: '', text: msg}); });
|
352
|
-
var dom = new JSDOM('', Object.assign({}, JSDOMOptions, { virtualConsole: con }));
|
353
|
-
var browser = dom.window.navigator.userAgent;
|
354
|
-
LastResult = [RegisterDom(dom, handle_id), browser];
|
355
|
-
LastExecutionFinished = true;
|
356
|
-
} catch (err) {
|
357
|
-
LastErr = err;
|
358
|
-
LastExecutionFinished = true;
|
359
|
-
}
|
360
|
-
})();
|
361
|
-
JAVASCRIPT
|
362
|
-
end
|
363
|
-
|
364
|
-
def timed_out?(start_time)
|
365
|
-
if (Time.now - start_time) > @timeout
|
366
|
-
raise "Command Execution timed out!"
|
367
|
-
end
|
368
|
-
false
|
369
|
-
end
|
370
|
-
end
|
371
|
-
end
|
372
|
-
end
|
373
|
-
end
|