playwright-ruby-client 1.37.1 → 1.39.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.
- checksums.yaml +4 -4
- data/README.md +13 -7
- data/documentation/docs/api/browser.md +13 -9
- data/documentation/docs/api/browser_context.md +51 -32
- data/documentation/docs/api/browser_type.md +12 -7
- data/documentation/docs/api/dialog.md +18 -15
- data/documentation/docs/api/download.md +17 -7
- data/documentation/docs/api/element_handle.md +7 -19
- data/documentation/docs/api/frame.md +55 -30
- data/documentation/docs/api/keyboard.md +4 -0
- data/documentation/docs/api/locator.md +57 -16
- data/documentation/docs/api/page.md +102 -54
- data/documentation/docs/api/playwright.md +23 -20
- data/documentation/docs/api/request.md +17 -0
- data/documentation/docs/api/selectors.md +34 -29
- data/documentation/docs/include/api_coverage.md +1 -0
- data/lib/playwright/channel.rb +8 -0
- data/lib/playwright/channel_owner.rb +7 -2
- data/lib/playwright/channel_owners/browser_context.rb +16 -1
- data/lib/playwright/channel_owners/local_utils.rb +27 -0
- data/lib/playwright/channel_owners/page.rb +2 -0
- data/lib/playwright/channel_owners/playwright.rb +1 -24
- data/lib/playwright/channel_owners/request.rb +17 -1
- data/lib/playwright/channel_owners/route.rb +5 -1
- data/lib/playwright/connection.rb +1 -1
- data/lib/playwright/console_message_impl.rb +29 -0
- data/lib/playwright/errors.rb +13 -2
- data/lib/playwright/events.rb +1 -0
- data/lib/playwright/javascript/value_parser.rb +8 -0
- data/lib/playwright/javascript/value_serializer.rb +10 -4
- data/lib/playwright/locator_impl.rb +4 -0
- data/lib/playwright/utils.rb +4 -0
- data/lib/playwright/version.rb +2 -2
- data/lib/playwright_api/browser.rb +2 -2
- data/lib/playwright_api/browser_context.rb +4 -4
- data/lib/playwright_api/browser_type.rb +2 -2
- data/lib/playwright_api/console_message.rb +0 -22
- data/lib/playwright_api/dialog.rb +2 -2
- data/lib/playwright_api/download.rb +12 -3
- data/lib/playwright_api/element_handle.rb +2 -15
- data/lib/playwright_api/frame.rb +8 -13
- data/lib/playwright_api/keyboard.rb +4 -0
- data/lib/playwright_api/locator.rb +52 -16
- data/lib/playwright_api/page.rb +24 -29
- data/lib/playwright_api/playwright.rb +4 -4
- data/lib/playwright_api/request.rb +17 -0
- data/lib/playwright_api/selectors.rb +2 -2
- data/lib/playwright_api/worker.rb +4 -4
- data/sig/playwright.rbs +1 -0
- metadata +4 -4
- data/lib/playwright/channel_owners/console_message.rb +0 -25
@@ -12,12 +12,21 @@ instance might have multiple [Page](./page) instances.
|
|
12
12
|
|
13
13
|
This example creates a page, navigates it to a URL, and then saves a screenshot:
|
14
14
|
|
15
|
-
```
|
16
|
-
playwright.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
```python sync title=example_94e620cdbdfd41e2c9b14d561052ffa89535fc346038c4584ea4dd8520f5401c.py
|
16
|
+
from playwright.sync_api import sync_playwright, Playwright
|
17
|
+
|
18
|
+
def run(playwright: Playwright):
|
19
|
+
webkit = playwright.webkit
|
20
|
+
browser = webkit.launch()
|
21
|
+
context = browser.new_context()
|
22
|
+
page = context.new_page()
|
23
|
+
page.goto("https://example.com")
|
24
|
+
page.screenshot(path="screenshot.png")
|
25
|
+
browser.close()
|
26
|
+
|
27
|
+
with sync_playwright() as playwright:
|
28
|
+
run(playwright)
|
29
|
+
|
21
30
|
```
|
22
31
|
|
23
32
|
The Page class emits various events (described below) which can be handled using any of Node's native
|
@@ -462,18 +471,29 @@ See [BrowserContext#expose_binding](./browser_context#expose_binding) for the co
|
|
462
471
|
|
463
472
|
An example of exposing page URL to all frames in a page:
|
464
473
|
|
465
|
-
```
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
474
|
+
```python sync title=example_4f7d99a72aaea957cc5678ed8728965338d78598d7772f47fbf23c28f0eba52d.py
|
475
|
+
from playwright.sync_api import sync_playwright, Playwright
|
476
|
+
|
477
|
+
def run(playwright: Playwright):
|
478
|
+
webkit = playwright.webkit
|
479
|
+
browser = webkit.launch(headless=false)
|
480
|
+
context = browser.new_context()
|
481
|
+
page = context.new_page()
|
482
|
+
page.expose_binding("pageURL", lambda source: source["page"].url)
|
483
|
+
page.set_content("""
|
484
|
+
<script>
|
485
|
+
async function onClick() {
|
486
|
+
document.querySelector('div').textContent = await window.pageURL();
|
487
|
+
}
|
488
|
+
</script>
|
489
|
+
<button onclick="onClick()">Click me</button>
|
490
|
+
<div></div>
|
491
|
+
""")
|
492
|
+
page.click("button")
|
493
|
+
|
494
|
+
with sync_playwright() as playwright:
|
495
|
+
run(playwright)
|
496
|
+
|
477
497
|
```
|
478
498
|
|
479
499
|
An example of passing an element handle:
|
@@ -517,24 +537,35 @@ See [BrowserContext#expose_function](./browser_context#expose_function) for cont
|
|
517
537
|
|
518
538
|
An example of adding a `sha256` function to the page:
|
519
539
|
|
520
|
-
```
|
521
|
-
|
540
|
+
```python sync title=example_0f68a39bdff02a3df161c74e81cabb8a2ff1f09f0d09f6ef9b799a6f2f19a280.py
|
541
|
+
import hashlib
|
542
|
+
from playwright.sync_api import sync_playwright, Playwright
|
522
543
|
|
523
|
-
def
|
524
|
-
|
525
|
-
|
544
|
+
def sha256(text):
|
545
|
+
m = hashlib.sha256()
|
546
|
+
m.update(bytes(text, "utf8"))
|
547
|
+
return m.hexdigest()
|
548
|
+
|
549
|
+
|
550
|
+
def run(playwright: Playwright):
|
551
|
+
webkit = playwright.webkit
|
552
|
+
browser = webkit.launch(headless=False)
|
553
|
+
page = browser.new_page()
|
554
|
+
page.expose_function("sha256", sha256)
|
555
|
+
page.set_content("""
|
556
|
+
<script>
|
557
|
+
async function onClick() {
|
558
|
+
document.querySelector('div').textContent = await window.sha256('PLAYWRIGHT');
|
559
|
+
}
|
560
|
+
</script>
|
561
|
+
<button onclick="onClick()">Click me</button>
|
562
|
+
<div></div>
|
563
|
+
""")
|
564
|
+
page.click("button")
|
565
|
+
|
566
|
+
with sync_playwright() as playwright:
|
567
|
+
run(playwright)
|
526
568
|
|
527
|
-
page.expose_function("sha256", method(:sha256))
|
528
|
-
page.content = <<~HTML
|
529
|
-
<script>
|
530
|
-
async function onClick() {
|
531
|
-
document.querySelector('div').textContent = await window.sha256('PLAYWRIGHT');
|
532
|
-
}
|
533
|
-
</script>
|
534
|
-
<button onclick="onClick()">Click me</button>
|
535
|
-
<div></div>
|
536
|
-
HTML
|
537
|
-
page.locator("button").click
|
538
569
|
```
|
539
570
|
|
540
571
|
## fill
|
@@ -554,7 +585,7 @@ This method waits for an element matching `selector`, waits for [actionability](
|
|
554
585
|
|
555
586
|
If the target element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error. However, if the element is inside the `<label>` element that has an associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), the control will be filled instead.
|
556
587
|
|
557
|
-
To send fine-grained keyboard events, use [
|
588
|
+
To send fine-grained keyboard events, use [Locator#press_sequentially](./locator#press_sequentially).
|
558
589
|
|
559
590
|
## focus
|
560
591
|
|
@@ -1324,13 +1355,14 @@ Triggers a `change` and `input` event once all the provided options have been se
|
|
1324
1355
|
|
1325
1356
|
**Usage**
|
1326
1357
|
|
1327
|
-
```
|
1328
|
-
#
|
1329
|
-
page.select_option("select#colors",
|
1358
|
+
```python sync title=example_8260034c740933903e5a39d30a4f4e388bdffa9e82acd9a5fe1fb774752a505a.py
|
1359
|
+
# Single selection matching the value or label
|
1360
|
+
page.select_option("select#colors", "blue")
|
1330
1361
|
# single selection matching both the label
|
1331
|
-
page.select_option("select#colors", label
|
1362
|
+
page.select_option("select#colors", label="blue")
|
1332
1363
|
# multiple selection
|
1333
|
-
page.select_option("select#colors", value
|
1364
|
+
page.select_option("select#colors", value=["red", "green", "blue"])
|
1365
|
+
|
1334
1366
|
```
|
1335
1367
|
|
1336
1368
|
## set_checked
|
@@ -1519,11 +1551,6 @@ To press a special key, like `Control` or `ArrowDown`, use [Keyboard#press](./ke
|
|
1519
1551
|
|
1520
1552
|
**Usage**
|
1521
1553
|
|
1522
|
-
```ruby
|
1523
|
-
page.type("#mytextarea", "hello") # types instantly
|
1524
|
-
page.type("#mytextarea", "world", delay: 100) # types slower, like a user
|
1525
|
-
```
|
1526
|
-
|
1527
1554
|
## uncheck
|
1528
1555
|
|
1529
1556
|
```
|
@@ -1649,9 +1676,20 @@ Returns when the `expression` returns a truthy value. It resolves to a JSHandle
|
|
1649
1676
|
|
1650
1677
|
The [Page#wait_for_function](./page#wait_for_function) can be used to observe viewport size change:
|
1651
1678
|
|
1652
|
-
```
|
1653
|
-
|
1654
|
-
|
1679
|
+
```python sync title=example_83eed1f1f00ad73f641bf4a49f672e81c4faf1ca098a4a5070afeeabb88312f5.py
|
1680
|
+
from playwright.sync_api import sync_playwright, Playwright
|
1681
|
+
|
1682
|
+
def run(playwright: Playwright):
|
1683
|
+
webkit = playwright.webkit
|
1684
|
+
browser = webkit.launch()
|
1685
|
+
page = browser.new_page()
|
1686
|
+
page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);")
|
1687
|
+
page.wait_for_function("() => window.x > 0")
|
1688
|
+
browser.close()
|
1689
|
+
|
1690
|
+
with sync_playwright() as playwright:
|
1691
|
+
run(playwright)
|
1692
|
+
|
1655
1693
|
```
|
1656
1694
|
|
1657
1695
|
To pass an argument to the predicate of [Page#wait_for_function](./page#wait_for_function) function:
|
@@ -1819,12 +1857,22 @@ function will throw.
|
|
1819
1857
|
|
1820
1858
|
This method works across navigations:
|
1821
1859
|
|
1822
|
-
```
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1860
|
+
```python sync title=example_903c7325fd65fcdf6f22c77fc159922a568841abce60ae1b7c54ab5837401862.py
|
1861
|
+
from playwright.sync_api import sync_playwright, Playwright
|
1862
|
+
|
1863
|
+
def run(playwright: Playwright):
|
1864
|
+
chromium = playwright.chromium
|
1865
|
+
browser = chromium.launch()
|
1866
|
+
page = browser.new_page()
|
1867
|
+
for current_url in ["https://google.com", "https://bbc.com"]:
|
1868
|
+
page.goto(current_url, wait_until="domcontentloaded")
|
1869
|
+
element = page.wait_for_selector("img")
|
1870
|
+
print("Loaded image: " + str(element.get_attribute("src")))
|
1871
|
+
browser.close()
|
1872
|
+
|
1873
|
+
with sync_playwright() as playwright:
|
1874
|
+
run(playwright)
|
1875
|
+
|
1828
1876
|
```
|
1829
1877
|
|
1830
1878
|
## wait_for_timeout
|
@@ -8,19 +8,20 @@ sidebar_position: 10
|
|
8
8
|
Playwright module provides a method to launch a browser instance. The following is a typical example of using Playwright
|
9
9
|
to drive automation:
|
10
10
|
|
11
|
-
```
|
12
|
-
|
11
|
+
```python sync title=example_6647e5a44b0440884026a6142606dfddad75ba1e643919b015457df4ed2e198f.py
|
12
|
+
from playwright.sync_api import sync_playwright, Playwright
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
page = browser.new_page
|
18
|
-
page.goto(
|
14
|
+
def run(playwright: Playwright):
|
15
|
+
chromium = playwright.chromium # or "firefox" or "webkit".
|
16
|
+
browser = chromium.launch()
|
17
|
+
page = browser.new_page()
|
18
|
+
page.goto("http://example.com")
|
19
|
+
# other actions...
|
20
|
+
browser.close()
|
19
21
|
|
20
|
-
|
22
|
+
with sync_playwright() as playwright:
|
23
|
+
run(playwright)
|
21
24
|
|
22
|
-
end
|
23
|
-
end
|
24
25
|
```
|
25
26
|
|
26
27
|
## chromium
|
@@ -33,20 +34,22 @@ This object can be used to launch or connect to Chromium, returning instances of
|
|
33
34
|
|
34
35
|
Returns a dictionary of devices to be used with [Browser#new_context](./browser#new_context) or [Browser#new_page](./browser#new_page).
|
35
36
|
|
36
|
-
```
|
37
|
-
|
37
|
+
```python sync title=example_14d627977a4ad16a605ec5472d768a3324812fa8e7c57685561408fa6601e352.py
|
38
|
+
from playwright.sync_api import sync_playwright, Playwright
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
def run(playwright: Playwright):
|
41
|
+
webkit = playwright.webkit
|
42
|
+
iphone = playwright.devices["iPhone 6"]
|
43
|
+
browser = webkit.launch()
|
42
44
|
context = browser.new_context(**iphone)
|
43
|
-
page = context.new_page
|
44
|
-
page.goto(
|
45
|
+
page = context.new_page()
|
46
|
+
page.goto("http://example.com")
|
47
|
+
# other actions...
|
48
|
+
browser.close()
|
45
49
|
|
46
|
-
|
50
|
+
with sync_playwright() as playwright:
|
51
|
+
run(playwright)
|
47
52
|
|
48
|
-
end
|
49
|
-
end
|
50
53
|
```
|
51
54
|
|
52
55
|
## firefox
|
@@ -54,6 +54,20 @@ def frame
|
|
54
54
|
|
55
55
|
Returns the [Frame](./frame) that initiated this request.
|
56
56
|
|
57
|
+
**Usage**
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
frame_url = request.frame.url
|
61
|
+
```
|
62
|
+
|
63
|
+
**Details**
|
64
|
+
|
65
|
+
Note that in some cases the frame is not available, and this method will throw.
|
66
|
+
- When request originates in the Service Worker. You can use `request.serviceWorker()` to check that.
|
67
|
+
- When navigation request is issued before the corresponding frame is created. You can use [Request#navigation_request?](./request#navigation_request?) to check that.
|
68
|
+
|
69
|
+
Here is an example that handles all the cases:
|
70
|
+
|
57
71
|
## headers
|
58
72
|
|
59
73
|
```
|
@@ -93,6 +107,9 @@ def navigation_request?
|
|
93
107
|
|
94
108
|
Whether this request is driving frame's navigation.
|
95
109
|
|
110
|
+
Some navigation requests are issued before the corresponding frame is created, and therefore
|
111
|
+
do not have [Request#frame](./request#frame) available.
|
112
|
+
|
96
113
|
## method
|
97
114
|
|
98
115
|
```
|
@@ -21,33 +21,38 @@ Selectors must be registered before creating the page.
|
|
21
21
|
|
22
22
|
An example of registering selector engine that queries elements based on a tag name:
|
23
23
|
|
24
|
-
```
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
24
|
+
```python sync title=example_3e739d4f0e30e20a6a698e0e17605a841c35e65e75aa3c2642f8bfc368b33f9e.py
|
25
|
+
from playwright.sync_api import sync_playwright, Playwright
|
26
|
+
|
27
|
+
def run(playwright: Playwright):
|
28
|
+
tag_selector = """
|
29
|
+
{
|
30
|
+
// Returns the first element matching given selector in the root's subtree.
|
31
|
+
query(root, selector) {
|
32
|
+
return root.querySelector(selector);
|
33
|
+
},
|
34
|
+
// Returns all elements matching given selector in the root's subtree.
|
35
|
+
queryAll(root, selector) {
|
36
|
+
return Array.from(root.querySelectorAll(selector));
|
37
|
+
}
|
38
|
+
}"""
|
39
|
+
|
40
|
+
# Register the engine. Selectors will be prefixed with "tag=".
|
41
|
+
playwright.selectors.register("tag", tag_selector)
|
42
|
+
browser = playwright.chromium.launch()
|
43
|
+
page = browser.new_page()
|
44
|
+
page.set_content('<div><button>Click me</button></div>')
|
45
|
+
|
46
|
+
# Use the selector prefixed with its name.
|
47
|
+
button = page.locator('tag=button')
|
48
|
+
# Combine it with built-in locators.
|
49
|
+
page.locator('tag=div').get_by_text('Click me').click()
|
50
|
+
# Can use it in any methods supporting selectors.
|
51
|
+
button_count = page.locator('tag=button').count()
|
52
|
+
print(button_count)
|
53
|
+
browser.close()
|
54
|
+
|
55
|
+
with sync_playwright() as playwright:
|
56
|
+
run(playwright)
|
57
|
+
|
53
58
|
```
|
data/lib/playwright/channel.rb
CHANGED
@@ -30,6 +30,7 @@ module Playwright
|
|
30
30
|
# @param params [Hash]
|
31
31
|
# @return [Hash]
|
32
32
|
def send_message_to_server_result(method, params)
|
33
|
+
check_not_collected
|
33
34
|
with_logging do |metadata|
|
34
35
|
@connection.send_message_to_server(@guid, method, params, metadata: metadata)
|
35
36
|
end
|
@@ -39,6 +40,7 @@ module Playwright
|
|
39
40
|
# @param params [Hash]
|
40
41
|
# @returns [Concurrent::Promises::Future]
|
41
42
|
def async_send_message_to_server(method, params = {})
|
43
|
+
check_not_collected
|
42
44
|
with_logging do |metadata|
|
43
45
|
@connection.async_send_message_to_server(@guid, method, params, metadata: metadata)
|
44
46
|
end
|
@@ -74,5 +76,11 @@ module Playwright
|
|
74
76
|
end,
|
75
77
|
}
|
76
78
|
end
|
79
|
+
|
80
|
+
private def check_not_collected
|
81
|
+
if @object.was_collected?
|
82
|
+
raise "The object has been collected to prevent unbounded heap growth."
|
83
|
+
end
|
84
|
+
end
|
77
85
|
end
|
78
86
|
end
|
@@ -50,13 +50,18 @@ module Playwright
|
|
50
50
|
child.send(:update_parent, self)
|
51
51
|
end
|
52
52
|
|
53
|
+
def was_collected?
|
54
|
+
@was_collected
|
55
|
+
end
|
56
|
+
|
53
57
|
# used only from Connection. Not intended for public use. So keep private.
|
54
|
-
private def dispose!
|
58
|
+
private def dispose!(reason: nil)
|
55
59
|
# Clean up from parent and connection.
|
56
60
|
@connection.send(:delete_object_from_channel_owner, @guid)
|
61
|
+
@was_collected = reason == 'gc'
|
57
62
|
|
58
63
|
# Dispose all children.
|
59
|
-
@objects.each_value { |object| object.send(:dispose
|
64
|
+
@objects.each_value { |object| object.send(:dispose!, reason: reason) }
|
60
65
|
@objects.clear
|
61
66
|
end
|
62
67
|
|
@@ -36,7 +36,13 @@ module Playwright
|
|
36
36
|
on_service_worker(ChannelOwners::Worker.from(params['worker']))
|
37
37
|
})
|
38
38
|
@channel.on('console', ->(params) {
|
39
|
-
on_console_message(
|
39
|
+
on_console_message(ConsoleMessageImpl.new(params))
|
40
|
+
})
|
41
|
+
@channel.on('pageError', ->(params) {
|
42
|
+
on_page_error(
|
43
|
+
Error.parse(params['error']['error']),
|
44
|
+
ChannelOwners::Page.from_nullable(params['page']),
|
45
|
+
)
|
40
46
|
})
|
41
47
|
@channel.on('dialog', ->(params) {
|
42
48
|
on_dialog(ChannelOwners::Dialog.from(params['dialog']))
|
@@ -97,6 +103,8 @@ module Playwright
|
|
97
103
|
end
|
98
104
|
|
99
105
|
private def on_route(route)
|
106
|
+
route.send(:update_context, self)
|
107
|
+
|
100
108
|
# It is not desired to use PlaywrightApi.wrap directly.
|
101
109
|
# However it is a little difficult to define wrapper for `handler` parameter in generate_api.
|
102
110
|
# Just a workaround...
|
@@ -177,6 +185,13 @@ module Playwright
|
|
177
185
|
end
|
178
186
|
end
|
179
187
|
|
188
|
+
private def on_page_error(error, page)
|
189
|
+
emit(Events::BrowserContext::WebError, WebError.new(error, page))
|
190
|
+
if page
|
191
|
+
page.emit(Events::Page::PageError, error)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
180
195
|
private def on_request(request, page)
|
181
196
|
emit(Events::BrowserContext::Request, request)
|
182
197
|
page&.emit(Events::Page::Request, request)
|
@@ -1,5 +1,11 @@
|
|
1
1
|
module Playwright
|
2
2
|
define_channel_owner :LocalUtils do
|
3
|
+
def devices
|
4
|
+
@devices ||= @initializer['deviceDescriptors'].map do |device|
|
5
|
+
[device['name'], parse_device_descriptor(device['descriptor'])]
|
6
|
+
end.to_h
|
7
|
+
end
|
8
|
+
|
3
9
|
# @param zip_file [String]
|
4
10
|
def zip(params)
|
5
11
|
@channel.send_message_to_server('zip', params)
|
@@ -51,5 +57,26 @@ module Playwright
|
|
51
57
|
@channel.async_send_message_to_server('addStackToTracingNoReply', callData: { id: id, stack: stack })
|
52
58
|
nil
|
53
59
|
end
|
60
|
+
|
61
|
+
private def parse_device_descriptor(descriptor)
|
62
|
+
# This return value can be passed into Browser#new_context as it is.
|
63
|
+
# ex:
|
64
|
+
# ```
|
65
|
+
# iPhone = playwright.devices['iPhone 6']
|
66
|
+
# context = browser.new_context(**iPhone)
|
67
|
+
# page = context.new_page
|
68
|
+
#
|
69
|
+
# ```
|
70
|
+
{
|
71
|
+
userAgent: descriptor['userAgent'],
|
72
|
+
viewport: {
|
73
|
+
width: descriptor['viewport']['width'],
|
74
|
+
height: descriptor['viewport']['height'],
|
75
|
+
},
|
76
|
+
deviceScaleFactor: descriptor['deviceScaleFactor'],
|
77
|
+
isMobile: descriptor['isMobile'],
|
78
|
+
hasTouch: descriptor['hasTouch'],
|
79
|
+
}
|
80
|
+
end
|
54
81
|
end
|
55
82
|
end
|
@@ -96,6 +96,8 @@ module Playwright
|
|
96
96
|
end
|
97
97
|
|
98
98
|
private def on_route(route)
|
99
|
+
route.send(:update_context, self)
|
100
|
+
|
99
101
|
# It is not desired to use PlaywrightApi.wrap directly.
|
100
102
|
# However it is a little difficult to define wrapper for `handler` parameter in generate_api.
|
101
103
|
# Just a workaround...
|
@@ -25,9 +25,7 @@ module Playwright
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def devices
|
28
|
-
@devices
|
29
|
-
[item['name'], parse_device_descriptor(item['descriptor'])]
|
30
|
-
end.to_h
|
28
|
+
@connection.local_utils.devices
|
31
29
|
end
|
32
30
|
|
33
31
|
# used only from Playwright#connect_to_browser_server
|
@@ -44,26 +42,5 @@ module Playwright
|
|
44
42
|
end
|
45
43
|
::Playwright::ChannelOwners::AndroidDevice.from(@initializer['preConnectedAndroidDevice'])
|
46
44
|
end
|
47
|
-
|
48
|
-
private def parse_device_descriptor(descriptor)
|
49
|
-
# This return value can be passed into Browser#new_context as it is.
|
50
|
-
# ex:
|
51
|
-
# ```
|
52
|
-
# iPhone = playwright.devices['iPhone 6']
|
53
|
-
# context = browser.new_context(**iPhone)
|
54
|
-
# page = context.new_page
|
55
|
-
#
|
56
|
-
# ```
|
57
|
-
{
|
58
|
-
userAgent: descriptor['userAgent'],
|
59
|
-
viewport: {
|
60
|
-
width: descriptor['viewport']['width'],
|
61
|
-
height: descriptor['viewport']['height'],
|
62
|
-
},
|
63
|
-
deviceScaleFactor: descriptor['deviceScaleFactor'],
|
64
|
-
isMobile: descriptor['isMobile'],
|
65
|
-
hasTouch: descriptor['hasTouch'],
|
66
|
-
}
|
67
|
-
end
|
68
45
|
end
|
69
46
|
end
|
@@ -86,8 +86,24 @@ module Playwright
|
|
86
86
|
ChannelOwners::Response.from_nullable(resp)
|
87
87
|
end
|
88
88
|
|
89
|
+
class FramePageNotReadyError < StandardError
|
90
|
+
MESSAGE = [
|
91
|
+
'Frame for this navigation request is not available, because the request',
|
92
|
+
'was issued before the frame is created. You can check whether the request',
|
93
|
+
'is a navigation request by calling isNavigationRequest() method.',
|
94
|
+
].join('\n').freeze
|
95
|
+
|
96
|
+
def initialize
|
97
|
+
super(MESSAGE)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
89
101
|
def frame
|
90
|
-
ChannelOwners::Frame.from(@initializer['frame'])
|
102
|
+
ChannelOwners::Frame.from(@initializer['frame']).tap do |result|
|
103
|
+
unless result.page
|
104
|
+
raise FramePageNotReadyError.new
|
105
|
+
end
|
106
|
+
end
|
91
107
|
end
|
92
108
|
|
93
109
|
def navigation_request?
|
@@ -111,7 +111,7 @@ module Playwright
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def fetch(headers: nil, method: nil, postData: nil, url: nil, maxRedirects: nil, timeout: nil)
|
114
|
-
api_request_context =
|
114
|
+
api_request_context = @context.request
|
115
115
|
api_request_context.send(:_inner_fetch,
|
116
116
|
request,
|
117
117
|
url,
|
@@ -172,5 +172,9 @@ module Playwright
|
|
172
172
|
mime_types = MIME::Types.type_for(filepath)
|
173
173
|
mime_types.first.to_s || 'application/octet-stream'
|
174
174
|
end
|
175
|
+
|
176
|
+
private def update_context(context)
|
177
|
+
@context = context
|
178
|
+
end
|
175
179
|
end
|
176
180
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Playwright
|
2
|
+
define_api_implementation :ConsoleMessageImpl do
|
3
|
+
def initialize(event)
|
4
|
+
@event = event
|
5
|
+
end
|
6
|
+
|
7
|
+
def page
|
8
|
+
@page ||= ChannelOwners::Page.from_nullable(@event['page'])
|
9
|
+
end
|
10
|
+
|
11
|
+
def type
|
12
|
+
@event['type']
|
13
|
+
end
|
14
|
+
|
15
|
+
def text
|
16
|
+
@event['text']
|
17
|
+
end
|
18
|
+
|
19
|
+
def args
|
20
|
+
@event['args']&.map do |arg|
|
21
|
+
ChannelOwner.from(arg)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def location
|
26
|
+
@event['location']
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|