ferrum 0.14 → 0.15

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -25,6 +25,8 @@ going to crawl sites you better use Ferrum or
25
25
  * [Vessel](https://github.com/rubycdp/vessel) high-level web crawling framework
26
26
  based on Ferrum and Mechanize.
27
27
 
28
+ The development is done in [![RubyMine](https://resources.jetbrains.com/storage/products/company/brand/logos/RubyMine_icon.svg?width=10px)](https://jb.gg/ruby)
29
+ provided by [OSS license](https://jb.gg/OpenSourceSupport).
28
30
 
29
31
  ## Index
30
32
 
@@ -35,8 +37,8 @@ based on Ferrum and Mechanize.
35
37
  * [Navigation](https://github.com/rubycdp/ferrum#navigation)
36
38
  * [Finders](https://github.com/rubycdp/ferrum#finders)
37
39
  * [Screenshots](https://github.com/rubycdp/ferrum#screenshots)
38
- * [Cleaning Up](https://github.com/rubycdp/ferrum#cleaning-up)
39
40
  * [Network](https://github.com/rubycdp/ferrum#network)
41
+ * [Downloads](https://github.com/rubycdp/ferrum#downloads)
40
42
  * [Proxy](https://github.com/rubycdp/ferrum#proxy)
41
43
  * [Mouse](https://github.com/rubycdp/ferrum#mouse)
42
44
  * [Keyboard](https://github.com/rubycdp/ferrum#keyboard)
@@ -49,6 +51,7 @@ based on Ferrum and Mechanize.
49
51
  * [Animation](https://github.com/rubycdp/ferrum#animation)
50
52
  * [Node](https://github.com/rubycdp/ferrum#node)
51
53
  * [Tracing](https://github.com/rubycdp/ferrum#tracing)
54
+ * [Clean Up](https://github.com/rubycdp/ferrum#clean-up)
52
55
  * [Thread safety](https://github.com/rubycdp/ferrum#thread-safety)
53
56
  * [Development](https://github.com/rubycdp/ferrum#development)
54
57
  * [Contributing](https://github.com/rubycdp/ferrum#contributing)
@@ -61,7 +64,7 @@ There's no official Chrome or Chromium package for Linux don't install it this
61
64
  way because it's either outdated or unofficial, both are bad. Download it from
62
65
  official source for [Chrome](https://www.google.com/chrome/) or
63
66
  [Chromium](https://www.chromium.org/getting-involved/download-chromium).
64
- Chrome binary should be in the `PATH` or `BROWSER_PATH` or you can pass it as an
67
+ Chrome binary should be in the `PATH` or `BROWSER_PATH` and you can pass it as an
65
68
  option to browser instance see `:browser_path` in
66
69
  [Customization](https://github.com/rubycdp/ferrum#customization).
67
70
 
@@ -83,14 +86,17 @@ browser.screenshot(path: "google.png")
83
86
  browser.quit
84
87
  ```
85
88
 
86
- Interact with a page:
89
+ When you work with browser instance Ferrum creates and maintains a default page for you, in fact all the methods above
90
+ are sent to the `page` instance that is created in the `default_context` of the `browser` instance. You can interact
91
+ with a page created manually and this is preferred:
87
92
 
88
93
  ```ruby
89
94
  browser = Ferrum::Browser.new
90
- browser.go_to("https://google.com")
91
- input = browser.at_xpath("//input[@name='q']")
95
+ page = browser.create_page
96
+ page.go_to("https://google.com")
97
+ input = page.at_xpath("//input[@name='q']")
92
98
  input.focus.type("Ruby headless driver for Chrome", :Enter)
93
- browser.at_css("a > h3").text # => "rubycdp/ferrum: Ruby Chrome/Chromium driver - GitHub"
99
+ page.at_css("a > h3").text # => "rubycdp/ferrum: Ruby Chrome/Chromium driver - GitHub"
94
100
  browser.quit
95
101
  ```
96
102
 
@@ -98,8 +104,9 @@ Evaluate some JavaScript and get full width/height:
98
104
 
99
105
  ```ruby
100
106
  browser = Ferrum::Browser.new
101
- browser.go_to("https://www.google.com/search?q=Ruby+headless+driver+for+Capybara")
102
- width, height = browser.evaluate <<~JS
107
+ page = browser.create_page
108
+ page.go_to("https://www.google.com/search?q=Ruby+headless+driver+for+Capybara")
109
+ width, height = page.evaluate <<~JS
103
110
  [document.documentElement.offsetWidth,
104
111
  document.documentElement.offsetHeight]
105
112
  JS
@@ -112,8 +119,9 @@ Do any mouse movements you like:
112
119
  ```ruby
113
120
  # Trace a 100x100 square
114
121
  browser = Ferrum::Browser.new
115
- browser.go_to("https://google.com")
116
- browser.mouse
122
+ page = browser.create_page
123
+ page.go_to("https://google.com")
124
+ page.mouse
117
125
  .move(x: 0, y: 0)
118
126
  .down
119
127
  .move(x: 0, y: 100)
@@ -148,6 +156,7 @@ Ferrum::Browser.new(options)
148
156
  * `:headless` (String | Boolean) - Set browser as headless or not, `true` by default. You can set `"new"` to support
149
157
  [new headless mode](https://developer.chrome.com/articles/new-headless/).
150
158
  * `:xvfb` (Boolean) - Run browser in a virtual framebuffer, `false` by default.
159
+ * `:flatten` (Boolean) - Use one websocket connection to the browser and all the pages in flatten mode.
151
160
  * `:window_size` (Array) - The dimensions of the browser window in which to
152
161
  test, expressed as a 2-element array, e.g. [1024, 768]. Default: [1024, 768]
153
162
  * `:extensions` (Array[String | Hash]) - An array of paths to files or JS
@@ -178,6 +187,8 @@ Ferrum::Browser.new(options)
178
187
  * `:host` (String) - Remote debugging address for headless Chrome.
179
188
  * `:url` (String) - URL for a running instance of Chrome. If this is set, a
180
189
  browser process will not be spawned.
190
+ * `:ws_url` (String) - Websocket url for a running instance of Chrome. If this is set, a
191
+ browser process will not be spawned.
181
192
  * `:process_timeout` (Integer) - How long to wait for the Chrome process to
182
193
  respond on startup.
183
194
  * `:ws_max_receive_size` (Integer) - How big messages to accept from Chrome
@@ -198,7 +209,7 @@ Navigate page to.
198
209
  configuring driver.
199
210
 
200
211
  ```ruby
201
- browser.go_to("https://github.com/")
212
+ page.go_to("https://github.com/")
202
213
  ```
203
214
 
204
215
  #### back
@@ -206,9 +217,9 @@ browser.go_to("https://github.com/")
206
217
  Navigate to the previous page in history.
207
218
 
208
219
  ```ruby
209
- browser.go_to("https://github.com/")
210
- browser.at_xpath("//a").click
211
- browser.back
220
+ page.go_to("https://github.com/")
221
+ page.at_xpath("//a").click
222
+ page.back
212
223
  ```
213
224
 
214
225
  #### forward
@@ -216,10 +227,10 @@ browser.back
216
227
  Navigate to the next page in history.
217
228
 
218
229
  ```ruby
219
- browser.go_to("https://github.com/")
220
- browser.at_xpath("//a").click
221
- browser.back
222
- browser.forward
230
+ page.go_to("https://github.com/")
231
+ page.at_xpath("//a").click
232
+ page.back
233
+ page.forward
223
234
  ```
224
235
 
225
236
  #### refresh
@@ -227,8 +238,8 @@ browser.forward
227
238
  Reload current page.
228
239
 
229
240
  ```ruby
230
- browser.go_to("https://github.com/")
231
- browser.refresh
241
+ page.go_to("https://github.com/")
242
+ page.refresh
232
243
  ```
233
244
 
234
245
  #### stop
@@ -236,8 +247,8 @@ browser.refresh
236
247
  Stop all navigations and loading pending resources on the page
237
248
 
238
249
  ```ruby
239
- browser.go_to("https://github.com/")
240
- browser.stop
250
+ page.go_to("https://github.com/")
251
+ page.stop
241
252
  ```
242
253
 
243
254
  #### position = \*\*options
@@ -260,6 +271,37 @@ Get the position for the browser window
260
271
  browser.position # => [10, 20]
261
272
  ```
262
273
 
274
+ #### window_bounds = \*\*options
275
+
276
+ Set window bounds
277
+
278
+ * options `Hash`
279
+ * :left `Integer`
280
+ * :top `Integer`
281
+ * :width `Integer`
282
+ * :height `Integer`
283
+ * :window_state `String`
284
+
285
+ ```ruby
286
+ browser.window_bounds = { left: 10, top: 20, width: 1024, height: 768, window_state: "normal" }
287
+ ```
288
+
289
+ #### window_bounds : `Hash<String, Integer | String>`
290
+
291
+ Get window bounds
292
+
293
+ ```ruby
294
+ browser.window_bounds # => { "left": 0, "top": 1286, "width": 10, "height": 10, "windowState": "normal" }
295
+ ```
296
+
297
+ #### window_id : `Integer`
298
+
299
+ Current window id
300
+
301
+ ```ruby
302
+ browser.window_id # => 1
303
+ ```
304
+
263
305
  ## Finders
264
306
 
265
307
  #### at_css(selector, \*\*options) : `Node` | `nil`
@@ -272,8 +314,8 @@ provided node.
272
314
  * :within `Node` | `nil`
273
315
 
274
316
  ```ruby
275
- browser.go_to("https://github.com/")
276
- browser.at_css("a[aria-label='Issues you created']") # => Node
317
+ page.go_to("https://github.com/")
318
+ page.at_css("a[aria-label='Issues you created']") # => Node
277
319
  ```
278
320
 
279
321
 
@@ -287,8 +329,8 @@ document or provided node.
287
329
  * :within `Node` | `nil`
288
330
 
289
331
  ```ruby
290
- browser.go_to("https://github.com/")
291
- browser.css("a[aria-label='Issues you created']") # => [Node]
332
+ page.go_to("https://github.com/")
333
+ page.css("a[aria-label='Issues you created']") # => [Node]
292
334
  ```
293
335
 
294
336
  #### at_xpath(selector, \*\*options) : `Node` | `nil`
@@ -300,8 +342,8 @@ Find node by xpath.
300
342
  * :within `Node` | `nil`
301
343
 
302
344
  ```ruby
303
- browser.go_to("https://github.com/")
304
- browser.at_xpath("//a[@aria-label='Issues you created']") # => Node
345
+ page.go_to("https://github.com/")
346
+ page.at_xpath("//a[@aria-label='Issues you created']") # => Node
305
347
  ```
306
348
 
307
349
  #### xpath(selector, \*\*options) : `Array<Node>` | `[]`
@@ -313,8 +355,8 @@ Find nodes by xpath.
313
355
  * :within `Node` | `nil`
314
356
 
315
357
  ```ruby
316
- browser.go_to("https://github.com/")
317
- browser.xpath("//a[@aria-label='Issues you created']") # => [Node]
358
+ page.go_to("https://github.com/")
359
+ page.xpath("//a[@aria-label='Issues you created']") # => [Node]
318
360
  ```
319
361
 
320
362
  #### current_url : `String`
@@ -322,8 +364,8 @@ browser.xpath("//a[@aria-label='Issues you created']") # => [Node]
322
364
  Returns current top window location href.
323
365
 
324
366
  ```ruby
325
- browser.go_to("https://google.com/")
326
- browser.current_url # => "https://www.google.com/"
367
+ page.go_to("https://google.com/")
368
+ page.current_url # => "https://www.google.com/"
327
369
  ```
328
370
 
329
371
  #### current_title : `String`
@@ -331,8 +373,8 @@ browser.current_url # => "https://www.google.com/"
331
373
  Returns current top window title
332
374
 
333
375
  ```ruby
334
- browser.go_to("https://google.com/")
335
- browser.current_title # => "Google"
376
+ page.go_to("https://google.com/")
377
+ page.current_title # => "Google"
336
378
  ```
337
379
 
338
380
  #### body : `String`
@@ -340,8 +382,8 @@ browser.current_title # => "Google"
340
382
  Returns current page's html.
341
383
 
342
384
  ```ruby
343
- browser.go_to("https://google.com/")
344
- browser.body # => '<html itemscope="" itemtype="http://schema.org/WebPage" lang="ru"><head>...
385
+ page.go_to("https://google.com/")
386
+ page.body # => '<html itemscope="" itemtype="http://schema.org/WebPage" lang="ru"><head>...
345
387
  ```
346
388
 
347
389
 
@@ -359,20 +401,29 @@ Saves screenshot on a disk or returns it as base64.
359
401
  * :format `String` "jpeg" | "png"
360
402
  * :quality `Integer` 0-100 works for jpeg only
361
403
  * :full `Boolean` whether you need full page screenshot or a viewport
362
- * :selector `String` css selector for given element
404
+ * :selector `String` css selector for given element, optional
405
+ * :area `Hash` area for screenshot, optional
406
+ * :x `Integer`
407
+ * :y `Integer`
408
+ * :width `Integer`
409
+ * :height `Integer`
363
410
  * :scale `Float` zoom in/out
364
411
  * :background_color `Ferrum::RGBA.new(0, 0, 0, 0.0)` to have specific background color
365
412
 
366
413
  ```ruby
367
- browser.go_to("https://google.com/")
414
+ page.go_to("https://google.com/")
368
415
  # Save on the disk in PNG
369
- browser.screenshot(path: "google.png") # => 134660
416
+ page.screenshot(path: "google.png") # => 134660
370
417
  # Save on the disk in JPG
371
- browser.screenshot(path: "google.jpg") # => 30902
418
+ page.screenshot(path: "google.jpg") # => 30902
372
419
  # Save to Base64 the whole page not only viewport and reduce quality
373
- browser.screenshot(full: true, quality: 60) # "iVBORw0KGgoAAAANSUhEUgAABAAAAAMACAYAAAC6uhUNAAAAAXNSR0IArs4c6Q...
420
+ page.screenshot(full: true, quality: 60, encoding: :base64) # "iVBORw0KGgoAAAANSUhEUgAABAAAAAMACAYAAAC6uhUNAAAAAXNSR0IArs4c6Q...
421
+ # Save on the disk with the selected element in PNG
422
+ page.screenshot(path: "google.png", selector: 'textarea') # => 11340
423
+ # Save to Base64 with an area of the page in PNG
424
+ page.screenshot(path: "google.png", area: { x: 0, y: 0, width: 400, height: 300 }) # => 54239
374
425
  # Save with specific background color
375
- browser.screenshot(background_color: Ferrum::RGBA.new(0, 0, 0, 0.0))
426
+ page.screenshot(background_color: Ferrum::RGBA.new(0, 0, 0, 0.0))
376
427
  ```
377
428
 
378
429
  #### pdf(\*\*options) : `String` | `Boolean`
@@ -393,9 +444,9 @@ Saves PDF on a disk or returns it as base64.
393
444
  * See other [native options](https://chromedevtools.github.io/devtools-protocol/tot/Page#method-printToPDF) you can pass
394
445
 
395
446
  ```ruby
396
- browser.go_to("https://google.com/")
447
+ page.go_to("https://google.com/")
397
448
  # Save to disk as a PDF
398
- browser.pdf(path: "google.pdf", paper_width: 1.0, paper_height: 1.0) # => true
449
+ page.pdf(path: "google.pdf", paper_width: 1.0, paper_height: 1.0) # => true
399
450
  ```
400
451
 
401
452
  #### mhtml(\*\*options) : `String` | `Integer`
@@ -406,33 +457,14 @@ Saves MHTML on a disk or returns it as a string.
406
457
  * :path `String` to save a file on the disk.
407
458
 
408
459
  ```ruby
409
- browser.go_to("https://google.com/")
410
- browser.mhtml(path: "google.mhtml") # => 87742
411
- ```
412
-
413
-
414
- ## Cleaning Up
415
-
416
- #### reset
417
-
418
- Closes browser tabs opened by the `Browser` instance.
419
-
420
- ```ruby
421
- # connect to a long-running Chrome process
422
- browser = Ferrum::Browser.new(url: 'http://localhost:9222')
423
-
424
- browser.go_to("https://github.com/")
425
-
426
- # clean up, lest the tab stays there hanging forever
427
- browser.reset
428
-
429
- browser.quit
460
+ page.go_to("https://google.com/")
461
+ page.mhtml(path: "google.mhtml") # => 87742
430
462
  ```
431
463
 
432
464
 
433
465
  ## Network
434
466
 
435
- `browser.network`
467
+ `page.network`
436
468
 
437
469
  #### traffic `Array<Network::Exchange>`
438
470
 
@@ -440,8 +472,8 @@ Returns all information about network traffic as `Network::Exchange` instance
440
472
  which in general is a wrapper around `request`, `response` and `error`.
441
473
 
442
474
  ```ruby
443
- browser.go_to("https://github.com/")
444
- browser.network.traffic # => [#<Ferrum::Network::Exchange, ...]
475
+ page.go_to("https://github.com/")
476
+ page.network.traffic # => [#<Ferrum::Network::Exchange, ...]
445
477
  ```
446
478
 
447
479
  #### request : `Network::Request`
@@ -449,8 +481,8 @@ browser.network.traffic # => [#<Ferrum::Network::Exchange, ...]
449
481
  Page request of the main frame.
450
482
 
451
483
  ```ruby
452
- browser.go_to("https://github.com/")
453
- browser.network.request # => #<Ferrum::Network::Request...
484
+ page.go_to("https://github.com/")
485
+ page.network.request # => #<Ferrum::Network::Request...
454
486
  ```
455
487
 
456
488
  #### response : `Network::Response`
@@ -458,8 +490,8 @@ browser.network.request # => #<Ferrum::Network::Request...
458
490
  Page response of the main frame.
459
491
 
460
492
  ```ruby
461
- browser.go_to("https://github.com/")
462
- browser.network.response # => #<Ferrum::Network::Response...
493
+ page.go_to("https://github.com/")
494
+ page.network.response # => #<Ferrum::Network::Response...
463
495
  ```
464
496
 
465
497
  #### status : `Integer`
@@ -468,8 +500,8 @@ Contains the status code of the main page response (e.g., 200 for a
468
500
  success). This is just a shortcut for `response.status`.
469
501
 
470
502
  ```ruby
471
- browser.go_to("https://github.com/")
472
- browser.network.status # => 200
503
+ page.go_to("https://github.com/")
504
+ page.network.status # => 200
473
505
  ```
474
506
 
475
507
  #### wait_for_idle(\*\*options)
@@ -485,22 +517,22 @@ Waits for network idle or raises `Ferrum::TimeoutError` error
485
517
  by default
486
518
 
487
519
  ```ruby
488
- browser.go_to("https://example.com/")
489
- browser.at_xpath("//a[text() = 'No UI changes button']").click
490
- browser.network.wait_for_idle
520
+ page.go_to("https://example.com/")
521
+ page.at_xpath("//a[text() = 'No UI changes button']").click
522
+ page.network.wait_for_idle
491
523
  ```
492
524
 
493
525
  #### clear(type)
494
526
 
495
- Clear browser's cache or collected traffic.
527
+ Clear page's cache or collected traffic.
496
528
 
497
529
  * type `Symbol` it is either `:traffic` or `:cache`
498
530
 
499
531
  ```ruby
500
- traffic = browser.network.traffic # => []
501
- browser.go_to("https://github.com/")
532
+ traffic = page.network.traffic # => []
533
+ page.go_to("https://github.com/")
502
534
  traffic.size # => 51
503
- browser.network.clear(:traffic)
535
+ page.network.clear(:traffic)
504
536
  traffic.size # => 0
505
537
  ```
506
538
 
@@ -516,8 +548,9 @@ continue them.
516
548
 
517
549
  ```ruby
518
550
  browser = Ferrum::Browser.new
519
- browser.network.intercept
520
- browser.on(:request) do |request|
551
+ page = browser.create_page
552
+ page.network.intercept
553
+ page.on(:request) do |request|
521
554
  if request.match?(/bla-bla/)
522
555
  request.abort
523
556
  elsif request.match?(/lorem/)
@@ -526,7 +559,7 @@ browser.on(:request) do |request|
526
559
  request.continue
527
560
  end
528
561
  end
529
- browser.go_to("https://google.com")
562
+ page.go_to("https://google.com")
530
563
  ```
531
564
 
532
565
  #### authorize(\*\*options, &block)
@@ -541,10 +574,10 @@ If site or proxy uses authorization you can provide credentials using this metho
541
574
  care about unwanted requests just call `request.continue`.
542
575
 
543
576
  ```ruby
544
- browser.network.authorize(user: "login", password: "pass") { |req| req.continue }
545
- browser.go_to("http://example.com/authenticated")
546
- puts browser.network.status # => 200
547
- puts browser.body # => Welcome, authenticated client
577
+ page.network.authorize(user: "login", password: "pass") { |req| req.continue }
578
+ page.go_to("http://example.com/authenticated")
579
+ puts page.network.status # => 200
580
+ puts page.body # => Welcome, authenticated client
548
581
  ```
549
582
 
550
583
  Since Chrome implements authorize using request interception you must continue or abort authorized requests. If you
@@ -553,8 +586,9 @@ block, so this is version doesn't pass block and can work just fine:
553
586
 
554
587
  ```ruby
555
588
  browser = Ferrum::Browser.new
556
- browser.network.intercept
557
- browser.on(:request) do |request|
589
+ page = browser.create_page
590
+ page.network.intercept
591
+ page.on(:request) do |request|
558
592
  if request.resource_type == "Image"
559
593
  request.abort
560
594
  else
@@ -562,9 +596,9 @@ browser.on(:request) do |request|
562
596
  end
563
597
  end
564
598
 
565
- browser.network.authorize(user: "login", password: "pass", type: :proxy)
599
+ page.network.authorize(user: "login", password: "pass", type: :proxy)
566
600
 
567
- browser.go_to("https://google.com")
601
+ page.go_to("https://google.com")
568
602
  ```
569
603
 
570
604
  You used to call `authorize` method without block, but since it's implemented using request interception there could be
@@ -587,8 +621,8 @@ Activates emulation of network conditions.
587
621
  bluetooth, ethernet, wifi, wimax, other. `nil` by default
588
622
 
589
623
  ```ruby
590
- browser.network.emulate_network_conditions(connection_type: "cellular2g")
591
- browser.go_to("https://github.com/")
624
+ page.network.emulate_network_conditions(connection_type: "cellular2g")
625
+ page.go_to("https://github.com/")
592
626
  ```
593
627
 
594
628
  #### offline_mode
@@ -596,8 +630,8 @@ browser.go_to("https://github.com/")
596
630
  Activates offline mode for a page.
597
631
 
598
632
  ```ruby
599
- browser.network.offline_mode
600
- browser.go_to("https://github.com/") # => Ferrum::StatusError (Request to https://github.com/ failed(net::ERR_INTERNET_DISCONNECTED))
633
+ page.network.offline_mode
634
+ page.go_to("https://github.com/") # => Ferrum::StatusError (Request to https://github.com/ failed(net::ERR_INTERNET_DISCONNECTED))
601
635
  ```
602
636
 
603
637
  #### cache(disable: `Boolean`)
@@ -605,21 +639,65 @@ browser.go_to("https://github.com/") # => Ferrum::StatusError (Request to https:
605
639
  Toggles ignoring cache for each request. If true, cache will not be used.
606
640
 
607
641
  ```ruby
608
- browser.network.cache(disable: true)
642
+ page.network.cache(disable: true)
609
643
  ```
610
644
 
645
+
646
+ ## Downloads
647
+
648
+ `page.downloads`
649
+
650
+ #### files `Array<Hash>`
651
+
652
+ Returns all information about downloaded files as a `Hash`.
653
+
654
+ ```ruby
655
+ page.go_to("http://localhost/attachment.pdf")
656
+ page.downloads.files # => [{"frameId"=>"E3316DF1B5383D38F8ADF7485005FDE3", "guid"=>"11a68745-98ac-4d54-9b57-9f9016c268b3", "url"=>"http://localhost/attachment.pdf", "suggestedFilename"=>"attachment.pdf", "totalBytes"=>4911, "receivedBytes"=>4911, "state"=>"completed"}]
657
+ ```
658
+
659
+ #### wait(timeout)
660
+
661
+ Waits until the download is finished.
662
+
663
+ ```ruby
664
+ page.go_to("http://localhost/attachment.pdf")
665
+ page.downloads.wait
666
+ ```
667
+
668
+ or
669
+
670
+ ```ruby
671
+ page.go_to("http://localhost/page")
672
+ page.downloads.wait { page.at_css("#download").click }
673
+ ```
674
+
675
+ #### set_behavior(\*\*options)
676
+
677
+ Sets behavior in case of file to be downloaded.
678
+
679
+ * options `Hash`
680
+ * :save_path `String` absolute path of where to store the file
681
+ * :behavior `Symbol` `deny | allow | allowAndName | default`, `allow` by default
682
+
683
+ ```ruby
684
+ page.go_to("https://example.com/")
685
+ page.downloads.set_behavior(save_path: "/tmp", behavior: :allow)
686
+ ```
687
+
688
+
611
689
  ## Proxy
612
690
 
613
691
  You can set a proxy with a `:proxy` option:
614
692
 
615
693
  ```ruby
616
- browser = Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", user: "user", password: "pa$$" })
694
+ Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", user: "user", password: "pa$$" })
617
695
  ```
618
696
 
619
697
  `:bypass` can specify semi-colon-separated list of hosts for which proxy shouldn't be used:
620
698
 
621
699
  ```ruby
622
- browser = Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", bypass: "*.google.com;*foo.com" })
700
+ Ferrum::Browser.new(proxy: { host: "x.x.x.x", port: "8800", bypass: "*.google.com;*foo.com" })
623
701
  ```
624
702
 
625
703
  In general passing a proxy option when instantiating a browser results in a browser running with proxy command line
@@ -643,7 +721,7 @@ end
643
721
 
644
722
  ### Mouse
645
723
 
646
- `browser.mouse`
724
+ `page.mouse`
647
725
 
648
726
  #### scroll_to(x, y)
649
727
 
@@ -655,8 +733,8 @@ Scroll page to a given x, y
655
733
  displayed in the upper left
656
734
 
657
735
  ```ruby
658
- browser.go_to("https://www.google.com/search?q=Ruby+headless+driver+for+Capybara")
659
- browser.mouse.scroll_to(0, 400)
736
+ page.go_to("https://www.google.com/search?q=Ruby+headless+driver+for+Capybara")
737
+ page.mouse.scroll_to(0, 400)
660
738
  ```
661
739
 
662
740
  #### click(\*\*options) : `Mouse`
@@ -700,7 +778,7 @@ Mouse move to given x and y.
700
778
 
701
779
  ### Keyboard
702
780
 
703
- browser.keyboard
781
+ `page.keyboard`
704
782
 
705
783
  #### down(key) : `Keyboard`
706
784
 
@@ -730,14 +808,14 @@ Returns bitfield for a given keys
730
808
 
731
809
  ## Cookies
732
810
 
733
- `browser.cookies`
811
+ `page.cookies`
734
812
 
735
813
  #### all : `Hash<String, Cookie>`
736
814
 
737
815
  Returns cookies hash
738
816
 
739
817
  ```ruby
740
- browser.cookies.all # => {"NID"=>#<Ferrum::Cookies::Cookie:0x0000558624b37a40 @attributes={"name"=>"NID", "value"=>"...", "domain"=>".google.com", "path"=>"/", "expires"=>1583211046.575681, "size"=>178, "httpOnly"=>true, "secure"=>false, "session"=>false}>}
818
+ page.cookies.all # => {"NID"=>#<Ferrum::Cookies::Cookie:0x0000558624b37a40 @attributes={"name"=>"NID", "value"=>"...", "domain"=>".google.com", "path"=>"/", "expires"=>1583211046.575681, "size"=>178, "httpOnly"=>true, "secure"=>false, "session"=>false}>}
741
819
  ```
742
820
 
743
821
  #### [](value) : `Cookie`
@@ -747,7 +825,7 @@ Returns cookie
747
825
  * value `String`
748
826
 
749
827
  ```ruby
750
- browser.cookies["NID"] # => <Ferrum::Cookies::Cookie:0x0000558624b67a88 @attributes={"name"=>"NID", "value"=>"...", "domain"=>".google.com", "path"=>"/", "expires"=>1583211046.575681, "size"=>178, "httpOnly"=>true, "secure"=>false, "session"=>false}>
828
+ page.cookies["NID"] # => <Ferrum::Cookies::Cookie:0x0000558624b67a88 @attributes={"name"=>"NID", "value"=>"...", "domain"=>".google.com", "path"=>"/", "expires"=>1583211046.575681, "size"=>178, "httpOnly"=>true, "secure"=>false, "session"=>false}>
751
829
  ```
752
830
 
753
831
  #### set(value) : `Boolean`
@@ -763,14 +841,14 @@ Sets a cookie
763
841
  * :httponly `Boolean`
764
842
 
765
843
  ```ruby
766
- browser.cookies.set(name: "stealth", value: "omg", domain: "google.com") # => true
844
+ page.cookies.set(name: "stealth", value: "omg", domain: "google.com") # => true
767
845
  ```
768
846
 
769
847
  * value `Cookie`
770
848
 
771
849
  ```ruby
772
- nid_cookie = browser.cookies["NID"] # => <Ferrum::Cookies::Cookie:0x0000558624b67a88>
773
- browser.cookies.set(nid_cookie) # => true
850
+ nid_cookie = page.cookies["NID"] # => <Ferrum::Cookies::Cookie:0x0000558624b67a88>
851
+ page.cookies.set(nid_cookie) # => true
774
852
  ```
775
853
 
776
854
  #### remove(\*\*options) : `Boolean`
@@ -783,7 +861,7 @@ Removes given cookie
783
861
  * :url `String`
784
862
 
785
863
  ```ruby
786
- browser.cookies.remove(name: "stealth", domain: "google.com") # => true
864
+ page.cookies.remove(name: "stealth", domain: "google.com") # => true
787
865
  ```
788
866
 
789
867
  #### clear : `Boolean`
@@ -791,12 +869,12 @@ browser.cookies.remove(name: "stealth", domain: "google.com") # => true
791
869
  Removes all cookies for current page
792
870
 
793
871
  ```ruby
794
- browser.cookies.clear # => true
872
+ page.cookies.clear # => true
795
873
  ```
796
874
 
797
875
  ## Headers
798
876
 
799
- `browser.headers`
877
+ `page.headers`
800
878
 
801
879
  #### get : `Hash`
802
880
 
@@ -830,7 +908,7 @@ Evaluate and return result for given JS expression
830
908
  simple value.
831
909
 
832
910
  ```ruby
833
- browser.evaluate("[window.scrollX, window.scrollY]")
911
+ page.evaluate("[window.scrollX, window.scrollY]")
834
912
  ```
835
913
 
836
914
  #### evaluate_async(expression, wait_time, \*args)
@@ -843,7 +921,7 @@ Evaluate asynchronous expression and return result
843
921
  simple value.
844
922
 
845
923
  ```ruby
846
- browser.evaluate_async(%(arguments[0]({foo: "bar"})), 5) # => { "foo" => "bar" }
924
+ page.evaluate_async(%(arguments[0]({foo: "bar"})), 5) # => { "foo" => "bar" }
847
925
  ```
848
926
 
849
927
  #### execute(expression, \*args)
@@ -855,7 +933,7 @@ Execute expression. Doesn't return the result
855
933
  simple value.
856
934
 
857
935
  ```ruby
858
- browser.execute(%(1 + 1)) # => true
936
+ page.execute(%(1 + 1)) # => true
859
937
  ```
860
938
 
861
939
  #### evaluate_on_new_document(expression)
@@ -881,7 +959,7 @@ JS
881
959
  * :type `String` - `text/javascript` by default
882
960
 
883
961
  ```ruby
884
- browser.add_script_tag(url: "http://example.com/stylesheet.css") # => true
962
+ page.add_script_tag(url: "http://example.com/stylesheet.css") # => true
885
963
  ```
886
964
 
887
965
  #### add_style_tag(\*\*options) : `Boolean`
@@ -892,7 +970,7 @@ browser.add_script_tag(url: "http://example.com/stylesheet.css") # => true
892
970
  * :content `String`
893
971
 
894
972
  ```ruby
895
- browser.add_style_tag(content: "h1 { font-size: 40px; }") # => true
973
+ page.add_style_tag(content: "h1 { font-size: 40px; }") # => true
896
974
 
897
975
  ```
898
976
  #### bypass_csp(\*\*options) : `Boolean`
@@ -901,11 +979,39 @@ browser.add_style_tag(content: "h1 { font-size: 40px; }") # => true
901
979
  * :enabled `Boolean`, `true` by default
902
980
 
903
981
  ```ruby
904
- browser.bypass_csp # => true
905
- browser.go_to("https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/promises.in.md")
906
- browser.refresh
907
- browser.add_script_tag(content: "window.__injected = 42")
908
- browser.evaluate("window.__injected") # => 42
982
+ page.bypass_csp # => true
983
+ page.go_to("https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/promises.in.md")
984
+ page.refresh
985
+ page.add_script_tag(content: "window.__injected = 42")
986
+ page.evaluate("window.__injected") # => 42
987
+ ```
988
+
989
+
990
+ ## Emulation
991
+
992
+ #### disable_javascript
993
+
994
+ Disables Javascripts from the loaded HTML source.
995
+ You can still evaluate JavaScript with `evaluate` or `execute`.
996
+ Returns nothing.
997
+
998
+ ```ruby
999
+ page.disable_javascript
1000
+ ```
1001
+
1002
+
1003
+ #### set_viewport
1004
+
1005
+ Overrides device screen dimensions and emulates viewport.
1006
+
1007
+ * options `Hash`
1008
+ * :width `Integer`, viewport width. `0` by default
1009
+ * :height `Integer`, viewport height. `0` by default
1010
+ * :scale_factor `Float`, device scale factor. `0` by default
1011
+ * :mobile `Boolean`, whether to emulate mobile device. `false` by default
1012
+
1013
+ ```ruby
1014
+ page.set_viewport(width: 1000, height: 600, scale_factor: 3)
909
1015
  ```
910
1016
 
911
1017
 
@@ -916,8 +1022,8 @@ browser.evaluate("window.__injected") # => 42
916
1022
  Returns all the frames current page have.
917
1023
 
918
1024
  ```ruby
919
- browser.go_to("https://www.w3schools.com/tags/tag_frame.asp")
920
- browser.frames # =>
1025
+ page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
1026
+ page.frames # =>
921
1027
  # [
922
1028
  # #<Ferrum::Frame @id="C6D104CE454A025FBCF22B98DE612B12" @parent_id=nil @name=nil @state=:stopped_loading @execution_id=1>,
923
1029
  # #<Ferrum::Frame @id="C09C4E4404314AAEAE85928EAC109A93" @parent_id="C6D104CE454A025FBCF22B98DE612B12" @state=:stopped_loading @execution_id=2>,
@@ -939,7 +1045,7 @@ Find frame by given options.
939
1045
  * :name `String` - Frame's name if there's one
940
1046
 
941
1047
  ```ruby
942
- browser.frame_by(id: "C6D104CE454A025FBCF22B98DE612B12")
1048
+ page.frame_by(id: "C6D104CE454A025FBCF22B98DE612B12")
943
1049
  ```
944
1050
 
945
1051
 
@@ -975,8 +1081,8 @@ One of the states frame's in:
975
1081
  Returns current frame's location href.
976
1082
 
977
1083
  ```ruby
978
- browser.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
979
- frame = browser.frames[1]
1084
+ page.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
1085
+ frame = page.frames[1]
980
1086
  frame.url # => https://interactive-examples.mdn.mozilla.net/pages/tabbed/iframe.html
981
1087
  ```
982
1088
 
@@ -985,8 +1091,8 @@ frame.url # => https://interactive-examples.mdn.mozilla.net/pages/tabbed/iframe.
985
1091
  Returns current frame's title.
986
1092
 
987
1093
  ```ruby
988
- browser.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
989
- frame = browser.frames[1]
1094
+ page.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
1095
+ frame = page.frames[1]
990
1096
  frame.title # => HTML Demo: <iframe>
991
1097
  ```
992
1098
 
@@ -995,8 +1101,8 @@ frame.title # => HTML Demo: <iframe>
995
1101
  If current frame is the main frame of the page (top of the tree).
996
1102
 
997
1103
  ```ruby
998
- browser.go_to("https://www.w3schools.com/tags/tag_frame.asp")
999
- frame = browser.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
1104
+ page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
1105
+ frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
1000
1106
  frame.main? # => false
1001
1107
  ```
1002
1108
 
@@ -1005,8 +1111,8 @@ frame.main? # => false
1005
1111
  Returns current frame's top window location href.
1006
1112
 
1007
1113
  ```ruby
1008
- browser.go_to("https://www.w3schools.com/tags/tag_frame.asp")
1009
- frame = browser.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
1114
+ page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
1115
+ frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
1010
1116
  frame.current_url # => "https://www.w3schools.com/tags/tag_frame.asp"
1011
1117
  ```
1012
1118
 
@@ -1015,8 +1121,8 @@ frame.current_url # => "https://www.w3schools.com/tags/tag_frame.asp"
1015
1121
  Returns current frame's top window title.
1016
1122
 
1017
1123
  ```ruby
1018
- browser.go_to("https://www.w3schools.com/tags/tag_frame.asp")
1019
- frame = browser.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
1124
+ page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
1125
+ frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
1020
1126
  frame.current_title # => "HTML frame tag"
1021
1127
  ```
1022
1128
 
@@ -1025,8 +1131,8 @@ frame.current_title # => "HTML frame tag"
1025
1131
  Returns current frame's html.
1026
1132
 
1027
1133
  ```ruby
1028
- browser.go_to("https://www.w3schools.com/tags/tag_frame.asp")
1029
- frame = browser.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
1134
+ page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
1135
+ frame = page.frame_by(id: "C09C4E4404314AAEAE85928EAC109A93")
1030
1136
  frame.body # => "<html><head></head><body></body></html>"
1031
1137
  ```
1032
1138
 
@@ -1035,8 +1141,8 @@ frame.body # => "<html><head></head><body></body></html>"
1035
1141
  Returns current frame's doctype.
1036
1142
 
1037
1143
  ```ruby
1038
- browser.go_to("https://www.w3schools.com/tags/tag_frame.asp")
1039
- browser.main_frame.doctype # => "<!DOCTYPE html>"
1144
+ page.go_to("https://www.w3schools.com/tags/tag_frame.asp")
1145
+ page.main_frame.doctype # => "<!DOCTYPE html>"
1040
1146
  ```
1041
1147
 
1042
1148
  #### content = html
@@ -1046,8 +1152,8 @@ Sets a content of a given frame.
1046
1152
  * html `String`
1047
1153
 
1048
1154
  ```ruby
1049
- browser.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
1050
- frame = browser.frames[1]
1155
+ page.go_to("https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe")
1156
+ frame = page.frames[1]
1051
1157
  frame.body # <html lang="en"><head><style>body {transition: opacity ease-in 0.2s; }...
1052
1158
  frame.content = "<html><head></head><body><p>lol</p></body></html>"
1053
1159
  frame.body # => <html><head></head><body><p>lol</p></body></html>
@@ -1067,15 +1173,14 @@ Accept dialog with given text or default prompt if applicable
1067
1173
  Dismiss dialog
1068
1174
 
1069
1175
  ```ruby
1070
- browser = Ferrum::Browser.new
1071
- browser.on(:dialog) do |dialog|
1176
+ page.on(:dialog) do |dialog|
1072
1177
  if dialog.match?(/bla-bla/)
1073
1178
  dialog.accept
1074
1179
  else
1075
1180
  dialog.dismiss
1076
1181
  end
1077
1182
  end
1078
- browser.go_to("https://google.com")
1183
+ page.go_to("https://google.com")
1079
1184
  ```
1080
1185
 
1081
1186
 
@@ -1095,10 +1200,9 @@ Sets playback rate of CSS animations
1095
1200
  * value `Integer`
1096
1201
 
1097
1202
  ```ruby
1098
- browser = Ferrum::Browser.new
1099
- browser.playback_rate = 2000
1100
- browser.go_to("https://google.com")
1101
- browser.playback_rate # => 2000
1203
+ page.playback_rate = 2000
1204
+ page.go_to("https://google.com")
1205
+ page.playback_rate # => 2000
1102
1206
  ```
1103
1207
 
1104
1208
 
@@ -1112,7 +1216,7 @@ Returns [Frame](https://github.com/rubycdp/ferrum#frame) object for current node
1112
1216
  [Finders](https://github.com/rubycdp/ferrum#Finders) for that object:
1113
1217
 
1114
1218
  ```ruby
1115
- frame = browser.at_xpath("//iframe").frame # => Frame
1219
+ frame = page.at_xpath("//iframe").frame # => Frame
1116
1220
  frame.at_css("//a[text() = 'Log in']") # => Node
1117
1221
  ```
1118
1222
 
@@ -1143,15 +1247,15 @@ frame.at_css("//a[text() = 'Log in']") # => Node
1143
1247
  (chainable) Selects options by passed attribute.
1144
1248
 
1145
1249
  ```ruby
1146
- browser.at_xpath("//*[select]").select(["1"]) # => Node (select)
1147
- browser.at_xpath("//*[select]").select(["text"], by: :text) # => Node (select)
1250
+ page.at_xpath("//*[select]").select(["1"]) # => Node (select)
1251
+ page.at_xpath("//*[select]").select(["text"], by: :text) # => Node (select)
1148
1252
  ```
1149
1253
 
1150
1254
  Accept string, array or strings:
1151
1255
  ```ruby
1152
- browser.at_xpath("//*[select]").select("1")
1153
- browser.at_xpath("//*[select]").select("1", "2")
1154
- browser.at_xpath("//*[select]").select(["1", "2"])
1256
+ page.at_xpath("//*[select]").select("1")
1257
+ page.at_xpath("//*[select]").select("1", "2")
1258
+ page.at_xpath("//*[select]").select(["1", "2"])
1155
1259
  ```
1156
1260
 
1157
1261
 
@@ -1182,6 +1286,25 @@ Accepts block, records trace and by default returns trace data from `Tracing.tra
1182
1286
  only one trace config can be active at a time per browser.
1183
1287
 
1184
1288
 
1289
+ ## Clean Up
1290
+
1291
+ #### reset
1292
+
1293
+ Closes browser tabs opened by the `Browser` instance.
1294
+
1295
+ ```ruby
1296
+ # connect to a long-running Chrome process
1297
+ browser = Ferrum::Browser.new(url: 'http://localhost:9222')
1298
+
1299
+ browser.go_to("https://github.com/")
1300
+
1301
+ # clean up, lest the tab stays there hanging forever
1302
+ browser.reset
1303
+
1304
+ browser.quit
1305
+ ```
1306
+
1307
+
1185
1308
  ## Thread safety ##
1186
1309
 
1187
1310
  Ferrum is fully thread-safe. You can create one browser or a few as you wish and