playwright-ruby-client 1.61.0 → 1.63.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 +12 -17
- data/documentation/docs/api/api_request_context.md +3 -0
- data/documentation/docs/api/api_response.md +12 -0
- data/documentation/docs/api/browser_context.md +5 -3
- data/documentation/docs/api/browser_type.md +2 -0
- data/documentation/docs/api/credentials.md +6 -2
- data/documentation/docs/api/element_handle.md +7 -0
- data/documentation/docs/api/frame.md +20 -1
- data/documentation/docs/api/frame_locator.md +20 -0
- data/documentation/docs/api/locator.md +57 -0
- data/documentation/docs/api/locator_assertions.md +4 -2
- data/documentation/docs/api/page.md +26 -1
- data/documentation/docs/api/playwright.md +2 -2
- data/documentation/docs/api/tracing.md +3 -1
- data/documentation/docs/article/getting_started.md +12 -11
- data/documentation/docs/article/guides/download_playwright_driver.md +11 -32
- data/documentation/docs/article/guides/launch_browser.md +5 -4
- data/documentation/docs/article/guides/playwright_on_alpine_linux.md +6 -5
- data/documentation/docs/article/guides/rails_integration.md +72 -4
- data/documentation/docs/article/guides/rails_integration_with_null_driver.md +4 -3
- data/documentation/docs/article/guides/semi_automation.md +1 -1
- data/documentation/docs/article/guides/use_storage_state.md +1 -1
- data/documentation/docs/include/api_coverage.md +3 -0
- data/documentation/docusaurus.config.js +31 -0
- data/documentation/package.json +3 -0
- data/documentation/yarn.lock +159 -174
- data/lib/playwright/api_request_impl.rb +3 -1
- data/lib/playwright/api_response_impl.rb +16 -0
- data/lib/playwright/channel.rb +2 -1
- data/lib/playwright/channel_owners/browser.rb +1 -0
- data/lib/playwright/channel_owners/browser_context.rb +22 -3
- data/lib/playwright/channel_owners/element_handle.rb +14 -4
- data/lib/playwright/channel_owners/frame.rb +16 -2
- data/lib/playwright/channel_owners/page.rb +21 -9
- data/lib/playwright/channel_owners/tracing.rb +43 -13
- data/lib/playwright/connection.rb +9 -1
- data/lib/playwright/events.rb +2 -0
- data/lib/playwright/frame_locator_impl.rb +20 -5
- data/lib/playwright/locator_assertions_impl.rb +14 -1
- data/lib/playwright/locator_impl.rb +32 -5
- data/lib/playwright/screencast.rb +20 -6
- data/lib/playwright/screenshot_utils.rb +24 -0
- data/lib/playwright/test.rb +12 -2
- data/lib/playwright/url_matcher.rb +120 -4
- data/lib/playwright/utils.rb +12 -0
- data/lib/playwright/version.rb +2 -2
- data/lib/playwright.rb +2 -2
- data/lib/playwright_api/api_request_context.rb +3 -1
- data/lib/playwright_api/api_response.rb +9 -0
- data/lib/playwright_api/browser_context.rb +16 -14
- data/lib/playwright_api/browser_type.rb +2 -0
- data/lib/playwright_api/credentials.rb +6 -2
- data/lib/playwright_api/element_handle.rb +14 -7
- data/lib/playwright_api/frame.rb +28 -9
- data/lib/playwright_api/frame_locator.rb +20 -0
- data/lib/playwright_api/locator.rb +64 -13
- data/lib/playwright_api/locator_assertions.rb +6 -4
- data/lib/playwright_api/page.rb +46 -21
- data/lib/playwright_api/tracing.rb +4 -2
- data/playwright.gemspec +5 -0
- data/sig/playwright.rbs +49 -46
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 275e62d0e3c798dd08cdb59a52299af990f93b7fd5fe1cf2a1f9b1c5441a1680
|
|
4
|
+
data.tar.gz: 1711ed5665344b5c52b6f45c2621e03e2ac8983d698e6717303cad3bbb80659b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9180d7ceb51f46c828e8a08aaffdd1e813bc57b842f268556990030a9003686841842cd8d3f5c98ea8b5c2ea3e6fdb63a4ff45afb6e44adb2b2a9a6c7c6ef861
|
|
7
|
+
data.tar.gz: 5efd8cd40f2e8b5d2cf2e22943ae6df4e3791b66874ca3cb0f72bbb66a1bd50442e8e481c990eed9fe958f4bfe82102e58634c5bfd2bc1823a0ff25b16036bbf
|
data/README.md
CHANGED
|
@@ -12,25 +12,22 @@ gem 'playwright-ruby-client'
|
|
|
12
12
|
|
|
13
13
|
and then 'bundle install'.
|
|
14
14
|
|
|
15
|
-
Since playwright-ruby-client doesn't include
|
|
15
|
+
Since playwright-ruby-client doesn't include Playwright, **we have to install Node.js and a compatible version of [playwright-core](https://www.npmjs.com/package/playwright-core) in advance**.
|
|
16
16
|
|
|
17
|
+
```sh
|
|
18
|
+
PLAYWRIGHT_CLI_VERSION=$(bundle exec ruby -e 'require "playwright/version"; puts Playwright::COMPATIBLE_PLAYWRIGHT_VERSION')
|
|
19
|
+
npm install "playwright-core@$PLAYWRIGHT_CLI_VERSION"
|
|
20
|
+
./node_modules/.bin/playwright-core install
|
|
17
21
|
```
|
|
18
|
-
npm install playwright
|
|
19
|
-
./node_modules/.bin/playwright install
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
And set `playwright_cli_executable_path: './node_modules/.bin/playwright'`
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Instead of npm, you can also directly download playwright driver from playwright.azureedge.net/builds/. The URL can be easily detected from [here](https://github.com/microsoft/playwright-python/blob/cb5409934629adaabc0cff1891080de2052fa778/setup.py#L73-L77)
|
|
23
|
+
And set `playwright_cli_executable_path: './node_modules/.bin/playwright-core'`.
|
|
27
24
|
|
|
28
25
|
### Capture a site
|
|
29
26
|
|
|
30
27
|
```ruby
|
|
31
28
|
require 'playwright'
|
|
32
29
|
|
|
33
|
-
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright') do |playwright|
|
|
30
|
+
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright-core') do |playwright|
|
|
34
31
|
playwright.chromium.launch(headless: false) do |browser|
|
|
35
32
|
page = browser.new_page
|
|
36
33
|
page.goto('https://github.com/YusukeIwaki')
|
|
@@ -46,7 +43,7 @@ end
|
|
|
46
43
|
```ruby
|
|
47
44
|
require 'playwright'
|
|
48
45
|
|
|
49
|
-
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright') do |playwright|
|
|
46
|
+
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright-core') do |playwright|
|
|
50
47
|
playwright.chromium.launch(headless: false) do |browser|
|
|
51
48
|
page = browser.new_page
|
|
52
49
|
page.goto('https://github.com/')
|
|
@@ -94,7 +91,7 @@ $ bundle exec ruby main.rb
|
|
|
94
91
|
```ruby
|
|
95
92
|
require 'playwright'
|
|
96
93
|
|
|
97
|
-
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright') do |playwright|
|
|
94
|
+
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright-core') do |playwright|
|
|
98
95
|
devices = playwright.android.devices
|
|
99
96
|
unless devices.empty?
|
|
100
97
|
device = devices.last
|
|
@@ -128,12 +125,10 @@ end
|
|
|
128
125
|
We have to download android-driver for Playwright in advance.
|
|
129
126
|
|
|
130
127
|
```
|
|
131
|
-
wget https://github.com/microsoft/playwright/raw/master/bin/android-driver-target.apk -O /
|
|
132
|
-
wget https://github.com/microsoft/playwright/raw/master/bin/android-driver.apk -O /
|
|
128
|
+
wget https://github.com/microsoft/playwright/raw/master/bin/android-driver-target.apk -O ./node_modules/playwright-core/bin/android-driver-target.apk
|
|
129
|
+
wget https://github.com/microsoft/playwright/raw/master/bin/android-driver.apk -O ./node_modules/playwright-core/bin/android-driver.apk
|
|
133
130
|
```
|
|
134
131
|
|
|
135
|
-
(If you downloaded Playwright via npm, replace `/path/to/playwright-driver/package/` with `./node_modules/playwright/` above.)
|
|
136
|
-
|
|
137
132
|
```ruby
|
|
138
133
|
require 'playwright'
|
|
139
134
|
|
|
@@ -168,7 +163,7 @@ If your environment doesn't accept installing browser or creating browser proces
|
|
|
168
163
|
For launching Playwright server, just execute:
|
|
169
164
|
|
|
170
165
|
```
|
|
171
|
-
|
|
166
|
+
./node_modules/.bin/playwright-core install && ./node_modules/.bin/playwright-core run-server --port 8080 --path /ws
|
|
172
167
|
```
|
|
173
168
|
|
|
174
169
|
and we can connect to the server with the code like this:
|
|
@@ -122,6 +122,18 @@ def text
|
|
|
122
122
|
|
|
123
123
|
Returns the text representation of response body.
|
|
124
124
|
|
|
125
|
+
## timing
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
def timing
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
Returns resource timing information for given response. For redirected requests, returns the information for the last
|
|
133
|
+
request in the redirect chain. When the response is served [from the HAR file](https://playwright.dev/python/docs/mock#replaying-from-har), timing
|
|
134
|
+
information is not available and all the values are -1. Find more information at
|
|
135
|
+
[Resource Timing API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming).
|
|
136
|
+
|
|
125
137
|
## url
|
|
126
138
|
|
|
127
139
|
```
|
|
@@ -434,11 +434,11 @@ alias: `offline=`
|
|
|
434
434
|
## storage_state
|
|
435
435
|
|
|
436
436
|
```
|
|
437
|
-
def storage_state(indexedDB: nil, path: nil)
|
|
437
|
+
def storage_state(credentials: nil, indexedDB: nil, opfs: nil, path: nil)
|
|
438
438
|
```
|
|
439
439
|
|
|
440
440
|
|
|
441
|
-
Returns storage state for this browser context, contains current cookies, local storage snapshot and
|
|
441
|
+
Returns storage state for this browser context, contains current cookies, local storage snapshot, IndexedDB snapshot, origin private file system snapshot and virtual WebAuthn credentials.
|
|
442
442
|
|
|
443
443
|
## set_storage_state
|
|
444
444
|
|
|
@@ -448,7 +448,9 @@ def set_storage_state(storageState)
|
|
|
448
448
|
alias: `storage_state=`
|
|
449
449
|
|
|
450
450
|
|
|
451
|
-
Clears the existing cookies, local storage
|
|
451
|
+
Clears the existing cookies, local storage, IndexedDB entries, origin private file system entries and virtual WebAuthn credentials, and sets the new storage
|
|
452
|
+
state. When the storage state contains credentials, the virtual WebAuthn authenticator is installed (equivalent to
|
|
453
|
+
[Credentials#install](./credentials#install)), preventing all real authenticators from working in this context.
|
|
452
454
|
|
|
453
455
|
**Usage**
|
|
454
456
|
|
|
@@ -59,6 +59,8 @@ The default browser context is accessible via [Browser#contexts](./browser#conte
|
|
|
59
59
|
|
|
60
60
|
**NOTE**: This connection is significantly lower fidelity than the Playwright protocol connection via [BrowserType#connect](./browser_type#connect). If you are experiencing issues or attempting to use advanced functionality, you probably want to use [BrowserType#connect](./browser_type#connect).
|
|
61
61
|
|
|
62
|
+
**NOTE**: Playwright maintains a curated list of arguments for launching the browser. If you launch the browser without Playwright and do not pass the exact same arguments, some of Playwright functionality may be broken upon connecting to the browser.
|
|
63
|
+
|
|
62
64
|
**Usage**
|
|
63
65
|
|
|
64
66
|
```ruby
|
|
@@ -9,7 +9,7 @@ sidebar_position: 10
|
|
|
9
9
|
register passkeys and answer `navigator.credentials.create()` / `navigator.credentials.get()`
|
|
10
10
|
ceremonies in the page, without a real authenticator or hardware security key.
|
|
11
11
|
|
|
12
|
-
There are
|
|
12
|
+
There are three common ways to use it:
|
|
13
13
|
|
|
14
14
|
**Usage: seed a known credential**
|
|
15
15
|
|
|
@@ -31,7 +31,7 @@ page.goto("https://example.com/login")
|
|
|
31
31
|
# The page's navigator.credentials.get() is answered with the seeded passkey.
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
**Usage: capture a
|
|
34
|
+
**Usage: capture a credential, then reuse it**
|
|
35
35
|
|
|
36
36
|
```ruby
|
|
37
37
|
# setup test: let the app register a passkey, then save it.
|
|
@@ -65,6 +65,10 @@ page.goto("https://example.com/login")
|
|
|
65
65
|
# navigator.credentials.get() resolves the captured passkey - already signed in.
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
+
**Usage: save credentials in the storage state, restore later**
|
|
69
|
+
|
|
70
|
+
See [authentication guide](https://playwright.dev/python/docs/auth) for examples of using saving and resotring the storage state.
|
|
71
|
+
|
|
68
72
|
**Defaults**
|
|
69
73
|
|
|
70
74
|
## install
|
|
@@ -75,6 +75,7 @@ def check(
|
|
|
75
75
|
force: nil,
|
|
76
76
|
noWaitAfter: nil,
|
|
77
77
|
position: nil,
|
|
78
|
+
scroll: nil,
|
|
78
79
|
timeout: nil,
|
|
79
80
|
trial: nil)
|
|
80
81
|
```
|
|
@@ -103,6 +104,7 @@ def click(
|
|
|
103
104
|
modifiers: nil,
|
|
104
105
|
noWaitAfter: nil,
|
|
105
106
|
position: nil,
|
|
107
|
+
scroll: nil,
|
|
106
108
|
steps: nil,
|
|
107
109
|
timeout: nil,
|
|
108
110
|
trial: nil)
|
|
@@ -139,6 +141,7 @@ def dblclick(
|
|
|
139
141
|
modifiers: nil,
|
|
140
142
|
noWaitAfter: nil,
|
|
141
143
|
position: nil,
|
|
144
|
+
scroll: nil,
|
|
142
145
|
steps: nil,
|
|
143
146
|
timeout: nil,
|
|
144
147
|
trial: nil)
|
|
@@ -290,6 +293,7 @@ def hover(
|
|
|
290
293
|
modifiers: nil,
|
|
291
294
|
noWaitAfter: nil,
|
|
292
295
|
position: nil,
|
|
296
|
+
scroll: nil,
|
|
293
297
|
timeout: nil,
|
|
294
298
|
trial: nil)
|
|
295
299
|
```
|
|
@@ -538,6 +542,7 @@ def set_checked(
|
|
|
538
542
|
force: nil,
|
|
539
543
|
noWaitAfter: nil,
|
|
540
544
|
position: nil,
|
|
545
|
+
scroll: nil,
|
|
541
546
|
timeout: nil,
|
|
542
547
|
trial: nil)
|
|
543
548
|
```
|
|
@@ -578,6 +583,7 @@ def tap_point(
|
|
|
578
583
|
modifiers: nil,
|
|
579
584
|
noWaitAfter: nil,
|
|
580
585
|
position: nil,
|
|
586
|
+
scroll: nil,
|
|
581
587
|
timeout: nil,
|
|
582
588
|
trial: nil)
|
|
583
589
|
```
|
|
@@ -630,6 +636,7 @@ def uncheck(
|
|
|
630
636
|
force: nil,
|
|
631
637
|
noWaitAfter: nil,
|
|
632
638
|
position: nil,
|
|
639
|
+
scroll: nil,
|
|
633
640
|
timeout: nil,
|
|
634
641
|
trial: nil)
|
|
635
642
|
```
|
|
@@ -58,6 +58,7 @@ def check(
|
|
|
58
58
|
force: nil,
|
|
59
59
|
noWaitAfter: nil,
|
|
60
60
|
position: nil,
|
|
61
|
+
scroll: nil,
|
|
61
62
|
strict: nil,
|
|
62
63
|
timeout: nil,
|
|
63
64
|
trial: nil)
|
|
@@ -95,6 +96,7 @@ def click(
|
|
|
95
96
|
modifiers: nil,
|
|
96
97
|
noWaitAfter: nil,
|
|
97
98
|
position: nil,
|
|
99
|
+
scroll: nil,
|
|
98
100
|
strict: nil,
|
|
99
101
|
timeout: nil,
|
|
100
102
|
trial: nil)
|
|
@@ -131,6 +133,7 @@ def dblclick(
|
|
|
131
133
|
modifiers: nil,
|
|
132
134
|
noWaitAfter: nil,
|
|
133
135
|
position: nil,
|
|
136
|
+
scroll: nil,
|
|
134
137
|
strict: nil,
|
|
135
138
|
timeout: nil,
|
|
136
139
|
trial: nil)
|
|
@@ -202,6 +205,7 @@ def drag_and_drop(
|
|
|
202
205
|
target,
|
|
203
206
|
force: nil,
|
|
204
207
|
noWaitAfter: nil,
|
|
208
|
+
scroll: nil,
|
|
205
209
|
sourcePosition: nil,
|
|
206
210
|
steps: nil,
|
|
207
211
|
strict: nil,
|
|
@@ -387,13 +391,17 @@ puts frame == content_frame # => true
|
|
|
387
391
|
## frame_locator
|
|
388
392
|
|
|
389
393
|
```
|
|
390
|
-
def frame_locator(selector)
|
|
394
|
+
def frame_locator(selector = nil)
|
|
391
395
|
```
|
|
392
396
|
|
|
393
397
|
|
|
394
398
|
When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements
|
|
395
399
|
in that iframe.
|
|
396
400
|
|
|
401
|
+
When called without `selector`, the search starts in this frame or in any of the iframes inside it,
|
|
402
|
+
so that you don't need to locate each iframe first. Note that the rest of the locator is resolved inside a single
|
|
403
|
+
frame, just like any other locator. If it matches elements inside multiple frames, an error is thrown.
|
|
404
|
+
|
|
397
405
|
**Usage**
|
|
398
406
|
|
|
399
407
|
Following snippet locates element with text "Submit" in the iframe with id `my-frame`, like `<iframe id="my-frame">`:
|
|
@@ -403,6 +411,13 @@ locator = frame.frame_locator("#my-iframe").get_by_text("Submit")
|
|
|
403
411
|
locator.click
|
|
404
412
|
```
|
|
405
413
|
|
|
414
|
+
Following snippet locates a button, either in the frame or in one of the iframes inside it:
|
|
415
|
+
|
|
416
|
+
```ruby
|
|
417
|
+
locator = frame.frame_locator.get_by_role('button')
|
|
418
|
+
locator.click
|
|
419
|
+
```
|
|
420
|
+
|
|
406
421
|
## get_attribute
|
|
407
422
|
|
|
408
423
|
```
|
|
@@ -671,6 +686,7 @@ def hover(
|
|
|
671
686
|
modifiers: nil,
|
|
672
687
|
noWaitAfter: nil,
|
|
673
688
|
position: nil,
|
|
689
|
+
scroll: nil,
|
|
674
690
|
strict: nil,
|
|
675
691
|
timeout: nil,
|
|
676
692
|
trial: nil)
|
|
@@ -932,6 +948,7 @@ def set_checked(
|
|
|
932
948
|
force: nil,
|
|
933
949
|
noWaitAfter: nil,
|
|
934
950
|
position: nil,
|
|
951
|
+
scroll: nil,
|
|
935
952
|
strict: nil,
|
|
936
953
|
timeout: nil,
|
|
937
954
|
trial: nil)
|
|
@@ -987,6 +1004,7 @@ def tap_point(
|
|
|
987
1004
|
modifiers: nil,
|
|
988
1005
|
noWaitAfter: nil,
|
|
989
1006
|
position: nil,
|
|
1007
|
+
scroll: nil,
|
|
990
1008
|
strict: nil,
|
|
991
1009
|
timeout: nil,
|
|
992
1010
|
trial: nil)
|
|
@@ -1056,6 +1074,7 @@ def uncheck(
|
|
|
1056
1074
|
force: nil,
|
|
1057
1075
|
noWaitAfter: nil,
|
|
1058
1076
|
position: nil,
|
|
1077
|
+
scroll: nil,
|
|
1059
1078
|
strict: nil,
|
|
1060
1079
|
timeout: nil,
|
|
1061
1080
|
trial: nil)
|
|
@@ -24,6 +24,26 @@ page.locator('.result-frame').content_frame.get_by_role('button').click
|
|
|
24
24
|
page.locator('.result-frame').first.content_frame.get_by_role('button').click
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
**Any frame**
|
|
28
|
+
|
|
29
|
+
Calling [Page#frame_locator](./page#frame_locator) or [Frame#frame_locator](./frame#frame_locator) without a selector creates a frame locator that
|
|
30
|
+
starts the search in any frame of the subtree - so that you don't
|
|
31
|
+
need to locate the iframe first.
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
# Finds the button in any frame on the page:
|
|
35
|
+
page.frame_locator.get_by_role('button').click
|
|
36
|
+
|
|
37
|
+
# Finds the iframe anywhere on the page and clicks the button inside it:
|
|
38
|
+
page.frame_locator.locator('#my-frame').content_frame.get_by_role('button').click
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Only the start of the search is affected - the rest of the locator is resolved inside a single frame, just like any
|
|
42
|
+
other locator. Following the strictness rules above, an error is thrown when elements are matched in multiple frames.
|
|
43
|
+
|
|
44
|
+
Such a frame locator does not point to a particular `iframe`, so [FrameLocator#owner](./frame_locator#owner),
|
|
45
|
+
[FrameLocator#first](./frame_locator#first), [FrameLocator#last](./frame_locator#last) and [FrameLocator#nth](./frame_locator#nth) are not supported on it.
|
|
46
|
+
|
|
27
47
|
**Converting Locator to FrameLocator**
|
|
28
48
|
|
|
29
49
|
If you have a [Locator](./locator) object pointing to an `iframe` it can be converted to [FrameLocator](./frame_locator) using [Locator#content_frame](./locator#content_frame).
|
|
@@ -179,6 +179,7 @@ def check(
|
|
|
179
179
|
force: nil,
|
|
180
180
|
noWaitAfter: nil,
|
|
181
181
|
position: nil,
|
|
182
|
+
scroll: nil,
|
|
182
183
|
timeout: nil,
|
|
183
184
|
trial: nil)
|
|
184
185
|
```
|
|
@@ -238,6 +239,7 @@ def click(
|
|
|
238
239
|
modifiers: nil,
|
|
239
240
|
noWaitAfter: nil,
|
|
240
241
|
position: nil,
|
|
242
|
+
scroll: nil,
|
|
241
243
|
steps: nil,
|
|
242
244
|
timeout: nil,
|
|
243
245
|
trial: nil)
|
|
@@ -300,6 +302,7 @@ def dblclick(
|
|
|
300
302
|
modifiers: nil,
|
|
301
303
|
noWaitAfter: nil,
|
|
302
304
|
position: nil,
|
|
305
|
+
scroll: nil,
|
|
303
306
|
steps: nil,
|
|
304
307
|
timeout: nil,
|
|
305
308
|
trial: nil)
|
|
@@ -410,6 +413,7 @@ def drag_to(
|
|
|
410
413
|
target,
|
|
411
414
|
force: nil,
|
|
412
415
|
noWaitAfter: nil,
|
|
416
|
+
scroll: nil,
|
|
413
417
|
sourcePosition: nil,
|
|
414
418
|
steps: nil,
|
|
415
419
|
targetPosition: nil,
|
|
@@ -921,6 +925,7 @@ def hover(
|
|
|
921
925
|
modifiers: nil,
|
|
922
926
|
noWaitAfter: nil,
|
|
923
927
|
position: nil,
|
|
928
|
+
scroll: nil,
|
|
924
929
|
timeout: nil,
|
|
925
930
|
trial: nil)
|
|
926
931
|
```
|
|
@@ -1367,6 +1372,7 @@ def set_checked(
|
|
|
1367
1372
|
force: nil,
|
|
1368
1373
|
noWaitAfter: nil,
|
|
1369
1374
|
position: nil,
|
|
1375
|
+
scroll: nil,
|
|
1370
1376
|
timeout: nil,
|
|
1371
1377
|
trial: nil)
|
|
1372
1378
|
```
|
|
@@ -1438,6 +1444,7 @@ def tap_point(
|
|
|
1438
1444
|
modifiers: nil,
|
|
1439
1445
|
noWaitAfter: nil,
|
|
1440
1446
|
position: nil,
|
|
1447
|
+
scroll: nil,
|
|
1441
1448
|
timeout: nil,
|
|
1442
1449
|
trial: nil)
|
|
1443
1450
|
```
|
|
@@ -1496,6 +1503,7 @@ def uncheck(
|
|
|
1496
1503
|
force: nil,
|
|
1497
1504
|
noWaitAfter: nil,
|
|
1498
1505
|
position: nil,
|
|
1506
|
+
scroll: nil,
|
|
1499
1507
|
timeout: nil,
|
|
1500
1508
|
trial: nil)
|
|
1501
1509
|
```
|
|
@@ -1523,6 +1531,34 @@ If the element is detached from the DOM at any moment during the action, this me
|
|
|
1523
1531
|
When all steps combined have not finished during the specified `timeout`, this method throws a
|
|
1524
1532
|
`TimeoutError`. Passing zero timeout disables this.
|
|
1525
1533
|
|
|
1534
|
+
## visible
|
|
1535
|
+
|
|
1536
|
+
```
|
|
1537
|
+
def visible
|
|
1538
|
+
```
|
|
1539
|
+
|
|
1540
|
+
|
|
1541
|
+
Returns a locator that matches only [visible](https://playwright.dev/python/docs/actionability#visible) elements, ignoring the invisible ones. This is the recommended way to distinguish elements by visibility, as opposed to the `:visible` CSS pseudo-class.
|
|
1542
|
+
|
|
1543
|
+
Note that visibility is checked every time the locator is used, and not at the moment of the [Locator#visible](./locator#visible) call.
|
|
1544
|
+
|
|
1545
|
+
**Usage**
|
|
1546
|
+
|
|
1547
|
+
Consider a page with two buttons, the first invisible and the second visible.
|
|
1548
|
+
|
|
1549
|
+
```html
|
|
1550
|
+
<button style='display: none'>Invisible</button>
|
|
1551
|
+
<button>Visible</button>
|
|
1552
|
+
```
|
|
1553
|
+
|
|
1554
|
+
This will only find the second button, because it is visible, and then click it.
|
|
1555
|
+
|
|
1556
|
+
```ruby
|
|
1557
|
+
page.locator('button').visible.click
|
|
1558
|
+
```
|
|
1559
|
+
|
|
1560
|
+
To match invisible elements instead, use [Locator#filter](./locator#filter) with the `visible` option set to `false`.
|
|
1561
|
+
|
|
1526
1562
|
## wait_for
|
|
1527
1563
|
|
|
1528
1564
|
```
|
|
@@ -1541,3 +1577,24 @@ If target element already satisfies the condition, the method returns immediatel
|
|
|
1541
1577
|
order_sent = page.locator("#order-sent")
|
|
1542
1578
|
order_sent.wait_for
|
|
1543
1579
|
```
|
|
1580
|
+
|
|
1581
|
+
## wait_for_function
|
|
1582
|
+
|
|
1583
|
+
```
|
|
1584
|
+
def wait_for_function(expression, arg: nil, timeout: nil)
|
|
1585
|
+
```
|
|
1586
|
+
|
|
1587
|
+
|
|
1588
|
+
Returns when `expression` returns a truthy value, called with the matching element as a first argument, and `arg` as a second argument.
|
|
1589
|
+
|
|
1590
|
+
This is a generic way to wait for an element to reach a custom condition without asserting it. The locator is re-resolved on each retry, so it tolerates the element being re-rendered while waiting.
|
|
1591
|
+
|
|
1592
|
+
If `expression` returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise), this method will wait for the promise to resolve before checking its value.
|
|
1593
|
+
|
|
1594
|
+
If `expression` throws or rejects, this method throws.
|
|
1595
|
+
|
|
1596
|
+
**Usage**
|
|
1597
|
+
|
|
1598
|
+
Wait for an attribute to appear:
|
|
1599
|
+
|
|
1600
|
+
Passing argument to `expression`:
|
|
@@ -164,7 +164,7 @@ The opposite of [LocatorAssertions#to_have_accessible_name](./locator_assertions
|
|
|
164
164
|
## not_to_have_attribute
|
|
165
165
|
|
|
166
166
|
```ruby
|
|
167
|
-
expect(locator).not_to have_attribute(name, value, ignoreCase: nil, timeout: nil)
|
|
167
|
+
expect(locator).not_to have_attribute(name, value: nil, ignoreCase: nil, timeout: nil)
|
|
168
168
|
```
|
|
169
169
|
|
|
170
170
|
|
|
@@ -587,7 +587,7 @@ expect(locator).to have_accessible_name("Save to disk")
|
|
|
587
587
|
## to_have_attribute
|
|
588
588
|
|
|
589
589
|
```ruby
|
|
590
|
-
expect(locator).to have_attribute(name, value, ignoreCase: nil, timeout: nil)
|
|
590
|
+
expect(locator).to have_attribute(name, value: nil, ignoreCase: nil, timeout: nil)
|
|
591
591
|
```
|
|
592
592
|
|
|
593
593
|
|
|
@@ -598,6 +598,8 @@ Ensures the [Locator](./locator) points to an element with given attribute.
|
|
|
598
598
|
```ruby
|
|
599
599
|
locator = page.locator("input")
|
|
600
600
|
expect(locator).to have_attribute("type", "text")
|
|
601
|
+
expect(locator).to have_attribute("disabled")
|
|
602
|
+
expect(locator).not_to have_attribute("readonly")
|
|
601
603
|
```
|
|
602
604
|
|
|
603
605
|
## to_have_class
|
|
@@ -112,6 +112,7 @@ def check(
|
|
|
112
112
|
force: nil,
|
|
113
113
|
noWaitAfter: nil,
|
|
114
114
|
position: nil,
|
|
115
|
+
scroll: nil,
|
|
115
116
|
strict: nil,
|
|
116
117
|
timeout: nil,
|
|
117
118
|
trial: nil)
|
|
@@ -141,6 +142,7 @@ def click(
|
|
|
141
142
|
modifiers: nil,
|
|
142
143
|
noWaitAfter: nil,
|
|
143
144
|
position: nil,
|
|
145
|
+
scroll: nil,
|
|
144
146
|
strict: nil,
|
|
145
147
|
timeout: nil,
|
|
146
148
|
trial: nil)
|
|
@@ -201,6 +203,7 @@ def dblclick(
|
|
|
201
203
|
modifiers: nil,
|
|
202
204
|
noWaitAfter: nil,
|
|
203
205
|
position: nil,
|
|
206
|
+
scroll: nil,
|
|
204
207
|
strict: nil,
|
|
205
208
|
timeout: nil,
|
|
206
209
|
trial: nil)
|
|
@@ -275,6 +278,7 @@ def drag_and_drop(
|
|
|
275
278
|
target,
|
|
276
279
|
force: nil,
|
|
277
280
|
noWaitAfter: nil,
|
|
281
|
+
scroll: nil,
|
|
278
282
|
sourcePosition: nil,
|
|
279
283
|
steps: nil,
|
|
280
284
|
strict: nil,
|
|
@@ -581,13 +585,17 @@ frame = page.frame(url: /.*domain.*/)
|
|
|
581
585
|
## frame_locator
|
|
582
586
|
|
|
583
587
|
```
|
|
584
|
-
def frame_locator(selector)
|
|
588
|
+
def frame_locator(selector = nil)
|
|
585
589
|
```
|
|
586
590
|
|
|
587
591
|
|
|
588
592
|
When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements
|
|
589
593
|
in that iframe.
|
|
590
594
|
|
|
595
|
+
When called without `selector`, the search starts in any frame on the page - the main frame or any of
|
|
596
|
+
the iframes - so that you don't need to locate each iframe first. Note that the rest of the locator is resolved
|
|
597
|
+
inside a single frame, just like any other locator. If it matches elements inside multiple frames, an error is thrown.
|
|
598
|
+
|
|
591
599
|
**Usage**
|
|
592
600
|
|
|
593
601
|
Following snippet locates element with text "Submit" in the iframe with id `my-frame`,
|
|
@@ -598,6 +606,13 @@ locator = page.frame_locator("#my-iframe").get_by_text("Submit")
|
|
|
598
606
|
locator.click
|
|
599
607
|
```
|
|
600
608
|
|
|
609
|
+
Following snippet locates a button, either in the main frame or in one of the iframes:
|
|
610
|
+
|
|
611
|
+
```ruby
|
|
612
|
+
locator = page.frame_locator.get_by_role('button')
|
|
613
|
+
locator.click
|
|
614
|
+
```
|
|
615
|
+
|
|
601
616
|
## frames
|
|
602
617
|
|
|
603
618
|
```
|
|
@@ -851,6 +866,9 @@ last redirect. If cannot go back, returns `null`.
|
|
|
851
866
|
|
|
852
867
|
Navigate to the previous page in history.
|
|
853
868
|
|
|
869
|
+
**NOTE**: **Testing Back/Forward Cache (BFCache) is not supported.**
|
|
870
|
+
By default, Playwright disables the Back/Forward Cache across all browsers. Even if explicitly enabled, Playwright's internal state relies on network-level navigation events. Because BFCache restores unfreeze the DOM without firing these events, using `page.goBack()` or `page.goForward()` to trigger a BFCache restore will result in timeouts and a desynchronized [Page](./page) state.
|
|
871
|
+
|
|
854
872
|
## go_forward
|
|
855
873
|
|
|
856
874
|
```
|
|
@@ -863,6 +881,9 @@ last redirect. If cannot go forward, returns `null`.
|
|
|
863
881
|
|
|
864
882
|
Navigate to the next page in history.
|
|
865
883
|
|
|
884
|
+
**NOTE**: **Testing Back/Forward Cache (BFCache) is not supported.**
|
|
885
|
+
By default, Playwright disables the Back/Forward Cache across all browsers. Even if explicitly enabled, Playwright's internal state relies on network-level navigation events. Because BFCache restores unfreeze the DOM without firing these events, using `page.goBack()` or `page.goForward()` to trigger a BFCache restore will result in timeouts and a desynchronized [Page](./page) state.
|
|
886
|
+
|
|
866
887
|
## goto
|
|
867
888
|
|
|
868
889
|
```
|
|
@@ -908,6 +929,7 @@ def hover(
|
|
|
908
929
|
modifiers: nil,
|
|
909
930
|
noWaitAfter: nil,
|
|
910
931
|
position: nil,
|
|
932
|
+
scroll: nil,
|
|
911
933
|
strict: nil,
|
|
912
934
|
timeout: nil,
|
|
913
935
|
trial: nil)
|
|
@@ -1416,6 +1438,7 @@ def set_checked(
|
|
|
1416
1438
|
force: nil,
|
|
1417
1439
|
noWaitAfter: nil,
|
|
1418
1440
|
position: nil,
|
|
1441
|
+
scroll: nil,
|
|
1419
1442
|
strict: nil,
|
|
1420
1443
|
timeout: nil,
|
|
1421
1444
|
trial: nil)
|
|
@@ -1546,6 +1569,7 @@ def tap_point(
|
|
|
1546
1569
|
modifiers: nil,
|
|
1547
1570
|
noWaitAfter: nil,
|
|
1548
1571
|
position: nil,
|
|
1572
|
+
scroll: nil,
|
|
1549
1573
|
strict: nil,
|
|
1550
1574
|
timeout: nil,
|
|
1551
1575
|
trial: nil)
|
|
@@ -1615,6 +1639,7 @@ def uncheck(
|
|
|
1615
1639
|
force: nil,
|
|
1616
1640
|
noWaitAfter: nil,
|
|
1617
1641
|
position: nil,
|
|
1642
|
+
scroll: nil,
|
|
1618
1643
|
strict: nil,
|
|
1619
1644
|
timeout: nil,
|
|
1620
1645
|
trial: nil)
|
|
@@ -11,7 +11,7 @@ to drive automation:
|
|
|
11
11
|
```ruby
|
|
12
12
|
require 'playwright'
|
|
13
13
|
|
|
14
|
-
Playwright.create(playwright_cli_executable_path: '
|
|
14
|
+
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright-core') do |playwright|
|
|
15
15
|
chromium = playwright.chromium # or "firefox" or "webkit".
|
|
16
16
|
chromium.launch do |browser|
|
|
17
17
|
page = browser.new_page
|
|
@@ -36,7 +36,7 @@ Returns a dictionary of devices to be used with [Browser#new_context](./browser#
|
|
|
36
36
|
```ruby
|
|
37
37
|
require 'playwright'
|
|
38
38
|
|
|
39
|
-
Playwright.create(playwright_cli_executable_path: '
|
|
39
|
+
Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright-core') do |playwright|
|
|
40
40
|
iphone = playwright.devices["iPhone 6"]
|
|
41
41
|
playwright.webkit.launch do |browser|
|
|
42
42
|
context = browser.new_context(**iphone)
|
|
@@ -26,9 +26,11 @@ end
|
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
def start(
|
|
29
|
+
ariaSnapshots: nil,
|
|
29
30
|
live: nil,
|
|
30
31
|
name: nil,
|
|
31
32
|
screenshots: nil,
|
|
33
|
+
screenSnapshots: nil,
|
|
32
34
|
snapshots: nil,
|
|
33
35
|
sources: nil,
|
|
34
36
|
title: nil)
|
|
@@ -86,7 +88,7 @@ def start_har(path, content: nil, mode: nil, urlFilter: nil)
|
|
|
86
88
|
|
|
87
89
|
Start recording a HAR (HTTP Archive) of network activity in this context. The HAR file is written to disk when [Tracing#stop_har](./tracing#stop_har) is called, or when the returned `Disposable` is disposed.
|
|
88
90
|
|
|
89
|
-
Only one HAR recording can be active at a time per [
|
|
91
|
+
Only one HAR recording can be active at a time per [Tracing](./tracing) instance.
|
|
90
92
|
|
|
91
93
|
**Usage**
|
|
92
94
|
|