playwright-ruby-client 1.18.3 → 1.20.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|