playwright-ruby-client 1.18.3 → 1.20.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 +1 -1
- data/documentation/docs/api/api_request_context.md +11 -1
- data/documentation/docs/api/element_handle.md +2 -0
- data/documentation/docs/api/experimental/android.md +1 -1
- data/documentation/docs/api/frame.md +1 -1
- data/documentation/docs/api/frame_locator.md +1 -1
- data/documentation/docs/api/locator.md +21 -2
- data/documentation/docs/api/page.md +11 -4
- data/documentation/docs/api/route.md +1 -0
- data/documentation/docs/api/tracing.md +6 -1
- data/documentation/docs/article/guides/playwright_on_alpine_linux.md +5 -5
- data/documentation/docs/include/api_coverage.md +2 -0
- data/lib/playwright/api_response_impl.rb +4 -0
- data/lib/playwright/channel_owner.rb +4 -0
- data/lib/playwright/channel_owners/android.rb +2 -2
- data/lib/playwright/channel_owners/api_request_context.rb +4 -0
- data/lib/playwright/channel_owners/browser_context.rb +10 -9
- data/lib/playwright/channel_owners/element_handle.rb +8 -0
- data/lib/playwright/channel_owners/frame.rb +6 -2
- data/lib/playwright/channel_owners/page.rb +19 -5
- data/lib/playwright/channel_owners/route.rb +18 -4
- data/lib/playwright/{tracing_impl.rb → channel_owners/tracing.rb} +4 -8
- data/lib/playwright/frame_locator_impl.rb +2 -1
- data/lib/playwright/locator_impl.rb +57 -15
- data/lib/playwright/route_handler.rb +11 -8
- data/lib/playwright/version.rb +2 -2
- data/lib/playwright_api/android.rb +2 -2
- data/lib/playwright_api/api_request_context.rb +2 -2
- data/lib/playwright_api/element_handle.rb +3 -1
- data/lib/playwright_api/frame.rb +7 -2
- data/lib/playwright_api/frame_locator.rb +2 -2
- data/lib/playwright_api/locator.rb +17 -4
- data/lib/playwright_api/page.rb +14 -11
- data/lib/playwright_api/route.rb +2 -1
- data/lib/playwright_api/tracing.rb +29 -2
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4fa3fb99ecc1273e529e04b47bebf13546ecfcfc930b10b14c5fe3d0816af724
|
4
|
+
data.tar.gz: 6c74c799eccc9cf4c0c7dd120e10cdd0bfdc8dbd3e23713d2a0842fc53edb6f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bcf0cf470b95f65380b584a3f6d4489be51f5479d23695ca8f6dd16549df1d9a4af07b112a5e5ca779d7915b86cd77b5644becea1b58fdddf527638e547734e3
|
7
|
+
data.tar.gz: 389a1c2b5e73fa6cd62703d487b864af1135822aaeaebeedcef24a6911c23cdd4f39e4353ea3d36a7ca367b5ae4fe8d88b65eb98336bd2a4afcfe5740dea3866
|
data/README.md
CHANGED
@@ -162,7 +162,7 @@ If your environment doesn't accept installing browser or creating browser proces
|
|
162
162
|
For launching Playwright server, just execute:
|
163
163
|
|
164
164
|
```
|
165
|
-
npx playwright install && npx playwright run-server 8080
|
165
|
+
npx playwright install && npx playwright run-server --port 8080
|
166
166
|
```
|
167
167
|
|
168
168
|
and we can connect to the server with the code like this:
|
@@ -28,7 +28,17 @@ playwright.chromium.launch do |browser|
|
|
28
28
|
data: { name: 'test-repo-1' },
|
29
29
|
)
|
30
30
|
response.ok? # => true
|
31
|
-
response.json['name'] # => "
|
31
|
+
response.json['name'] # => "test-repo-1"
|
32
|
+
|
33
|
+
# Delete a repository.
|
34
|
+
response = api_request_context.delete(
|
35
|
+
"/repos/YourName/test-repo-1",
|
36
|
+
headers: {
|
37
|
+
"Accept": "application/vnd.github.v3+json",
|
38
|
+
"Authorization": "Bearer #{API_TOKEN}",
|
39
|
+
},
|
40
|
+
)
|
41
|
+
response.ok? # => true
|
32
42
|
end
|
33
43
|
```
|
34
44
|
|
@@ -549,7 +549,7 @@ considered not visible.
|
|
549
549
|
## locator
|
550
550
|
|
551
551
|
```
|
552
|
-
def locator(selector, hasText: nil)
|
552
|
+
def locator(selector, has: nil, hasText: nil)
|
553
553
|
```
|
554
554
|
|
555
555
|
The method returns an element locator that can be used to perform actions in the frame. Locator is resolved to the
|
@@ -311,7 +311,7 @@ When working with iframes, you can create a frame locator that will enter the if
|
|
311
311
|
that iframe:
|
312
312
|
|
313
313
|
```ruby
|
314
|
-
locator = page.frame_locator("
|
314
|
+
locator = page.frame_locator("iframe").locator("text=Submit")
|
315
315
|
locator.click
|
316
316
|
```
|
317
317
|
|
@@ -325,6 +325,15 @@ def get_attribute(name, timeout: nil)
|
|
325
325
|
|
326
326
|
Returns element attribute value.
|
327
327
|
|
328
|
+
## highlight
|
329
|
+
|
330
|
+
```
|
331
|
+
def highlight
|
332
|
+
```
|
333
|
+
|
334
|
+
Highlight the corresponding element(s) on the screen. Useful for debugging, don't commit the code that uses
|
335
|
+
[Locator#highlight](./locator#highlight).
|
336
|
+
|
328
337
|
## hover
|
329
338
|
|
330
339
|
```
|
@@ -430,7 +439,7 @@ Returns locator to the last matching element.
|
|
430
439
|
## locator
|
431
440
|
|
432
441
|
```
|
433
|
-
def locator(selector, hasText: nil)
|
442
|
+
def locator(selector, has: nil, hasText: nil)
|
434
443
|
```
|
435
444
|
|
436
445
|
The method finds an element matching the specified selector in the [Locator](./locator)'s subtree.
|
@@ -443,6 +452,14 @@ def nth(index)
|
|
443
452
|
|
444
453
|
Returns locator to the n-th matching element.
|
445
454
|
|
455
|
+
## page
|
456
|
+
|
457
|
+
```
|
458
|
+
def page
|
459
|
+
```
|
460
|
+
|
461
|
+
A page this locator belongs to.
|
462
|
+
|
446
463
|
## press
|
447
464
|
|
448
465
|
```
|
@@ -472,6 +489,8 @@ modifier, modifier is pressed and being held while the subsequent key is being p
|
|
472
489
|
|
473
490
|
```
|
474
491
|
def screenshot(
|
492
|
+
animations: nil,
|
493
|
+
mask: nil,
|
475
494
|
omitBackground: nil,
|
476
495
|
path: nil,
|
477
496
|
quality: nil,
|
@@ -774,7 +774,7 @@ considered not visible.
|
|
774
774
|
## locator
|
775
775
|
|
776
776
|
```
|
777
|
-
def locator(selector, hasText: nil)
|
777
|
+
def locator(selector, has: nil, hasText: nil)
|
778
778
|
```
|
779
779
|
|
780
780
|
The method returns an element locator that can be used to perform actions on the page. Locator is resolved to the
|
@@ -1012,8 +1012,10 @@ To remove a route with its handler you can use [Page#unroute](./page#unroute).
|
|
1012
1012
|
|
1013
1013
|
```
|
1014
1014
|
def screenshot(
|
1015
|
+
animations: nil,
|
1015
1016
|
clip: nil,
|
1016
1017
|
fullPage: nil,
|
1018
|
+
mask: nil,
|
1017
1019
|
omitBackground: nil,
|
1018
1020
|
path: nil,
|
1019
1021
|
quality: nil,
|
@@ -1167,9 +1169,10 @@ alias: `viewport_size=`
|
|
1167
1169
|
In the case of multiple pages in a single browser, each page can have its own viewport size. However,
|
1168
1170
|
[Browser#new_context](./browser#new_context) allows to set viewport size (and more) for all pages in the context at once.
|
1169
1171
|
|
1170
|
-
|
1171
|
-
viewport size before navigating to the page. [Page#set_viewport_size](./page#set_viewport_size) will also reset `screen`
|
1172
|
-
[Browser#new_context](./browser#new_context) with `screen` and `viewport` parameters if you need better control of these
|
1172
|
+
[Page#set_viewport_size](./page#set_viewport_size) will resize the page. A lot of websites don't expect phones to change size, so you
|
1173
|
+
should set the viewport size before navigating to the page. [Page#set_viewport_size](./page#set_viewport_size) will also reset `screen`
|
1174
|
+
size, use [Browser#new_context](./browser#new_context) with `screen` and `viewport` parameters if you need better control of these
|
1175
|
+
properties.
|
1173
1176
|
|
1174
1177
|
```ruby
|
1175
1178
|
page.viewport_size = { width: 640, height: 480 }
|
@@ -1491,6 +1494,9 @@ response = page.expect_response(/example.com\/resource/) do
|
|
1491
1494
|
page.click("input")
|
1492
1495
|
end
|
1493
1496
|
puts response.body
|
1497
|
+
puts response.ok?
|
1498
|
+
|
1499
|
+
page.wait_for_load_state # wait for request finished.
|
1494
1500
|
|
1495
1501
|
# or with a predicate
|
1496
1502
|
page.content = '<form action="https://example.com/resource"><input type="submit" /></form>'
|
@@ -1498,6 +1504,7 @@ response = page.expect_response(->(res) { res.url.start_with? 'https://example.c
|
|
1498
1504
|
page.click("input")
|
1499
1505
|
end
|
1500
1506
|
puts response.body
|
1507
|
+
puts response.ok?
|
1501
1508
|
```
|
1502
1509
|
|
1503
1510
|
|
@@ -27,7 +27,7 @@ This article introduces a way to separate environments into client (for executin
|
|
27
27
|
|
28
28
|
## Overview
|
29
29
|
|
30
|
-
|
30
|
+
Playwright Ruby client is running on Alpine Linux. It just sends/receives JSON messages of Playwright-protocol via WebSocket.
|
31
31
|
|
32
32
|
Playwright server is running on a container of [official Docker image](https://hub.docker.com/_/microsoft-playwright). It just operates browsers in response to the JSON messages from WebSocket.
|
33
33
|
|
@@ -69,7 +69,7 @@ end
|
|
69
69
|
|
70
70
|
### Server code
|
71
71
|
|
72
|
-
With the [official Docker image](https://hub.docker.com/_/microsoft-playwright) or in the local development environment with Node.js, just execute `npx playwright install && npx playwright run-server $PORT`. (`$PORT` is a port number of the server)
|
72
|
+
With the [official Docker image](https://hub.docker.com/_/microsoft-playwright) or in the local development environment with Node.js, just execute `npx playwright install && npx playwright run-server --port $PORT --path /ws`. (`$PORT` is a port number of the server)
|
73
73
|
|
74
74
|
If custom Docker image is preferred, build it as follows:
|
75
75
|
|
@@ -80,7 +80,7 @@ WORKDIR /root
|
|
80
80
|
RUN npm install playwright@1.12.3 && ./node_modules/.bin/playwright install
|
81
81
|
|
82
82
|
ENV PORT 8888
|
83
|
-
CMD ["./node_modules/.bin/playwright", "run-server", "$PORT"]
|
83
|
+
CMD ["./node_modules/.bin/playwright", "run-server", "--port", "$PORT", "--path", "/ws"]
|
84
84
|
```
|
85
85
|
|
86
86
|
## Browser server/client
|
@@ -100,7 +100,7 @@ end
|
|
100
100
|
|
101
101
|
### Server code
|
102
102
|
|
103
|
-
For instant use, `npx playwright launch-server chromium` generates a WebSocket endpoint URL with a random path.
|
103
|
+
For instant use, `npx playwright launch-server --browser chromium` generates a WebSocket endpoint URL with a random path.
|
104
104
|
|
105
105
|
More customization can be done by implementing JavaScript server like below:
|
106
106
|
|
@@ -138,7 +138,7 @@ DEBUG=1 bundle exec ruby some-automation-with-playwright.rb
|
|
138
138
|
Just set an environment variable `DEBUG=pw:*` or `DEBUG=pw:server`
|
139
139
|
|
140
140
|
```
|
141
|
-
DEBUG=pw:* npx playwright run-server 8888
|
141
|
+
DEBUG=pw:* npx playwright run-server --port 8888 --path /ws
|
142
142
|
```
|
143
143
|
|
144
144
|
See [the official documentation](https://playwright.dev/docs/debug/#verbose-api-logs) for details.
|
@@ -417,6 +417,7 @@
|
|
417
417
|
* focus
|
418
418
|
* frame_locator
|
419
419
|
* get_attribute
|
420
|
+
* highlight
|
420
421
|
* hover
|
421
422
|
* inner_html
|
422
423
|
* inner_text
|
@@ -430,6 +431,7 @@
|
|
430
431
|
* last
|
431
432
|
* locator
|
432
433
|
* nth
|
434
|
+
* page
|
433
435
|
* press
|
434
436
|
* screenshot
|
435
437
|
* scroll_into_view_if_needed
|
@@ -72,6 +72,10 @@ module Playwright
|
|
72
72
|
private def delete_object_from_child(guid)
|
73
73
|
@objects.delete(guid)
|
74
74
|
end
|
75
|
+
|
76
|
+
private def same_connection?(other)
|
77
|
+
@connection == other.instance_variable_get(:@connection)
|
78
|
+
end
|
75
79
|
end
|
76
80
|
|
77
81
|
class RootChannelOwner < ChannelOwner
|
@@ -4,8 +4,8 @@ module Playwright
|
|
4
4
|
@timeout_settings = TimeoutSettings.new
|
5
5
|
end
|
6
6
|
|
7
|
-
def devices
|
8
|
-
resp = @channel.send_message_to_server('devices')
|
7
|
+
def devices(port: nil)
|
8
|
+
resp = @channel.send_message_to_server('devices', port: port)
|
9
9
|
resp.map { |device| ChannelOwners::AndroidDevice.from(device) }
|
10
10
|
end
|
11
11
|
end
|
@@ -14,7 +14,7 @@ module Playwright
|
|
14
14
|
@service_workers = Set.new
|
15
15
|
@background_pages = Set.new
|
16
16
|
|
17
|
-
@tracing =
|
17
|
+
@tracing = ChannelOwners::Tracing.from(@initializer['tracing'])
|
18
18
|
@request = ChannelOwners::APIRequestContext.from(@initializer['APIRequestContext'])
|
19
19
|
|
20
20
|
@channel.on('bindingCall', ->(params) { on_binding(ChannelOwners::BindingCall.from(params['binding'])) })
|
@@ -72,13 +72,19 @@ module Playwright
|
|
72
72
|
wrapped_route = PlaywrightApi.wrap(route)
|
73
73
|
wrapped_request = PlaywrightApi.wrap(request)
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
|
75
|
+
handler_entry = @routes.find do |entry|
|
76
|
+
entry.match?(request.url)
|
77
|
+
end
|
78
|
+
|
79
|
+
if handler_entry
|
80
|
+
handler_entry.async_handle(wrapped_route, wrapped_request)
|
81
|
+
|
78
82
|
@routes.reject!(&:expired?)
|
79
83
|
if @routes.count == 0
|
80
84
|
@channel.async_send_message_to_server('setNetworkInterceptionEnabled', enabled: false)
|
81
85
|
end
|
86
|
+
else
|
87
|
+
route.continue
|
82
88
|
end
|
83
89
|
end
|
84
90
|
|
@@ -360,10 +366,5 @@ module Playwright
|
|
360
366
|
private def base_url
|
361
367
|
@options[:baseURL]
|
362
368
|
end
|
363
|
-
|
364
|
-
# called from Tracing
|
365
|
-
private def remote_connection?
|
366
|
-
@connection.remote?
|
367
|
-
end
|
368
369
|
end
|
369
370
|
end
|
@@ -281,6 +281,8 @@ module Playwright
|
|
281
281
|
end
|
282
282
|
|
283
283
|
def screenshot(
|
284
|
+
animations: nil,
|
285
|
+
mask: nil,
|
284
286
|
omitBackground: nil,
|
285
287
|
path: nil,
|
286
288
|
quality: nil,
|
@@ -288,12 +290,18 @@ module Playwright
|
|
288
290
|
type: nil)
|
289
291
|
|
290
292
|
params = {
|
293
|
+
animations: animations,
|
291
294
|
omitBackground: omitBackground,
|
292
295
|
path: path,
|
293
296
|
quality: quality,
|
294
297
|
timeout: timeout,
|
295
298
|
type: type,
|
296
299
|
}.compact
|
300
|
+
if mask.is_a?(Enumerable)
|
301
|
+
params[:mask] = mask.map do |locator|
|
302
|
+
locator.send(:to_protocol)
|
303
|
+
end
|
304
|
+
end
|
297
305
|
encoded_binary = @channel.send_message_to_server('screenshot', params)
|
298
306
|
decoded_binary = Base64.strict_decode64(encoded_binary)
|
299
307
|
if path
|
@@ -400,8 +400,8 @@ module Playwright
|
|
400
400
|
nil
|
401
401
|
end
|
402
402
|
|
403
|
-
def locator(selector, hasText: nil)
|
404
|
-
LocatorImpl.new(frame: self, timeout_settings: @page.send(:timeout_settings), selector: selector, hasText: hasText)
|
403
|
+
def locator(selector, hasText: nil, has: nil)
|
404
|
+
LocatorImpl.new(frame: self, timeout_settings: @page.send(:timeout_settings), selector: selector, hasText: hasText, has: has)
|
405
405
|
end
|
406
406
|
|
407
407
|
def frame_locator(selector)
|
@@ -615,6 +615,10 @@ module Playwright
|
|
615
615
|
@channel.send_message_to_server('title')
|
616
616
|
end
|
617
617
|
|
618
|
+
def highlight(selector)
|
619
|
+
@channel.send_message_to_server('highlight', selector: selector)
|
620
|
+
end
|
621
|
+
|
618
622
|
# @param page [Page]
|
619
623
|
# @note This method should be used internally. Accessed via .send method, so keep private!
|
620
624
|
private def update_page_from_page(page)
|
@@ -98,13 +98,19 @@ module Playwright
|
|
98
98
|
wrapped_route = PlaywrightApi.wrap(route)
|
99
99
|
wrapped_request = PlaywrightApi.wrap(request)
|
100
100
|
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
handler_entry = @routes.find do |entry|
|
102
|
+
entry.match?(request.url)
|
103
|
+
end
|
104
|
+
|
105
|
+
if handler_entry
|
106
|
+
handler_entry.async_handle(wrapped_route, wrapped_request)
|
107
|
+
|
104
108
|
@routes.reject!(&:expired?)
|
105
109
|
if @routes.count == 0
|
106
110
|
@channel.async_send_message_to_server('setNetworkInterceptionEnabled', enabled: false)
|
107
111
|
end
|
112
|
+
else
|
113
|
+
@browser_context.send(:on_route, route, request)
|
108
114
|
end
|
109
115
|
end
|
110
116
|
|
@@ -408,6 +414,8 @@ module Playwright
|
|
408
414
|
fullPage: nil,
|
409
415
|
clip: nil,
|
410
416
|
omitBackground: nil,
|
417
|
+
animations: nil,
|
418
|
+
mask: nil,
|
411
419
|
timeout: nil)
|
412
420
|
|
413
421
|
params = {
|
@@ -416,8 +424,14 @@ module Playwright
|
|
416
424
|
fullPage: fullPage,
|
417
425
|
clip: clip,
|
418
426
|
omitBackground: omitBackground,
|
427
|
+
animations: animations,
|
419
428
|
timeout: timeout,
|
420
429
|
}.compact
|
430
|
+
if mask.is_a?(Enumerable)
|
431
|
+
params[:mask] = mask.map do |locator|
|
432
|
+
locator.send(:to_protocol)
|
433
|
+
end
|
434
|
+
end
|
421
435
|
encoded_binary = @channel.send_message_to_server('screenshot', params)
|
422
436
|
decoded_binary = Base64.strict_decode64(encoded_binary)
|
423
437
|
if path
|
@@ -558,8 +572,8 @@ module Playwright
|
|
558
572
|
timeout: timeout)
|
559
573
|
end
|
560
574
|
|
561
|
-
def locator(selector, hasText: nil)
|
562
|
-
@main_frame.locator(selector, hasText: hasText)
|
575
|
+
def locator(selector, hasText: nil, has: nil)
|
576
|
+
@main_frame.locator(selector, hasText: hasText, has: has)
|
563
577
|
end
|
564
578
|
|
565
579
|
def frame_locator(selector)
|
@@ -17,16 +17,30 @@ module Playwright
|
|
17
17
|
contentType: nil,
|
18
18
|
headers: nil,
|
19
19
|
path: nil,
|
20
|
-
status: nil
|
20
|
+
status: nil,
|
21
|
+
response: nil)
|
21
22
|
params = {
|
22
23
|
contentType: contentType,
|
23
24
|
status: status,
|
24
25
|
}.compact
|
26
|
+
option_body = body
|
27
|
+
|
28
|
+
if response
|
29
|
+
params[:status] ||= response.status
|
30
|
+
params[:headers] ||= response.headers
|
31
|
+
|
32
|
+
if !body && !path && response.is_a?(APIResponse)
|
33
|
+
if response.send(:_request).send(:same_connection?, self)
|
34
|
+
params[:fetchResponseUid] = response.send(:fetch_uid)
|
35
|
+
else
|
36
|
+
option_body = response.body
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
25
40
|
|
26
|
-
length = 0
|
27
41
|
content =
|
28
|
-
if
|
29
|
-
|
42
|
+
if option_body
|
43
|
+
option_body
|
30
44
|
elsif path
|
31
45
|
File.read(path)
|
32
46
|
else
|
@@ -1,15 +1,11 @@
|
|
1
1
|
module Playwright
|
2
|
-
|
3
|
-
def
|
4
|
-
@channel = channel
|
5
|
-
@context = context
|
6
|
-
end
|
7
|
-
|
8
|
-
def start(name: nil, title: nil, screenshots: nil, snapshots: nil)
|
2
|
+
define_channel_owner :Tracing do
|
3
|
+
def start(name: nil, title: nil, screenshots: nil, snapshots: nil, sources: nil)
|
9
4
|
params = {
|
10
5
|
name: name,
|
11
6
|
screenshots: screenshots,
|
12
7
|
snapshots: snapshots,
|
8
|
+
sources: sources,
|
13
9
|
}.compact
|
14
10
|
@channel.send_message_to_server('tracingStart', params)
|
15
11
|
@channel.send_message_to_server('tracingStartChunk', { title: title }.compact)
|
@@ -31,7 +27,7 @@ module Playwright
|
|
31
27
|
private def do_stop_chunk(file_path:)
|
32
28
|
mode = 'doNotSave'
|
33
29
|
if file_path
|
34
|
-
if @
|
30
|
+
if @connection.remote?
|
35
31
|
mode = 'compressTrace'
|
36
32
|
else
|
37
33
|
mode = 'compressTraceAndSources'
|
@@ -6,12 +6,13 @@ module Playwright
|
|
6
6
|
@frame_selector = frame_selector
|
7
7
|
end
|
8
8
|
|
9
|
-
def locator(selector, hasText: nil)
|
9
|
+
def locator(selector, hasText: nil, has: nil)
|
10
10
|
LocatorImpl.new(
|
11
11
|
frame: @frame,
|
12
12
|
timeout_settings: @timeout_settings,
|
13
13
|
selector: "#{@frame_selector} >> control=enter-frame >> #{selector}",
|
14
14
|
hasText: hasText,
|
15
|
+
has: has,
|
15
16
|
)
|
16
17
|
end
|
17
18
|
|
@@ -24,29 +24,58 @@ module Playwright
|
|
24
24
|
end
|
25
25
|
|
26
26
|
define_api_implementation :LocatorImpl do
|
27
|
-
def initialize(frame:, timeout_settings:, selector:, hasText: nil)
|
27
|
+
def initialize(frame:, timeout_settings:, selector:, hasText: nil, has: nil)
|
28
28
|
@frame = frame
|
29
29
|
@timeout_settings = timeout_settings
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
30
|
+
selector_scopes = [selector]
|
31
|
+
|
32
|
+
case hasText
|
33
|
+
when Regexp
|
34
|
+
source = EscapeWithQuotes.new(hasText.source, '"')
|
35
|
+
flags = []
|
36
|
+
flags << 'ms' if (hasText.options & Regexp::MULTILINE) != 0
|
37
|
+
flags << 'i' if (hasText.options & Regexp::IGNORECASE) != 0
|
38
|
+
selector_scopes << ":scope:text-matches(#{source}, \"#{flags.join('')}\")"
|
39
|
+
when String
|
40
|
+
text = EscapeWithQuotes.new(hasText, '"')
|
41
|
+
selector_scopes << ":scope:has-text(#{text})"
|
42
|
+
end
|
43
|
+
|
44
|
+
if has
|
45
|
+
unless same_frame?(has)
|
46
|
+
raise DifferentFrameError.new
|
43
47
|
end
|
48
|
+
selector_scopes << "has=#{has.send(:selector_json)}"
|
49
|
+
end
|
50
|
+
|
51
|
+
@selector = selector_scopes.join(' >> ')
|
44
52
|
end
|
45
53
|
|
46
54
|
def to_s
|
47
55
|
"Locator@#{@selector}"
|
48
56
|
end
|
49
57
|
|
58
|
+
private def to_protocol
|
59
|
+
{
|
60
|
+
frame: @frame.channel,
|
61
|
+
selector: @selector,
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
class DifferentFrameError < StandardError
|
66
|
+
def initialize
|
67
|
+
super('Inner "has" locator must belong to the same frame.')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private def same_frame?(other)
|
72
|
+
@frame == other.instance_variable_get(:@frame)
|
73
|
+
end
|
74
|
+
|
75
|
+
private def selector_json
|
76
|
+
@selector.to_json
|
77
|
+
end
|
78
|
+
|
50
79
|
private def with_element(timeout: nil, &block)
|
51
80
|
timeout_or_default = @timeout_settings.timeout(timeout)
|
52
81
|
start_time = Time.now
|
@@ -67,6 +96,10 @@ module Playwright
|
|
67
96
|
end
|
68
97
|
end
|
69
98
|
|
99
|
+
def page
|
100
|
+
@frame.page
|
101
|
+
end
|
102
|
+
|
70
103
|
def bounding_box(timeout: nil)
|
71
104
|
with_element(timeout: timeout) do |handle|
|
72
105
|
handle.bounding_box
|
@@ -180,12 +213,13 @@ module Playwright
|
|
180
213
|
@frame.fill(@selector, value, strict: true, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
|
181
214
|
end
|
182
215
|
|
183
|
-
def locator(selector, hasText: nil)
|
216
|
+
def locator(selector, hasText: nil, has: nil)
|
184
217
|
LocatorImpl.new(
|
185
218
|
frame: @frame,
|
186
219
|
timeout_settings: @timeout_settings,
|
187
220
|
selector: "#{@selector} >> #{selector}",
|
188
221
|
hasText: hasText,
|
222
|
+
has: has,
|
189
223
|
)
|
190
224
|
end
|
191
225
|
|
@@ -279,6 +313,8 @@ module Playwright
|
|
279
313
|
end
|
280
314
|
|
281
315
|
def screenshot(
|
316
|
+
animations: nil,
|
317
|
+
mask: nil,
|
282
318
|
omitBackground: nil,
|
283
319
|
path: nil,
|
284
320
|
quality: nil,
|
@@ -286,6 +322,8 @@ module Playwright
|
|
286
322
|
type: nil)
|
287
323
|
with_element(timeout: timeout) do |handle, options|
|
288
324
|
handle.screenshot(
|
325
|
+
animations: animations,
|
326
|
+
mask: mask,
|
289
327
|
omitBackground: omitBackground,
|
290
328
|
path: path,
|
291
329
|
quality: quality,
|
@@ -389,5 +427,9 @@ module Playwright
|
|
389
427
|
def all_text_contents
|
390
428
|
@frame.eval_on_selector_all(@selector, "ee => ee.map(e => e.textContent || '')")
|
391
429
|
end
|
430
|
+
|
431
|
+
def highlight
|
432
|
+
@frame.highlight(@selector)
|
433
|
+
end
|
392
434
|
end
|
393
435
|
end
|
@@ -5,7 +5,7 @@ module Playwright
|
|
5
5
|
@count = count
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
8
|
+
def increment
|
9
9
|
return false if expired?
|
10
10
|
|
11
11
|
@count = @count - 1
|
@@ -18,7 +18,7 @@ module Playwright
|
|
18
18
|
end
|
19
19
|
|
20
20
|
class StubCounter
|
21
|
-
def
|
21
|
+
def increment
|
22
22
|
true
|
23
23
|
end
|
24
24
|
|
@@ -43,14 +43,17 @@ module Playwright
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
def
|
47
|
-
|
46
|
+
def match?(url)
|
47
|
+
@url_matcher.match?(url)
|
48
|
+
end
|
49
|
+
|
50
|
+
def async_handle(route, request)
|
51
|
+
@counter.increment
|
48
52
|
|
49
|
-
|
53
|
+
Concurrent::Promises.future do
|
50
54
|
@handler.call(route, request)
|
51
|
-
|
52
|
-
|
53
|
-
false
|
55
|
+
rescue => err
|
56
|
+
puts err, err.backtrace
|
54
57
|
end
|
55
58
|
end
|
56
59
|
|
data/lib/playwright/version.rb
CHANGED
@@ -26,8 +26,8 @@ module Playwright
|
|
26
26
|
class Android < PlaywrightApi
|
27
27
|
|
28
28
|
# Returns the list of detected Android devices.
|
29
|
-
def devices
|
30
|
-
wrap_impl(@impl.devices)
|
29
|
+
def devices(port: nil)
|
30
|
+
wrap_impl(@impl.devices(port: unwrap_impl(port)))
|
31
31
|
end
|
32
32
|
|
33
33
|
# This setting will change the default maximum time for all the methods accepting `timeout` option.
|
@@ -16,13 +16,13 @@ module Playwright
|
|
16
16
|
# # This will launch a new browser, create a context and page. When making HTTP
|
17
17
|
# # requests with the internal APIRequestContext (e.g. `context.request` or `page.request`)
|
18
18
|
# # it will automatically set the cookies to the browser page and vise versa.
|
19
|
-
# browser =
|
19
|
+
# browser = p.chromium.launch()
|
20
20
|
# context = browser.new_context(base_url="https://api.github.com")
|
21
21
|
# api_request_context = context.request
|
22
22
|
# page = context.new_page()
|
23
23
|
#
|
24
24
|
# # Alternatively you can create a APIRequestContext manually without having a browser context attached:
|
25
|
-
# # api_request_context =
|
25
|
+
# # api_request_context = p.request.new_context(base_url="https://api.github.com")
|
26
26
|
#
|
27
27
|
#
|
28
28
|
# # Create a repository.
|
@@ -346,12 +346,14 @@ module Playwright
|
|
346
346
|
# This method waits for the [actionability](./actionability.md) checks, then scrolls element into view before taking a
|
347
347
|
# screenshot. If the element is detached from DOM, the method throws an error.
|
348
348
|
def screenshot(
|
349
|
+
animations: nil,
|
350
|
+
mask: nil,
|
349
351
|
omitBackground: nil,
|
350
352
|
path: nil,
|
351
353
|
quality: nil,
|
352
354
|
timeout: nil,
|
353
355
|
type: nil)
|
354
|
-
wrap_impl(@impl.screenshot(omitBackground: unwrap_impl(omitBackground), path: unwrap_impl(path), quality: unwrap_impl(quality), timeout: unwrap_impl(timeout), type: unwrap_impl(type)))
|
356
|
+
wrap_impl(@impl.screenshot(animations: unwrap_impl(animations), mask: unwrap_impl(mask), omitBackground: unwrap_impl(omitBackground), path: unwrap_impl(path), quality: unwrap_impl(quality), timeout: unwrap_impl(timeout), type: unwrap_impl(type)))
|
355
357
|
end
|
356
358
|
|
357
359
|
# This method waits for [actionability](./actionability.md) checks, then tries to scroll element into view, unless it is
|
data/lib/playwright_api/frame.rb
CHANGED
@@ -445,8 +445,8 @@ module Playwright
|
|
445
445
|
# The method returns an element locator that can be used to perform actions in the frame. Locator is resolved to the
|
446
446
|
# element immediately before performing an action, so a series of actions on the same locator can in fact be performed on
|
447
447
|
# different DOM elements. That would happen if the DOM structure between those actions has changed.
|
448
|
-
def locator(selector, hasText: nil)
|
449
|
-
wrap_impl(@impl.locator(unwrap_impl(selector), hasText: unwrap_impl(hasText)))
|
448
|
+
def locator(selector, has: nil, hasText: nil)
|
449
|
+
wrap_impl(@impl.locator(unwrap_impl(selector), has: unwrap_impl(has), hasText: unwrap_impl(hasText)))
|
450
450
|
end
|
451
451
|
|
452
452
|
# Returns frame's name attribute as specified in the tag.
|
@@ -788,6 +788,11 @@ module Playwright
|
|
788
788
|
wrap_impl(@impl.detached=(unwrap_impl(req)))
|
789
789
|
end
|
790
790
|
|
791
|
+
# @nodoc
|
792
|
+
def highlight(selector)
|
793
|
+
wrap_impl(@impl.highlight(unwrap_impl(selector)))
|
794
|
+
end
|
795
|
+
|
791
796
|
# -- inherited from EventEmitter --
|
792
797
|
# @nodoc
|
793
798
|
def off(event, callback)
|
@@ -48,8 +48,8 @@ module Playwright
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# The method finds an element matching the specified selector in the FrameLocator's subtree.
|
51
|
-
def locator(selector, hasText: nil)
|
52
|
-
wrap_impl(@impl.locator(unwrap_impl(selector), hasText: unwrap_impl(hasText)))
|
51
|
+
def locator(selector, has: nil, hasText: nil)
|
52
|
+
wrap_impl(@impl.locator(unwrap_impl(selector), has: unwrap_impl(has), hasText: unwrap_impl(hasText)))
|
53
53
|
end
|
54
54
|
|
55
55
|
# Returns locator to the n-th matching frame.
|
@@ -238,7 +238,7 @@ module Playwright
|
|
238
238
|
# that iframe:
|
239
239
|
#
|
240
240
|
# ```python sync
|
241
|
-
# locator = page.frame_locator("
|
241
|
+
# locator = page.frame_locator("iframe").locator("text=Submit")
|
242
242
|
# locator.click()
|
243
243
|
# ```
|
244
244
|
def frame_locator(selector)
|
@@ -250,6 +250,12 @@ module Playwright
|
|
250
250
|
wrap_impl(@impl.get_attribute(unwrap_impl(name), timeout: unwrap_impl(timeout)))
|
251
251
|
end
|
252
252
|
|
253
|
+
# Highlight the corresponding element(s) on the screen. Useful for debugging, don't commit the code that uses
|
254
|
+
# [`method: Locator.highlight`].
|
255
|
+
def highlight
|
256
|
+
wrap_impl(@impl.highlight)
|
257
|
+
end
|
258
|
+
|
253
259
|
# This method hovers over the element by performing the following steps:
|
254
260
|
# 1. Wait for [actionability](./actionability.md) checks on the element, unless `force` option is set.
|
255
261
|
# 1. Scroll the element into view if needed.
|
@@ -320,8 +326,8 @@ module Playwright
|
|
320
326
|
end
|
321
327
|
|
322
328
|
# The method finds an element matching the specified selector in the `Locator`'s subtree.
|
323
|
-
def locator(selector, hasText: nil)
|
324
|
-
wrap_impl(@impl.locator(unwrap_impl(selector), hasText: unwrap_impl(hasText)))
|
329
|
+
def locator(selector, has: nil, hasText: nil)
|
330
|
+
wrap_impl(@impl.locator(unwrap_impl(selector), has: unwrap_impl(has), hasText: unwrap_impl(hasText)))
|
325
331
|
end
|
326
332
|
|
327
333
|
# Returns locator to the n-th matching element.
|
@@ -329,6 +335,11 @@ module Playwright
|
|
329
335
|
wrap_impl(@impl.nth(unwrap_impl(index)))
|
330
336
|
end
|
331
337
|
|
338
|
+
# A page this locator belongs to.
|
339
|
+
def page
|
340
|
+
wrap_impl(@impl.page)
|
341
|
+
end
|
342
|
+
|
332
343
|
# Focuses the element, and then uses [`method: Keyboard.down`] and [`method: Keyboard.up`].
|
333
344
|
#
|
334
345
|
# `key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
|
@@ -356,12 +367,14 @@ module Playwright
|
|
356
367
|
# This method waits for the [actionability](./actionability.md) checks, then scrolls element into view before taking a
|
357
368
|
# screenshot. If the element is detached from DOM, the method throws an error.
|
358
369
|
def screenshot(
|
370
|
+
animations: nil,
|
371
|
+
mask: nil,
|
359
372
|
omitBackground: nil,
|
360
373
|
path: nil,
|
361
374
|
quality: nil,
|
362
375
|
timeout: nil,
|
363
376
|
type: nil)
|
364
|
-
wrap_impl(@impl.screenshot(omitBackground: unwrap_impl(omitBackground), path: unwrap_impl(path), quality: unwrap_impl(quality), timeout: unwrap_impl(timeout), type: unwrap_impl(type)))
|
377
|
+
wrap_impl(@impl.screenshot(animations: unwrap_impl(animations), mask: unwrap_impl(mask), omitBackground: unwrap_impl(omitBackground), path: unwrap_impl(path), quality: unwrap_impl(quality), timeout: unwrap_impl(timeout), type: unwrap_impl(type)))
|
365
378
|
end
|
366
379
|
|
367
380
|
# This method waits for [actionability](./actionability.md) checks, then tries to scroll element into view, unless it is
|
data/lib/playwright_api/page.rb
CHANGED
@@ -686,8 +686,8 @@ module Playwright
|
|
686
686
|
# different DOM elements. That would happen if the DOM structure between those actions has changed.
|
687
687
|
#
|
688
688
|
# Shortcut for main frame's [`method: Frame.locator`].
|
689
|
-
def locator(selector, hasText: nil)
|
690
|
-
wrap_impl(@impl.locator(unwrap_impl(selector), hasText: unwrap_impl(hasText)))
|
689
|
+
def locator(selector, has: nil, hasText: nil)
|
690
|
+
wrap_impl(@impl.locator(unwrap_impl(selector), has: unwrap_impl(has), hasText: unwrap_impl(hasText)))
|
691
691
|
end
|
692
692
|
|
693
693
|
# The page's main frame. Page is guaranteed to have a main frame which persists during navigations.
|
@@ -891,14 +891,16 @@ module Playwright
|
|
891
891
|
|
892
892
|
# Returns the buffer with the captured screenshot.
|
893
893
|
def screenshot(
|
894
|
+
animations: nil,
|
894
895
|
clip: nil,
|
895
896
|
fullPage: nil,
|
897
|
+
mask: nil,
|
896
898
|
omitBackground: nil,
|
897
899
|
path: nil,
|
898
900
|
quality: nil,
|
899
901
|
timeout: nil,
|
900
902
|
type: nil)
|
901
|
-
wrap_impl(@impl.screenshot(clip: unwrap_impl(clip), fullPage: unwrap_impl(fullPage), omitBackground: unwrap_impl(omitBackground), path: unwrap_impl(path), quality: unwrap_impl(quality), timeout: unwrap_impl(timeout), type: unwrap_impl(type)))
|
903
|
+
wrap_impl(@impl.screenshot(animations: unwrap_impl(animations), clip: unwrap_impl(clip), fullPage: unwrap_impl(fullPage), mask: unwrap_impl(mask), omitBackground: unwrap_impl(omitBackground), path: unwrap_impl(path), quality: unwrap_impl(quality), timeout: unwrap_impl(timeout), type: unwrap_impl(type)))
|
902
904
|
end
|
903
905
|
|
904
906
|
# This method waits for an element matching `selector`, waits for [actionability](./actionability.md) checks, waits until
|
@@ -1016,9 +1018,10 @@ module Playwright
|
|
1016
1018
|
# In the case of multiple pages in a single browser, each page can have its own viewport size. However,
|
1017
1019
|
# [`method: Browser.newContext`] allows to set viewport size (and more) for all pages in the context at once.
|
1018
1020
|
#
|
1019
|
-
# `
|
1020
|
-
# viewport size before navigating to the page. [`method: Page.setViewportSize`] will also reset `screen`
|
1021
|
-
# [`method: Browser.newContext`] with `screen` and `viewport` parameters if you need better control of these
|
1021
|
+
# [`method: Page.setViewportSize`] will resize the page. A lot of websites don't expect phones to change size, so you
|
1022
|
+
# should set the viewport size before navigating to the page. [`method: Page.setViewportSize`] will also reset `screen`
|
1023
|
+
# size, use [`method: Browser.newContext`] with `screen` and `viewport` parameters if you need better control of these
|
1024
|
+
# properties.
|
1022
1025
|
#
|
1023
1026
|
# ```python sync
|
1024
1027
|
# page = browser.new_page()
|
@@ -1282,7 +1285,7 @@ module Playwright
|
|
1282
1285
|
# return response.ok
|
1283
1286
|
#
|
1284
1287
|
# # or with a lambda
|
1285
|
-
# with page.expect_response(lambda response: response.url == "https://example.com" and response.status
|
1288
|
+
# with page.expect_response(lambda response: response.url == "https://example.com" and response.status == 200) as response_info:
|
1286
1289
|
# page.click("input")
|
1287
1290
|
# response = response_info.value
|
1288
1291
|
# return response.ok
|
@@ -1392,8 +1395,8 @@ module Playwright
|
|
1392
1395
|
end
|
1393
1396
|
|
1394
1397
|
# @nodoc
|
1395
|
-
def
|
1396
|
-
wrap_impl(@impl.
|
1398
|
+
def start_css_coverage(resetOnNavigation: nil, reportAnonymousScripts: nil)
|
1399
|
+
wrap_impl(@impl.start_css_coverage(resetOnNavigation: unwrap_impl(resetOnNavigation), reportAnonymousScripts: unwrap_impl(reportAnonymousScripts)))
|
1397
1400
|
end
|
1398
1401
|
|
1399
1402
|
# @nodoc
|
@@ -1402,8 +1405,8 @@ module Playwright
|
|
1402
1405
|
end
|
1403
1406
|
|
1404
1407
|
# @nodoc
|
1405
|
-
def
|
1406
|
-
wrap_impl(@impl.
|
1408
|
+
def stop_css_coverage
|
1409
|
+
wrap_impl(@impl.stop_css_coverage)
|
1407
1410
|
end
|
1408
1411
|
|
1409
1412
|
# @nodoc
|
data/lib/playwright_api/route.rb
CHANGED
@@ -47,8 +47,9 @@ module Playwright
|
|
47
47
|
contentType: nil,
|
48
48
|
headers: nil,
|
49
49
|
path: nil,
|
50
|
+
response: nil,
|
50
51
|
status: nil)
|
51
|
-
wrap_impl(@impl.fulfill(body: unwrap_impl(body), contentType: unwrap_impl(contentType), headers: unwrap_impl(headers), path: unwrap_impl(path), status: unwrap_impl(status)))
|
52
|
+
wrap_impl(@impl.fulfill(body: unwrap_impl(body), contentType: unwrap_impl(contentType), headers: unwrap_impl(headers), path: unwrap_impl(path), response: unwrap_impl(response), status: unwrap_impl(status)))
|
52
53
|
end
|
53
54
|
|
54
55
|
# A request to be routed.
|
@@ -22,8 +22,13 @@ module Playwright
|
|
22
22
|
# page.goto("https://playwright.dev")
|
23
23
|
# context.tracing.stop(path = "trace.zip")
|
24
24
|
# ```
|
25
|
-
def start(
|
26
|
-
|
25
|
+
def start(
|
26
|
+
name: nil,
|
27
|
+
screenshots: nil,
|
28
|
+
snapshots: nil,
|
29
|
+
sources: nil,
|
30
|
+
title: nil)
|
31
|
+
wrap_impl(@impl.start(name: unwrap_impl(name), screenshots: unwrap_impl(screenshots), snapshots: unwrap_impl(snapshots), sources: unwrap_impl(sources), title: unwrap_impl(title)))
|
27
32
|
end
|
28
33
|
|
29
34
|
# Start a new trace chunk. If you'd like to record multiple traces on the same `BrowserContext`, use
|
@@ -58,5 +63,27 @@ module Playwright
|
|
58
63
|
def stop_chunk(path: nil)
|
59
64
|
wrap_impl(@impl.stop_chunk(path: unwrap_impl(path)))
|
60
65
|
end
|
66
|
+
|
67
|
+
# -- inherited from EventEmitter --
|
68
|
+
# @nodoc
|
69
|
+
def off(event, callback)
|
70
|
+
event_emitter_proxy.off(event, callback)
|
71
|
+
end
|
72
|
+
|
73
|
+
# -- inherited from EventEmitter --
|
74
|
+
# @nodoc
|
75
|
+
def once(event, callback)
|
76
|
+
event_emitter_proxy.once(event, callback)
|
77
|
+
end
|
78
|
+
|
79
|
+
# -- inherited from EventEmitter --
|
80
|
+
# @nodoc
|
81
|
+
def on(event, callback)
|
82
|
+
event_emitter_proxy.on(event, callback)
|
83
|
+
end
|
84
|
+
|
85
|
+
private def event_emitter_proxy
|
86
|
+
@event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
|
87
|
+
end
|
61
88
|
end
|
62
89
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: playwright-ruby-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.20.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- YusukeIwaki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -304,6 +304,7 @@ files:
|
|
304
304
|
- lib/playwright/channel_owners/route.rb
|
305
305
|
- lib/playwright/channel_owners/selectors.rb
|
306
306
|
- lib/playwright/channel_owners/stream.rb
|
307
|
+
- lib/playwright/channel_owners/tracing.rb
|
307
308
|
- lib/playwright/channel_owners/web_socket.rb
|
308
309
|
- lib/playwright/channel_owners/worker.rb
|
309
310
|
- lib/playwright/connection.rb
|
@@ -329,7 +330,6 @@ files:
|
|
329
330
|
- lib/playwright/select_option_values.rb
|
330
331
|
- lib/playwright/timeout_settings.rb
|
331
332
|
- lib/playwright/touchscreen_impl.rb
|
332
|
-
- lib/playwright/tracing_impl.rb
|
333
333
|
- lib/playwright/transport.rb
|
334
334
|
- lib/playwright/url_matcher.rb
|
335
335
|
- lib/playwright/utils.rb
|
@@ -396,5 +396,5 @@ requirements: []
|
|
396
396
|
rubygems_version: 3.3.7
|
397
397
|
signing_key:
|
398
398
|
specification_version: 4
|
399
|
-
summary: The Ruby binding of playwright driver 1.
|
399
|
+
summary: The Ruby binding of playwright driver 1.20.0
|
400
400
|
test_files: []
|