isomorfeus-puppetmaster 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,917 +0,0 @@
1
- module Isomorfeus
2
- module Puppetmaster
3
- module Driver
4
- module JsdomDocument
5
- def document_accept_alert(document, **options, &block)
6
- raise Isomorfeus::Puppetmaster::NotSupported
7
- # TODO maybe wrap in mutex
8
- # text = options.has_key?(:text) ? "`#{options[:text]}`" : 'null'
9
- # @context.exec <<~JAVASCRIPT
10
- # ModalText = #{text};
11
- # AllDomHandles[#{document.handle}].on('dialog', DialogAcceptHandler);
12
- # JAVASCRIPT
13
- # block.call
14
- # sleep @reaction_timeout
15
- # @context.eval 'ModalText'
16
- # ensure
17
- # matched = await <<~JAVASCRIPT
18
- # LastResult = ModalTextMatched;
19
- # ModalTextMatched = false;
20
- # ModalText = null;
21
- # AllDomHandles[#{document.handle}].removeListener('dialog', DialogAcceptHandler);
22
- # JAVASCRIPT
23
- # raise Isomorfeus::Puppetmaster::NoModalError if options.has_key?(:text) && !matched
24
- end
25
-
26
- def document_accept_confirm(document, **options, &block)
27
- raise Isomorfeus::Puppetmaster::NotSupported
28
- # TODO maybe wrap in mutex
29
- # text = options.has_key?(:text) ? "`#{options[:text]}`" : 'null'
30
- # @context.exec <<~JAVASCRIPT
31
- # ModalText = #{text};
32
- # AllDomHandles[#{document.handle}].on('dialog', DialogAcceptHandler);
33
- # JAVASCRIPT
34
- # block.call
35
- # sleep @reaction_timeout
36
- # @context.eval 'ModalText'
37
- # ensure
38
- # matched = await <<~JAVASCRIPT
39
- # LastResult = ModalTextMatched;
40
- # ModalTextMatched = false;
41
- # ModalText = null;
42
- # AllDomHandles[#{document.handle}].removeListener('dialog', DialogAcceptHandler);
43
- # JAVASCRIPT
44
- # raise Isomorfeus::Puppetmaster::NoModalError if options.has_key?(:text) && !matched
45
- end
46
-
47
- def document_accept_leave_page(document, **options, &block)
48
- raise Isomorfeus::Puppetmaster::NotSupported
49
- # TODO maybe wrap in mutex
50
- # text = options.has_key?(:text) ? "`#{options[:text]}`" : 'null'
51
- # @context.exec <<~JAVASCRIPT
52
- # ModalText = #{text};
53
- # AllDomHandles[#{document.handle}].on('dialog', DialogAcceptHandler);
54
- # JAVASCRIPT
55
- # block.call
56
- # sleep @reaction_timeout
57
- # @context.eval 'ModalText'
58
- # ensure
59
- # matched = await <<~JAVASCRIPT
60
- # LastResult = ModalTextMatched;
61
- # ModalTextMatched = false;
62
- # ModalText = null;
63
- # AllDomHandles[#{document.handle}].removeListener('dialog', DialogAcceptHandler);
64
- # JAVASCRIPT
65
- # raise Isomorfeus::Puppetmaster::NoModalError if options.has_key?(:text) && !matched
66
- end
67
-
68
- def document_accept_prompt(document, **options, &block)
69
- raise Isomorfeus::Puppetmaster::NotSupported
70
- # # TODO maybe wrap in mutex
71
- # text = options.has_key?(:text) ? "`#{options[:text]}`" : 'null'
72
- # @context.exec <<~JAVASCRIPT
73
- # ModalText = #{text};
74
- # AllDomHandles[#{document.handle}].on('dialog', DialogAcceptHandler);
75
- # JAVASCRIPT
76
- # block.call
77
- # sleep @reaction_timeout
78
- # @context.eval 'ModalText'
79
- # ensure
80
- # matched = await <<~JAVASCRIPT
81
- # LastResult = ModalTextMatched;
82
- # ModalTextMatched = false;
83
- # ModalText = null;
84
- # AllDomHandles[#{document.handle}].removeListener('dialog', DialogAcceptHandler);
85
- # JAVASCRIPT
86
- # raise Isomorfeus::Puppetmaster::NoModalError if options.has_key?(:text) && !matched
87
- end
88
-
89
- def document_all_text(document)
90
- @context.eval "AllDomHandles[#{document.handle}].window.document.documentElement.textContent"
91
- end
92
-
93
- def document_body(document)
94
- node_data = @context.exec <<~JAVASCRIPT
95
- var node = AllDomHandles[#{document.handle}].window.document.body;
96
- var node_handle = RegisterElementHandle(node);
97
- var name = node.nodeName;
98
- var tag = node.tagName.toLowerCase();
99
- return {handle: node_handle, name: name, tag: tag, type: null, content_editable: node.isContentEditable};
100
- JAVASCRIPT
101
- if node_data
102
- node_data[:css_selector] = 'body'
103
- Isomorfeus::Puppetmaster::Node.new_by_tag(self, document, node_data)
104
- end
105
- end
106
-
107
- def document_bring_to_front(_document); end
108
-
109
- def document_clear_authentication_credentials(document)
110
- raise Isomorfeus::Puppetmaster::NotSupported
111
- end
112
-
113
- def document_clear_cookies(document)
114
- @context.exec "AllDomHandles[#{document.handle}].cookieJar.removeAllCookiesSync()"
115
- end
116
-
117
- def document_clear_extra_headers(document)
118
- raise Isomorfeus::Puppetmaster::NotSupported
119
- end
120
-
121
- def document_clear_url_blacklist(document)
122
- raise Isomorfeus::Puppetmaster::NotSupported
123
- end
124
-
125
- def document_click(document, x: nil, y: nil, modifiers: nil)
126
- # modifier_keys: :alt, :control, :meta, :shift
127
- # raise Isomorfeus::Pupppetmaster::InvalidActionError.new(:click) unless visible?
128
- modifiers = [modifiers] if modifiers.is_a?(Symbol)
129
- modifiers = [] unless modifiers
130
- modifiers = modifiers.map {|key| key.to_s.camelize(:lower) }
131
- @context.exec <<~JAVASCRIPT
132
- var options = {button: 0, bubbles: true, cancelable: true};
133
- var window = AllDomHandles[#{document.handle}].window;
134
- var modifiers = #{modifiers};
135
- if (modifiers.includes('meta')) { options['metaKey'] = true; }
136
- if (modifiers.includes('control')) { options['ctrlKey'] = true; }
137
- if (modifiers.includes('shift')) { options['shiftKey'] = true; }
138
- if (modifiers.includes('alt')) { options['altKey'] = true; }
139
- var x = #{x ? x : 'null'};
140
- var y = #{y ? y : 'null'};
141
- if (x && y) {
142
- options['clientX'] = x;
143
- options['clientY'] = y;
144
- }
145
- window.document.dispatchEvent(new window.MouseEvent('mousedown', options));
146
- window.document.dispatchEvent(new window.MouseEvent('mouseup', options));
147
- window.document.dispatchEvent(new window.MouseEvent('click', options));
148
- JAVASCRIPT
149
- end
150
-
151
- def document_close(document)
152
- await <<~JAVASCRIPT
153
- delete AllDomHandles[#{document.handle}];
154
- delete AllConsoleHandles[#{document.handle}];
155
- delete ConsoleMessages[#{document.handle}];
156
- JAVASCRIPT
157
- end
158
-
159
- def document_console(document)
160
- messages = @context.eval "ConsoleMessages[#{document.handle}]"
161
- messages.map {|m| Isomorfeus::Puppetmaster::ConsoleMessage.new(m)}
162
- end
163
-
164
- def document_cookies(document)
165
- uri = document_url(document)
166
- if uri == 'about:blank'
167
- uri = if Isomorfeus::Puppetmaster.server_host
168
- u = URI.new
169
- u.scheme = Isomorfeus::Puppetmaster.server_scheme if Isomorfeus::Puppetmaster.server_scheme
170
- u.host = Isomorfeus::Puppetmaster.server_host
171
- u.to_s
172
- else
173
- 'http://127.0.0.1'
174
- end
175
- end
176
- result = @context.eval "AllDomHandles[#{document.handle}].cookieJar.getCookiesSync('#{uri.to_s}')"
177
- result_hash = {}
178
- result.each do |cookie|
179
- cookie['name'] = cookie['key']
180
- cookie['expires'] = DateTime.parse(cookie['expires']).to_time if cookie.has_key?('expires')
181
- result_hash[cookie['name']] = Isomorfeus::Puppetmaster::Cookie.new(cookie)
182
- end
183
- result_hash
184
- end
185
-
186
- def document_dismiss_confirm(document, **options, &block)
187
- # TODO
188
- text = options.has_key?(:text) ? "`#{options[:text]}`" : 'null'
189
- @context.exec <<~JAVASCRIPT
190
- ModalText = #{text};
191
- AllDomHandles[#{document.handle}].on('dialog', DialogDismissHandler);
192
- JAVASCRIPT
193
- block.call
194
- sleep @reaction_timeout
195
- @context.eval 'ModalText'
196
- ensure
197
- matched = await <<~JAVASCRIPT
198
- LastResult = ModalTextMatched;
199
- ModalTextMatched = false;
200
- ModalText = null;
201
- AllDomHandles[#{document.handle}].removeListener('dialog', DialogDismissHandler);
202
- JAVASCRIPT
203
- raise Isomorfeus::Puppetmaster::ModalNotFound if options.has_key?(:text) && !matched
204
- end
205
-
206
- def document_dismiss_leave_page(document, **options, &block)
207
- # TODO
208
- text = options.has_key?(:text) ? "`#{options[:text]}`" : 'null'
209
- @context.exec <<~JAVASCRIPT
210
- ModalText = #{text};
211
- AllDomHandles[#{document.handle}].on('dialog', DialogDismissHandler);
212
- JAVASCRIPT
213
- block.call
214
- sleep @reaction_timeout
215
- @context.eval 'ModalText'
216
- ensure
217
- matched = await <<~JAVASCRIPT
218
- LastResult = ModalTextMatched;
219
- ModalTextMatched = false;
220
- ModalText = null;
221
- AllDomHandles[#{document.handle}].removeListener('dialog', DialogDismissHandler);
222
- JAVASCRIPT
223
- raise Isomorfeus::Puppetmaster::ModalNotFound if options.has_key?(:text) && !matched
224
- end
225
-
226
- def document_dismiss_prompt(document, **options, &block)
227
- # TODO
228
- text = options.has_key?(:text) ? "`#{options[:text]}`" : 'null'
229
- @context.exec <<~JAVASCRIPT
230
- ModalText = #{text};
231
- AllDomHandles[#{document.handle}].on('dialog', DialogDismissHandler);
232
- JAVASCRIPT
233
- block.call
234
- sleep @reaction_timeout
235
- @context.eval 'ModalText'
236
- ensure
237
- matched = await <<~JAVASCRIPT
238
- LastResult = ModalTextMatched;
239
- ModalTextMatched = false;
240
- ModalText = null;
241
- AllDomHandles[#{document.handle}].removeListener('dialog', DialogDismissHandler);
242
- JAVASCRIPT
243
- raise Isomorfeus::Puppetmaster::ModalNotFound if options.has_key?(:text) && !matched
244
- end
245
-
246
- def document_dispatch_event(document, name, event_type = nil, **options)
247
- raise ArgumentError, 'Unknown event' unless EVENTS.key?(name.to_sym) || event_type
248
- event_type, opts = *EVENTS[name.to_s.downcase.tr('_', '').to_sym] if event_type.nil?
249
- opts.merge!(options)
250
- final_options = options.map { |k,v| "#{k}: '#{v}'" }
251
- @context.exec <<~JAVASCRIPT
252
- var window = AllDomHandles[#{document.handle}].window;
253
- var event = new window.#{event_type}('#{name}', { #{final_options.join(', ')} });
254
- window.document.dispatchEvent(event);
255
- JAVASCRIPT
256
- end
257
-
258
- def document_double_click(document, x: nil, y: nil, modifiers: nil)
259
- # modifier_keys: :alt, :control, :meta, :shift
260
- modifiers = [modifiers] if modifiers.is_a?(Symbol)
261
- modifiers = [] unless modifiers
262
- modifiers = modifiers.map {|key| key.to_s.camelize(:lower) }
263
- await <<~JAVASCRIPT
264
- var options = {button: 0, bubbles: true, cancelable: true};
265
- var window = AllDomHandles[#{document.handle}].window;
266
- var modifiers = #{modifiers};
267
- if (modifiers.includes('meta')) { options['metaKey'] = true; }
268
- if (modifiers.includes('control')) { options['ctrlKey'] = true; }
269
- if (modifiers.includes('shift')) { options['shiftKey'] = true; }
270
- if (modifiers.includes('alt')) { options['altKey'] = true; }
271
- var x = #{x ? x : 'null'};
272
- var y = #{y ? y : 'null'};
273
- if (x && y) {
274
- options['clientX'] = x;
275
- options['clientY'] = y;
276
- }
277
- window.document.dispatchEvent(new window.MouseEvent('mousedown', options));
278
- window.document.dispatchEvent(new window.MouseEvent('mouseup', options));
279
- window.document.dispatchEvent(new window.MouseEvent('dblclick', options));
280
- JAVASCRIPT
281
- end
282
-
283
- def document_evaluate_script(document, script, *args)
284
- @context.eval <<~JAVASCRIPT
285
- AllDomHandles[#{document.handle}].window.eval(
286
- "var arguments = #{ "#{args}".gsub('"', '\"') };" +
287
- "#{script.strip.gsub('\\', '\\\\\\').gsub('"', '\"').gsub("\n", "\\n")}"
288
- )
289
- JAVASCRIPT
290
- rescue ExecJS::ProgramError => e
291
- raise determine_error(e.message)
292
- end
293
-
294
- def document_execute_script(document, script, *args)
295
- @context.eval <<~JAVASCRIPT
296
- AllDomHandles[#{document.handle}].window.eval(
297
- "(function() { var arguments = #{ "#{args}".gsub('"', '\"') };" +
298
- "#{script.strip.gsub('\\', '\\\\\\').gsub('"', '\"').gsub("\n", "\\n")}" +
299
- "})()"
300
- )
301
- JAVASCRIPT
302
- rescue ExecJS::ProgramError => e
303
- raise determine_error(e.message)
304
- end
305
-
306
- def document_find(document, selector)
307
- js_escaped_selector = selector.gsub('\\', '\\\\\\').gsub('"', '\"')
308
- node_data = @context.exec <<~JAVASCRIPT
309
- var node = AllDomHandles[#{document.handle}].window.document.querySelector("#{js_escaped_selector}");
310
- if (node) {
311
- var node_handle = RegisterElementHandle(node);
312
- var tag = node.tagName ? node.tagName.toLowerCase() : '';
313
- var name = node.nodeName;
314
- var type = null;
315
- if (tag === 'input') { type = node.getAttribute('type'); }
316
- return {handle: node_handle, name: name, tag: tag, type: type, content_editable: node.isContentEditable};
317
- }
318
- JAVASCRIPT
319
- if node_data
320
- node_data[:css_selector] = selector
321
- Isomorfeus::Puppetmaster::Node.new_by_tag(self, document, node_data)
322
- else
323
- raise Isomorfeus::Puppetmaster::ElementNotFound.new(selector)
324
- end
325
- rescue Exception => e
326
- raise determine_error(e.message)
327
- end
328
-
329
- def document_find_all(document, selector)
330
- js_escaped_selector = selector.gsub('\\', '\\\\\\').gsub('"', '\"')
331
- node_data_array = @context.exec <<~JAVASCRIPT
332
- var node_array = AllDomHandles[#{document.handle}].window.document.querySelectorAll("#{js_escaped_selector}");
333
- var node_data_array = [];
334
- if (node_array) {
335
- for (var i=0; i<node_array.length; i++) {
336
- var node = node_array[i];
337
- var node_handle = RegisterElementHandle(node_array[i]);
338
- var tag = node.tagName ? node.tagName.toLowerCase() : '';
339
- var name = node.nodeName;
340
- var type = null;
341
- if (tag === 'input') { type = node.getAttribute('type'); }
342
- node_data_array.push({handle: node_handle, name: name, tag: tag, type: type, content_editable: node.isContentEditable});
343
- }
344
- }
345
- return node_data_array;
346
- JAVASCRIPT
347
- node_data_array.map do |node_data|
348
- node_data[:css_selector] = selector
349
- Isomorfeus::Puppetmaster::Node.new_by_tag(self, document, node_data)
350
- end
351
- end
352
-
353
- def document_find_all_xpath(document, query)
354
- js_escaped_query = query.gsub('\\', '\\\\\\').gsub('"', '\"')
355
- node_data_array = @context.exec <<~JAVASCRIPT
356
- var window = AllDomHandles[#{document.handle}].window;
357
- var document = window.document;
358
- var xpath_result = document.evaluate("#{js_escaped_query}", document, null, window.XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
359
- var node;
360
- var node_data_array = [];
361
- while (node = xpath_result.iterateNext()) {
362
- var node_handle = RegisterElementHandle(node);
363
- var tag = node.tagName ? node.tagName.toLowerCase() : '';
364
- var name = node.nodeName;
365
- var type = null;
366
- if (tag === 'input') { type = node.getAttribute('type'); }
367
- node_data_array.push({handle: node_handle, name: name, tag: tag, type: type, content_editable: node.isContentEditable});
368
- }
369
- return node_data_array;
370
- JAVASCRIPT
371
- node_data_array.map do |node_data|
372
- node_data[:xpath_query] = query
373
- Isomorfeus::Puppetmaster::Node.new_by_tag(self, document, node_data)
374
- end
375
- end
376
-
377
- def document_find_xpath(document, query)
378
- js_escaped_query = query.gsub('\\', '\\\\\\').gsub('"', '\"')
379
- node_data = @context.exec <<~JAVASCRIPT
380
- var window = AllDomHandles[#{document.handle}].window;
381
- var document = window.document;
382
- var xpath_result = document.evaluate("#{js_escaped_query}", document, null, window.XPathResult.FIRST_ORDERED_NODE_TYPE, null);
383
- var node = xpath_result.singleNodeValue;
384
- if (node) {
385
- var node_handle = RegisterElementHandle(node);
386
- var tag = node.tagName ? node.tagName.toLowerCase() : '';
387
- var name = node.nodeName;
388
- var type = null;
389
- if (tag === 'input') { type = node.getAttribute('type'); }
390
- return {handle: node_handle, name: name, tag: tag, type: type, content_editable: node.isContentEditable};
391
- }
392
- JAVASCRIPT
393
- if node_data
394
- node_data[:xpath_query] = query
395
- Isomorfeus::Puppetmaster::Node.new_by_tag(self, document, node_data)
396
- else
397
- raise Isomorfeus::Puppetmaster::ElementNotFound.new(query)
398
- end
399
- rescue ExecJS::ProgramError => e
400
- raise determine_error('invalid xpath query')
401
- end
402
-
403
- def document_go_back(document)
404
- raise 'Browser history not supported.'
405
- @context.eval "AllDomHandles[#{document.handle}].window.history.back()"
406
- end
407
-
408
- def document_go_forward(document)
409
- raise 'Browser history not supported.'
410
- @context.eval "AllDomHandles[#{document.handle}].window.history.forward()"
411
- end
412
-
413
- def document_goto(document, uri)
414
- parsed_uri = URI.parse(uri)
415
- parsed_uri.host = @app.host unless parsed_uri.host
416
- parsed_uri.port = @app.port unless parsed_uri.port
417
- parsed_uri.scheme = @app.scheme unless parsed_uri.scheme
418
- response_hash, messages = await <<~JAVASCRIPT
419
- ConsoleMessages[#{document.handle}] = [];
420
- var cookie_jar = AllDomHandles[#{document.handle}].cookieJar.cloneSync(new MemoryCookieStore());
421
- cookie_jar.rejectPublicSuffixes = false;
422
- var con = new jsdom.VirtualConsole()
423
- con.on('error', (msg) => { ConsoleMessages[#{document.handle}].push({level: 'error', location: '', text: msg}); });
424
- con.on('warn', (msg) => { ConsoleMessages[#{document.handle}].push({level: 'warn', location: '', text: msg}); });
425
- con.on('info', (msg) => { ConsoleMessages[#{document.handle}].push({level: 'info', location: '', text: msg}); });
426
- con.on('log', (msg) => { ConsoleMessages[#{document.handle}].push({level: 'dir', location: '', text: msg}); });
427
- con.on('debug', (msg) => { ConsoleMessages[#{document.handle}].push({level: 'dir', location: '', text: msg}); });
428
- AllConsoleHandles[#{document.handle}] = con;
429
- try {
430
- var new_dom = await JSDOM.fromURL('#{parsed_uri.to_s}', Object.assign({}, JSDOMOptions, { cookieJar: cookie_jar, virtualConsole: con }));
431
- AllDomHandles[#{document.handle}] = new_dom;
432
- var formatted_response = {
433
- headers: {},
434
- ok: true,
435
- remote_address: '#{parsed_uri.to_s}',
436
- request: {},
437
- status: 200,
438
- status_text: '',
439
- text: '',
440
- url: '#{parsed_uri.to_s}'
441
- };
442
- LastResult = [formatted_response, ConsoleMessages[#{document.handle}]];
443
- } catch (err) {
444
- var formatted_error_response = {
445
- headers: err.options.headers,
446
- ok: false,
447
- remote_address: '#{parsed_uri.to_s}',
448
- request: {},
449
- status: err.statusCode ? err.statusCode : 500,
450
- status_text: err.response ? err.response.statusMessage : '',
451
- text: err.message ? err.message : '',
452
- url: '#{parsed_uri.to_s}'
453
- };
454
- LastResult = [formatted_error_response, ConsoleMessages[#{document.handle}]];
455
- }
456
- JAVASCRIPT
457
- con_messages = messages.map {|m| Isomorfeus::Puppetmaster::ConsoleMessage.new(m)}
458
- # STDERR.puts 'M', con_messages
459
- # STDERR.puts 'R', response_hash
460
- con_messages.each { |m| raise determine_error(m.text) if m.level == 'error' && !m.text.start_with?('Failed to load resource:') }
461
- if response_hash
462
- response = Isomorfeus::Puppetmaster::Response.new(response_hash)
463
- if response.status == 500 && response.text.start_with?('Error:')
464
- error = determine_error(response.text)
465
- raise error if error
466
- end
467
- document.instance_variable_set(:@response, response)
468
- end
469
- document.response
470
- end
471
-
472
- def document_head(document)
473
- node_data = @context.exec <<~JAVASCRIPT
474
- var node = AllDomHandles[#{document.handle}].window.document.head;
475
- var node_handle = RegisterElementHandle(node);
476
- var name = node.nodeName;
477
- var tag = node.tagName.toLowerCase();
478
- return {handle: node_handle, name: name, tag: tag, type: null, content_editable: node.isContentEditable};
479
- JAVASCRIPT
480
- if node_data
481
- node_data[:css_selector] = 'body'
482
- Isomorfeus::Puppetmaster::Node.new_by_tag(self, document, node_data)
483
- end
484
- end
485
-
486
- def document_html(document)
487
- @context.eval "AllDomHandles[#{document.handle}].serialize()"
488
- end
489
-
490
- def document_open_new_document(_document, uri = nil)
491
- if !uri || uri == 'about:blank'
492
- parsed_uri = 'about:blank'
493
- else
494
- parsed_uri = URI.parse(uri)
495
- parsed_uri.host = @app.host unless parsed_uri.host
496
- parsed_uri.port = @app.port unless parsed_uri.port
497
- parsed_uri.scheme = @app.scheme unless parsed_uri.scheme
498
- end
499
- handle, response_hash, messages = await <<~JAVASCRIPT
500
- var con = new jsdom.VirtualConsole();
501
- var jar = new jsdom.CookieJar(new MemoryCookieStore(), {rejectPublicSuffixes: false, looseMode: true});
502
- var handle_id = RegisterCon(con);
503
- con.on('error', (msg) => { ConsoleMessages[handle_id].push({level: 'error', location: '', text: msg}); });
504
- con.on('warn', (msg) => { ConsoleMessages[handle_id].push({level: 'warn', location: '', text: msg}); });
505
- con.on('info', (msg) => { ConsoleMessages[handle_id].push({level: 'info', location: '', text: msg}); });
506
- con.on('log', (msg) => { ConsoleMessages[handle_id].push({level: 'dir', location: '', text: msg}); });
507
- con.on('debug', (msg) => { ConsoleMessages[handle_id].push({level: 'dir', location: '', text: msg}); });
508
- try {
509
- var new_dom;
510
- var uri = '#{parsed_uri.to_s}';
511
- if (uri === 'about:blank') {
512
- new_dom = new JSDOM('', Object.assign({}, JSDOMOptions, { cookieJar: jar, virtualConsole: con }));
513
- } else {
514
- new_dom = await JSDOM.fromURL(uri, Object.assign({}, JSDOMOptions, { cookieJar: jar, virtualConsole: con }));
515
- }
516
- AllDomHandles[handle_id] = new_dom;
517
- var formatted_response = {
518
- headers: {},
519
- ok: false,
520
- remote_address: '#{parsed_uri.to_s}',
521
- request: {},
522
- status: 200,
523
- status_text: '',
524
- text: '',
525
- url: '#{parsed_uri.to_s}'
526
- };
527
- LastResult = [handle_id, formatted_response, ConsoleMessages[handle_id]];
528
- } catch (err) {
529
- var formatted_response = {
530
- headers: err.options.headers,
531
- ok: true,
532
- remote_address: '#{parsed_uri.to_s}',
533
- request: {},
534
- status: err.statusCode,
535
- status_text: err.response ? err.response.statusMessage : '',
536
- text: '',
537
- url: '#{parsed_uri.to_s}'
538
- };
539
- LastResult = [handle_id, formatted_response, ConsoleMessages[handle_id]];
540
- }
541
- JAVASCRIPT
542
- # STDERR.puts 'R', response_hash
543
- # STDERR.puts 'C', messages
544
- con_messages = messages.map {|m| Isomorfeus::Puppetmaster::ConsoleMessage.new(m)}
545
- con_messages.each { |m| raise determine_error(m.text) if m.level == 'error' && !m.text.start_with?('Failed to load resource:') }
546
- response = Isomorfeus::Puppetmaster::Response.new(response_hash)
547
- if response.status == 500 && response.text.start_with?('Error:')
548
- error = determine_error(response.text)
549
- raise error if error
550
- end
551
- Isomorfeus::Puppetmaster::Document.new(self, handle, response)
552
- end
553
-
554
- def document_reload(document)
555
- document_goto(document, document_url(document))
556
- end
557
-
558
- def document_remove_cookie(document, name)
559
- uri = document_url(document)
560
- if uri == 'about:blank'
561
- uri = if Isomorfeus::Puppetmaster.server_host
562
- u = URI.new
563
- u.scheme = Isomorfeus::Puppetmaster.server_scheme if Isomorfeus::Puppetmaster.server_scheme
564
- u.host = Isomorfeus::Puppetmaster.server_host
565
- u.to_s
566
- else
567
- 'http://127.0.0.1'
568
- end
569
- end
570
- domain = URI.parse(uri).host
571
- await <<~JAVASCRIPT
572
- var cookies = AllDomHandles[#{document.handle}].cookieJar.getCookiesSync('#{uri.to_s}')
573
- var path = '/';
574
- for(i=0; i<cookies.length; i++) {
575
- if (cookies[i].key === '#{name}' && cookies[i].domain === '#{domain}') {
576
- var path = cookies[i].path;
577
- break;
578
- }
579
- }
580
- var promise = new Promise(function(resolve, reject) {
581
- AllDomHandles[#{document.handle}].cookieJar.store.removeCookie('#{domain}', path, '#{name}', function(err){ resolve(true); });
582
- })
583
- await promise;
584
- JAVASCRIPT
585
- end
586
-
587
- def document_render_base64(document, **options)
588
- raise Isomorfeus::Puppetmaster::NotSupported
589
- end
590
-
591
- def document_reset_user_agent(document)
592
- raise Isomorfeus::Puppetmaster::NotSupported
593
- end
594
-
595
- def document_right_click(document, x: nil, y: nil, modifiers: nil)
596
- # modifier_keys: :alt, :control, :meta, :shift
597
- modifiers = [modifiers] if modifiers.is_a?(Symbol)
598
- modifiers = [] unless modifiers
599
- modifiers = modifiers.map {|key| key.to_s.camelize(:lower) }
600
- await <<~JAVASCRIPT
601
- var options = {button: 2, bubbles: true, cancelable: true};
602
- var window = AllDomHandles[#{document.handle}].window;
603
- var modifiers = #{modifiers};
604
- if (modifiers.includes('meta')) { options['metaKey'] = true; }
605
- if (modifiers.includes('control')) { options['ctrlKey'] = true; }
606
- if (modifiers.includes('shift')) { options['shiftKey'] = true; }
607
- if (modifiers.includes('alt')) { options['altKey'] = true; }
608
- var x = #{x ? x : 'null'};
609
- var y = #{y ? y : 'null'};
610
- if (x && y) {
611
- options['clientX'] = x;
612
- options['clientY'] = y;
613
- }
614
- window.document.dispatchEvent(new window.MouseEvent('mousedown', options));
615
- window.document.dispatchEvent(new window.MouseEvent('mouseup', options));
616
- window.document.dispatchEvent(new window.MouseEvent('contextmenu', options));
617
- JAVASCRIPT
618
- end
619
-
620
- def document_save_pdf(document, **options)
621
- raise Isomorfeus::Puppetmaster::NotSupported
622
- end
623
-
624
- def document_save_screenshot(document, file, **options)
625
- raise Isomorfeus::Puppetmaster::NotSupported
626
- end
627
-
628
- def document_scroll_by(document, x, y)
629
- @context.exec <<~JAVASCRIPT
630
- AllDomHandles[#{document.handle}].window.scrollX = AllDomHandles[#{document.handle}].window.scrollX + #{x};
631
- AllDomHandles[#{document.handle}].window.scrollY = AllDomHandles[#{document.handle}].window.scrollY + #{y};
632
- JAVASCRIPT
633
- end
634
-
635
- def document_scroll_to(document, x, y)
636
- @context.exec <<~JAVASCRIPT
637
- AllDomHandles[#{document.handle}].window.scrollX = #{x};
638
- AllDomHandles[#{document.handle}].window.scrollY = #{y};
639
- JAVASCRIPT
640
- end
641
-
642
- def document_set_authentication_credentials(document, username, password)
643
- raise Isomorfeus::Puppetmaster::NotSupported
644
- end
645
-
646
- def document_set_cookie(document, name, value, **options)
647
- options[:key] ||= name
648
- options[:value] ||= value
649
- uri = document_url(document)
650
- if uri == 'about:blank'
651
- uri = if Isomorfeus::Puppetmaster.server_host
652
- u = URI.new
653
- u.scheme = Isomorfeus::Puppetmaster.server_scheme if Isomorfeus::Puppetmaster.server_scheme
654
- u.host = Isomorfeus::Puppetmaster.server_host
655
- u.to_s
656
- else
657
- 'http://127.0.0.1'
658
- end
659
- end
660
- options[:domain] ||= URI.parse(uri).host
661
- final_options = []
662
- final_options << "expires: new Date('#{options.delete(:expires).to_s}')" if options.has_key?(:expires)
663
- final_options << "httpOnly: #{options.delete(:http_only)}" if options.has_key?(:http_only)
664
- final_options << "secure: #{options.delete(:secure)}" if options.has_key?(:secure)
665
- final_options << "sameSite: '#{options.delete(:same_site)}'" if options.has_key?(:same_site)
666
- options.each do |k,v|
667
- final_options << "#{k}: '#{v}'"
668
- end
669
- @context.exec "AllDomHandles[#{document.handle}].cookieJar.setCookieSync(new Cookie({#{final_options.join(', ')}}), '#{uri.to_s}', {ignoreError: true})"
670
- end
671
-
672
- def document_set_extra_headers(document, headers_hash)
673
- raise Isomorfeus::Puppetmaster::NotSupported
674
- end
675
-
676
- def document_set_user_agent(document, agent_string)
677
- raise Isomorfeus::Puppetmaster::NotSupported
678
- end
679
-
680
- def document_title(document)
681
- @context.eval "AllDomHandles[#{document.handle}].window.document.title"
682
- end
683
-
684
- def document_type_keys(document, *keys)
685
- cjs = <<~JAVASCRIPT
686
- var window = AllDomHandles[#{document.handle}].window;
687
- var events = [];
688
- var options = {bubbles: true, cancelable: true};
689
- JAVASCRIPT
690
- top_modifiers = []
691
- keys.each do |key|
692
- if key.is_a?(String)
693
- key.each_char do |c|
694
- shift = !! /[[:upper:]]/.match(c)
695
- cjs << <<~JAVASCRIPT
696
- events.push(new window.KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: '#{c}'.charCodeAt(0), char: '#{c}',
697
- altKey: #{need_alt?(top_modifiers)}, ctrlKey: #{need_control?(top_modifiers)}, metaKey: #{need_meta?(top_modifiers)},
698
- shiftKey: #{shift || need_shift?(top_modifiers)}}));
699
- JAVASCRIPT
700
- cjs << <<~JAVASCRIPT
701
- events.push(new window.KeyboardEvent('keypress', { bubbles: true, cancelable: true, key: '#{c}'.charCodeAt(0), char: '#{c}',
702
- altKey: #{need_alt?(top_modifiers)}, ctrlKey: #{need_control?(top_modifiers)}, metaKey: #{need_meta?(top_modifiers)},
703
- shiftKey: #{shift || need_shift?(top_modifiers)}}));
704
- JAVASCRIPT
705
- cjs << <<~JAVASCRIPT
706
- events.push(new window.KeyboardEvent('keyup', { bubbles: true, cancelable: true, key: '#{c}'.charCodeAt(0), char: '#{c}',
707
- altKey: #{need_alt?(top_modifiers)}, ctrlKey: #{need_control?(top_modifiers)}, metaKey: #{need_meta?(top_modifiers)},
708
- shiftKey: #{shift || need_shift?(top_modifiers)}}));
709
- JAVASCRIPT
710
- end
711
- elsif key.is_a?(Symbol)
712
- if %i[ctrl Ctrl].include?(key)
713
- key = :control
714
- elsif %i[command Command Meta].include?(key)
715
- key = :meta
716
- elsif %i[divide Divide].include?(key)
717
- key = :numpad_divide
718
- elsif %i[decimal Decimal].include?(key)
719
- key = :numpad_decimal
720
- elsif %i[left right up down].include?(key)
721
- key = "arrow_#{key}".to_sym
722
- end
723
- if %i[alt alt_left alt_right control control_left control_rigth meta meta_left meta_right shift shift_left shift_right].include?(key)
724
- top_modifiers << key
725
- cjs << <<~JAVASCRIPT
726
- events.push(new window.KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: '#{key.to_s.camelize}', code: '#{key.to_s.camelize}',
727
- altKey: #{need_alt?(top_modifiers)}, ctrlKey: #{need_control?(top_modifiers)}, metaKey: #{need_meta?(top_modifiers)},
728
- shiftKey: #{need_shift?(top_modifiers)}}));
729
- JAVASCRIPT
730
- else
731
- cjs << <<~JAVASCRIPT
732
- events.push(new window.KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: '#{key.to_s.camelize}', code: '#{key.to_s.camelize}',
733
- altKey: #{need_alt?(top_modifiers)}, ctrlKey: #{need_control?(top_modifiers)}, metaKey: #{need_meta?(top_modifiers)},
734
- shiftKey: #{need_shift?(top_modifiers)}}));
735
- JAVASCRIPT
736
- cjs << <<~JAVASCRIPT
737
- events.push(new window.KeyboardEvent('keypress', { bubbles: true, cancelable: true, key: '#{key.to_s.camelize}', code: '#{key.to_s.camelize}',
738
- altKey: #{need_alt?(top_modifiers)}, ctrlKey: #{need_control?(top_modifiers)}, metaKey: #{need_meta?(top_modifiers)},
739
- shiftKey: #{need_shift?(top_modifiers)}}));
740
- JAVASCRIPT
741
- cjs << <<~JAVASCRIPT
742
- events.push(new window.KeyboardEvent('keyup', { bubbles: true, cancelable: true, key: '#{key.to_s.camelize}', code: '#{key.to_s.camelize}',
743
- altKey: #{need_alt?(top_modifiers)}, ctrlKey: #{need_control?(top_modifiers)}, metaKey: #{need_meta?(top_modifiers)},
744
- shiftKey: #{need_shift?(top_modifiers)}}));
745
- JAVASCRIPT
746
- end
747
- elsif key.is_a?(Array)
748
- modifiers = []
749
- key.each do |k|
750
- if k.is_a?(Symbol)
751
- if %i[ctrl Ctrl].include?(k)
752
- k = :control
753
- elsif %i[command Command Meta].include?(k)
754
- k = :meta
755
- elsif %i[divide Divide].include?(k)
756
- k = :numpad_divide
757
- elsif %i[decimal Decimal].include?(k)
758
- k = :numpad_decimal
759
- elsif %i[left right up down].include?(key)
760
- k = "arrow_#{key}".to_sym
761
- end
762
- if %i[alt alt_left alt_right control control_left control_rigth meta meta_left meta_right shift shift_left shift_right].include?(k)
763
- modifiers << k
764
- cjs << <<~JAVASCRIPT
765
- events.push(new window.KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: '#{k.to_s.camelize}', code: '#{k.to_s.camelize}',
766
- altKey: #{need_alt?(modifiers)}, ctrlKey: #{need_control?(modifiers)}, metaKey: #{need_meta?(modifiers)},
767
- shiftKey: #{need_shift?(modifiers)}}));
768
- JAVASCRIPT
769
- else
770
- cjs << <<~JAVASCRIPT
771
- events.push(new window.KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: '#{k.to_s.camelize}', code: '#{k.to_s.camelize}',
772
- altKey: #{need_alt?(modifiers)}, ctrlKey: #{need_control?(modifiers)}, metaKey: #{need_meta?(modifiers)},
773
- shiftKey: #{need_shift?(modifiers)}}));
774
- JAVASCRIPT
775
- cjs << <<~JAVASCRIPT
776
- events.push(new window.KeyboardEvent('keypress', { bubbles: true, cancelable: true, key: '#{k.to_s.camelize}', code: '#{k.to_s.camelize}',
777
- altKey: #{need_alt?(modifiers)}, ctrlKey: #{need_control?(modifiers)}, metaKey: #{need_meta?(modifiers)},
778
- shiftKey: #{need_shift?(modifiers)}}));
779
- JAVASCRIPT
780
- cjs << <<~JAVASCRIPT
781
- events.push(new window.KeyboardEvent('keyup', { bubbles: true, cancelable: true, key: '#{k.to_s.camelize}', code: '#{k.to_s.camelize}',
782
- altKey: #{need_alt?(modifiers)}, ctrlKey: #{need_control?(modifiers)}, metaKey: #{need_meta?(modifiers)},
783
- shiftKey: #{need_shift?(modifiers)}}));
784
- JAVASCRIPT
785
- end
786
- elsif k.is_a?(String)
787
- k.each_char do |c|
788
- shift = !! /[[:upper:]]/.match(c)
789
- cjs << <<~JAVASCRIPT
790
- events.push(new window.KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: '#{c}'.charCodeAt(0), char: '#{c}',
791
- altKey: #{need_alt?(modifiers)}, ctrlKey: #{need_control?(modifiers)}, metaKey: #{need_meta?(modifiers)},
792
- shiftKey: #{shift || need_shift?(modifiers)}}));
793
- JAVASCRIPT
794
- cjs << <<~JAVASCRIPT
795
- events.push(new window.KeyboardEvent('keypress', { bubbles: true, cancelable: true, key: '#{c}'.charCodeAt(0), char: '#{c}',
796
- altKey: #{need_alt?(modifiers)}, ctrlKey: #{need_control?(modifiers)}, metaKey: #{need_meta?(modifiers)},
797
- shiftKey: #{shift || need_shift?(modifiers)}}));
798
- JAVASCRIPT
799
- cjs << <<~JAVASCRIPT
800
- events.push(new window.KeyboardEvent('keyup', { bubbles: true, cancelable: true, key: '#{c}'.charCodeAt(0), char: '#{c}',
801
- altKey: #{need_alt?(modifiers)}, ctrlKey: #{need_control?(modifiers)}, metaKey: #{need_meta?(modifiers)},
802
- shiftKey: #{shift || need_shift?(modifiers)}}));
803
- JAVASCRIPT
804
- end
805
- end
806
- end
807
- modifiers.reverse.each do |k|
808
- cjs << <<~JAVASCRIPT
809
- events.push(new window.KeyboardEvent('keyup', { bubbles: true, cancelable: true, key: '#{k.to_s.camelize}', code: '#{k.to_s.camelize}',
810
- altKey: #{need_alt?(modifiers)}, ctrlKey: #{need_control?(modifiers)}, metaKey: #{need_meta?(modifiers)},
811
- shiftKey: #{need_shift?(modifiers)}}));
812
- JAVASCRIPT
813
- end
814
- end
815
- end
816
- top_modifiers.reverse.each do |key|
817
- cjs << <<~JAVASCRIPT
818
- events.push(new window.KeyboardEvent('keyup', { bubbles: true, cancelable: true, key: '#{key.to_s.camelize}', code: '#{key.to_s.camelize}',
819
- altKey: #{need_alt?(top_modifiers)}, ctrlKey: #{need_control?(top_modifiers)}, metaKey: #{need_meta?(top_modifiers)},
820
- shiftKey: #{need_shift?(top_modifiers)}}));
821
- JAVASCRIPT
822
- end
823
- cjs << <<~JAVASCRIPT
824
- for (i=0; i<events.length; i++) {
825
- window.document.dispatchEvent(events[i]);
826
- }
827
- JAVASCRIPT
828
- @context.exec cjs
829
- end
830
-
831
- def document_url(document)
832
- @context.eval "AllDomHandles[#{document.handle}].window.location.href"
833
- end
834
-
835
- def document_user_agent(document)
836
- @context.eval "AllDomHandles[#{document.handle}].window.navigator.userAgent"
837
- end
838
-
839
- def document_viewport_maximize(document)
840
- document_viewport_resize(document, @max_width, @max_height)
841
- end
842
-
843
- def document_viewport_resize(document, width, height)
844
- width = @max_width if width > @max_width
845
- height = @max_height if width > @max_height
846
- @context.exec <<~JAVASCRIPT
847
- AllDomHandles[#{document.handle}].window.innerWidth = #{width};
848
- AllDomHandles[#{document.handle}].window.innerHeight = #{height};
849
- JAVASCRIPT
850
- end
851
-
852
- def document_viewport_size(document)
853
- @context.eval "[AllDomHandles[#{document.handle}].window.innerWidth, AllDomHandles[#{document.handle}].window.innerHeight]"
854
- end
855
-
856
- def document_wait_for(document, selector)
857
- js_escaped_selector = selector.gsub('\\', '\\\\\\').gsub('"', '\"')
858
- node_data = await <<~JAVASCRIPT
859
- var node = null;
860
- var start_time = new Date();
861
- var resolver = function(resolve) {
862
- node = AllDomHandles[#{document.handle}].window.document.querySelector("#{js_escaped_selector}");
863
- if (node) {
864
- var node_handle = RegisterElementHandle(node);
865
- var name = node.nodeName;
866
- var tag = node.tagName.toLowerCase();
867
- var type = null;
868
- if (tag === 'input') { type = node.getAttribute('type'); }
869
- LastResult = {handle: node_handle, name: name, tag: tag, type: type, content_editable: node.isContentEditable};
870
- resolve(true);
871
- }
872
- else if ((new Date() - start_time) > #{@jsdom_timeout}) { resolve(true); }
873
- else { setTimeout(resolver, #{@jsdom_reaction_timeout}, resolve) }
874
- };
875
- var promise = new Promise(function(resolve, reject){ resolver(resolve); });
876
- await promise;
877
- JAVASCRIPT
878
- if node_data
879
- node_data[:css_selector] = selector
880
- Isomorfeus::Puppetmaster::Node.new_by_tag(self, document, node_data)
881
- end
882
- end
883
-
884
- def document_wait_for_xpath(document, query)
885
- js_escaped_query = query.gsub('\\', '\\\\\\').gsub('"', '\"')
886
- node_data = await <<~JAVASCRIPT
887
- var node = null;
888
- var start_time = new Date();
889
- var resolver = function(resolve) {
890
- var window = AllDomHandles[#{document.handle}].window;
891
- var document = window.document;
892
- var xpath_result = document.evaluate("#{js_escaped_query}", document, null, window.XPathResult.FIRST_ORDERED_NODE_TYPE, null);
893
- node = xpath_result.singleNodeValue;
894
- if (node) {
895
- var node_handle = RegisterElementHandle(node);
896
- var name = node.nodeName;
897
- var tag = node.tagName.toLowerCase();
898
- var type = null;
899
- if (tag === 'input') { type = node.getAttribute('type'); }
900
- LastResult = {handle: node_handle, name: name, tag: tag, type: type, content_editable: node.isContentEditable};
901
- resolve(true);
902
- }
903
- else if ((new Date() - start_time) > #{@jsdom_timeout}) { resolve(true); }
904
- else { setTimeout(resolver, #{@jsdom_reaction_timeout}, resolve) }
905
- };
906
- var promise = new Promise(function(resolve, reject){ resolver(resolve); });
907
- await promise;
908
- JAVASCRIPT
909
- if node_data
910
- node_data[:xpath_query] = query
911
- Isomorfeus::Puppetmaster::Node.new_by_tag(self, document, node_data)
912
- end
913
- end
914
- end
915
- end
916
- end
917
- end