isomorfeus-puppetmaster 0.3.1 → 0.4.0

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.
@@ -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