playwright-ruby-client 1.39.0 → 1.40.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/documentation/docs/api/api_request_context.md +1 -2
- data/documentation/docs/api/browser.md +10 -14
- data/documentation/docs/api/browser_context.md +32 -51
- data/documentation/docs/api/browser_type.md +8 -12
- data/documentation/docs/api/dialog.md +15 -18
- data/documentation/docs/api/download.md +10 -12
- data/documentation/docs/api/element_handle.md +9 -7
- data/documentation/docs/api/frame.md +28 -55
- data/documentation/docs/api/locator.md +24 -23
- data/documentation/docs/api/locator_assertions.md +652 -0
- data/documentation/docs/api/page.md +53 -103
- data/documentation/docs/api/playwright.md +20 -23
- data/documentation/docs/api/selectors.md +29 -34
- data/documentation/docs/article/guides/rails_integration.md +80 -51
- data/documentation/docs/article/guides/rspec_integration.md +59 -0
- data/documentation/docs/include/api_coverage.md +43 -0
- data/documentation/docusaurus.config.js +1 -1
- data/documentation/package.json +7 -7
- data/documentation/yarn.lock +4641 -5023
- data/lib/playwright/api_response_impl.rb +2 -2
- data/lib/playwright/channel.rb +1 -1
- data/lib/playwright/channel_owners/api_request_context.rb +12 -3
- data/lib/playwright/channel_owners/browser.rb +11 -7
- data/lib/playwright/channel_owners/browser_context.rb +35 -15
- data/lib/playwright/channel_owners/frame.rb +38 -14
- data/lib/playwright/channel_owners/page.rb +29 -16
- data/lib/playwright/channel_owners/web_socket.rb +8 -13
- data/lib/playwright/connection.rb +18 -2
- data/lib/playwright/errors.rb +22 -2
- data/lib/playwright/input_files.rb +4 -4
- data/lib/playwright/javascript/value_serializer.rb +1 -1
- data/lib/playwright/locator_assertions_impl.rb +417 -0
- data/lib/playwright/locator_impl.rb +24 -5
- data/lib/playwright/test.rb +68 -0
- data/lib/playwright/utils.rb +3 -10
- data/lib/playwright/version.rb +2 -2
- data/lib/playwright/waiter.rb +146 -0
- data/lib/playwright.rb +1 -1
- data/lib/playwright_api/api_request_context.rb +1 -2
- data/lib/playwright_api/browser.rb +2 -2
- data/lib/playwright_api/browser_context.rb +3 -3
- data/lib/playwright_api/browser_type.rb +2 -1
- data/lib/playwright_api/download.rb +1 -2
- data/lib/playwright_api/element_handle.rb +4 -1
- data/lib/playwright_api/frame.rb +4 -1
- data/lib/playwright_api/locator.rb +9 -1
- data/lib/playwright_api/locator_assertions.rb +561 -0
- data/lib/playwright_api/page.rb +16 -13
- data/lib/playwright_api/request.rb +4 -4
- data/lib/playwright_api/worker.rb +4 -4
- data/sig/playwright.rbs +48 -5
- metadata +9 -4
- data/lib/playwright/wait_helper.rb +0 -73
@@ -12,21 +12,12 @@ instance might have multiple [Page](./page) instances.
|
|
12
12
|
|
13
13
|
This example creates a page, navigates it to a URL, and then saves a screenshot:
|
14
14
|
|
15
|
-
```
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
context = browser.new_context()
|
22
|
-
page = context.new_page()
|
23
|
-
page.goto("https://example.com")
|
24
|
-
page.screenshot(path="screenshot.png")
|
25
|
-
browser.close()
|
26
|
-
|
27
|
-
with sync_playwright() as playwright:
|
28
|
-
run(playwright)
|
29
|
-
|
15
|
+
```ruby
|
16
|
+
playwright.webkit.launch do |browser|
|
17
|
+
page = browser.new_page
|
18
|
+
page.goto('https://example.com/')
|
19
|
+
page.screenshot(path: 'screenshot.png')
|
20
|
+
end
|
30
21
|
```
|
31
22
|
|
32
23
|
The Page class emits various events (described below) which can be handled using any of Node's native
|
@@ -161,7 +152,7 @@ When all steps combined have not finished during the specified `timeout`, this m
|
|
161
152
|
## close
|
162
153
|
|
163
154
|
```
|
164
|
-
def close(runBeforeUnload: nil)
|
155
|
+
def close(reason: nil, runBeforeUnload: nil)
|
165
156
|
```
|
166
157
|
|
167
158
|
|
@@ -249,13 +240,16 @@ default.
|
|
249
240
|
|
250
241
|
Since `eventInit` is event-specific, please refer to the events documentation for the lists of initial
|
251
242
|
properties:
|
243
|
+
- [DeviceMotionEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent/DeviceMotionEvent)
|
244
|
+
- [DeviceOrientationEvent](https://developer.mozilla.org/en-US/docs/Web/API/DeviceOrientationEvent/DeviceOrientationEvent)
|
252
245
|
- [DragEvent](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent)
|
246
|
+
- [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event)
|
253
247
|
- [FocusEvent](https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/FocusEvent)
|
254
248
|
- [KeyboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent)
|
255
249
|
- [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent)
|
256
250
|
- [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/PointerEvent)
|
257
251
|
- [TouchEvent](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent)
|
258
|
-
- [
|
252
|
+
- [WheelEvent](https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/WheelEvent)
|
259
253
|
|
260
254
|
You can also specify [JSHandle](./js_handle) as the property value if you want live objects to be passed into the event:
|
261
255
|
|
@@ -471,29 +465,18 @@ See [BrowserContext#expose_binding](./browser_context#expose_binding) for the co
|
|
471
465
|
|
472
466
|
An example of exposing page URL to all frames in a page:
|
473
467
|
|
474
|
-
```
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
document.querySelector('div').textContent = await window.pageURL();
|
487
|
-
}
|
488
|
-
</script>
|
489
|
-
<button onclick="onClick()">Click me</button>
|
490
|
-
<div></div>
|
491
|
-
""")
|
492
|
-
page.click("button")
|
493
|
-
|
494
|
-
with sync_playwright() as playwright:
|
495
|
-
run(playwright)
|
496
|
-
|
468
|
+
```ruby
|
469
|
+
page.expose_binding("pageURL", ->(source) { source[:page].url })
|
470
|
+
page.content = <<~HTML
|
471
|
+
<script>
|
472
|
+
async function onClick() {
|
473
|
+
document.querySelector('div').textContent = await window.pageURL();
|
474
|
+
}
|
475
|
+
</script>
|
476
|
+
<button onclick="onClick()">Click me</button>
|
477
|
+
<div></div>
|
478
|
+
HTML
|
479
|
+
page.click("button")
|
497
480
|
```
|
498
481
|
|
499
482
|
An example of passing an element handle:
|
@@ -537,35 +520,24 @@ See [BrowserContext#expose_function](./browser_context#expose_function) for cont
|
|
537
520
|
|
538
521
|
An example of adding a `sha256` function to the page:
|
539
522
|
|
540
|
-
```
|
541
|
-
|
542
|
-
from playwright.sync_api import sync_playwright, Playwright
|
543
|
-
|
544
|
-
def sha256(text):
|
545
|
-
m = hashlib.sha256()
|
546
|
-
m.update(bytes(text, "utf8"))
|
547
|
-
return m.hexdigest()
|
548
|
-
|
549
|
-
|
550
|
-
def run(playwright: Playwright):
|
551
|
-
webkit = playwright.webkit
|
552
|
-
browser = webkit.launch(headless=False)
|
553
|
-
page = browser.new_page()
|
554
|
-
page.expose_function("sha256", sha256)
|
555
|
-
page.set_content("""
|
556
|
-
<script>
|
557
|
-
async function onClick() {
|
558
|
-
document.querySelector('div').textContent = await window.sha256('PLAYWRIGHT');
|
559
|
-
}
|
560
|
-
</script>
|
561
|
-
<button onclick="onClick()">Click me</button>
|
562
|
-
<div></div>
|
563
|
-
""")
|
564
|
-
page.click("button")
|
523
|
+
```ruby
|
524
|
+
require 'digest'
|
565
525
|
|
566
|
-
|
567
|
-
|
526
|
+
def sha256(text)
|
527
|
+
Digest::SHA256.hexdigest(text)
|
528
|
+
end
|
568
529
|
|
530
|
+
page.expose_function("sha256", method(:sha256))
|
531
|
+
page.content = <<~HTML
|
532
|
+
<script>
|
533
|
+
async function onClick() {
|
534
|
+
document.querySelector('div').textContent = await window.sha256('PLAYWRIGHT');
|
535
|
+
}
|
536
|
+
</script>
|
537
|
+
<button onclick="onClick()">Click me</button>
|
538
|
+
<div></div>
|
539
|
+
HTML
|
540
|
+
page.locator("button").click
|
569
541
|
```
|
570
542
|
|
571
543
|
## fill
|
@@ -1355,14 +1327,13 @@ Triggers a `change` and `input` event once all the provided options have been se
|
|
1355
1327
|
|
1356
1328
|
**Usage**
|
1357
1329
|
|
1358
|
-
```
|
1359
|
-
#
|
1360
|
-
page.select_option("select#colors", "blue")
|
1330
|
+
```ruby
|
1331
|
+
# single selection matching the value
|
1332
|
+
page.select_option("select#colors", value: "blue")
|
1361
1333
|
# single selection matching both the label
|
1362
|
-
page.select_option("select#colors", label
|
1334
|
+
page.select_option("select#colors", label: "blue")
|
1363
1335
|
# multiple selection
|
1364
|
-
page.select_option("select#colors", value
|
1365
|
-
|
1336
|
+
page.select_option("select#colors", value: ["red", "green", "blue"])
|
1366
1337
|
```
|
1367
1338
|
|
1368
1339
|
## set_checked
|
@@ -1676,20 +1647,9 @@ Returns when the `expression` returns a truthy value. It resolves to a JSHandle
|
|
1676
1647
|
|
1677
1648
|
The [Page#wait_for_function](./page#wait_for_function) can be used to observe viewport size change:
|
1678
1649
|
|
1679
|
-
```
|
1680
|
-
|
1681
|
-
|
1682
|
-
def run(playwright: Playwright):
|
1683
|
-
webkit = playwright.webkit
|
1684
|
-
browser = webkit.launch()
|
1685
|
-
page = browser.new_page()
|
1686
|
-
page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);")
|
1687
|
-
page.wait_for_function("() => window.x > 0")
|
1688
|
-
browser.close()
|
1689
|
-
|
1690
|
-
with sync_playwright() as playwright:
|
1691
|
-
run(playwright)
|
1692
|
-
|
1650
|
+
```ruby
|
1651
|
+
page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);")
|
1652
|
+
page.wait_for_function("() => window.x > 0")
|
1693
1653
|
```
|
1694
1654
|
|
1695
1655
|
To pass an argument to the predicate of [Page#wait_for_function](./page#wait_for_function) function:
|
@@ -1857,22 +1817,12 @@ function will throw.
|
|
1857
1817
|
|
1858
1818
|
This method works across navigations:
|
1859
1819
|
|
1860
|
-
```
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
|
1866
|
-
page = browser.new_page()
|
1867
|
-
for current_url in ["https://google.com", "https://bbc.com"]:
|
1868
|
-
page.goto(current_url, wait_until="domcontentloaded")
|
1869
|
-
element = page.wait_for_selector("img")
|
1870
|
-
print("Loaded image: " + str(element.get_attribute("src")))
|
1871
|
-
browser.close()
|
1872
|
-
|
1873
|
-
with sync_playwright() as playwright:
|
1874
|
-
run(playwright)
|
1875
|
-
|
1820
|
+
```ruby
|
1821
|
+
%w[https://google.com https://bbc.com].each do |current_url|
|
1822
|
+
page.goto(current_url, waitUntil: "domcontentloaded")
|
1823
|
+
element = page.wait_for_selector("img")
|
1824
|
+
puts "Loaded image: #{element["src"]}"
|
1825
|
+
end
|
1876
1826
|
```
|
1877
1827
|
|
1878
1828
|
## wait_for_timeout
|
@@ -8,20 +8,19 @@ sidebar_position: 10
|
|
8
8
|
Playwright module provides a method to launch a browser instance. The following is a typical example of using Playwright
|
9
9
|
to drive automation:
|
10
10
|
|
11
|
-
```
|
12
|
-
|
11
|
+
```ruby
|
12
|
+
require 'playwright'
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
page = browser.new_page
|
18
|
-
page.goto(
|
19
|
-
# other actions...
|
20
|
-
browser.close()
|
14
|
+
Playwright.create(playwright_cli_executable_path: 'npx playwright') do |playwright|
|
15
|
+
chromium = playwright.chromium # or "firefox" or "webkit".
|
16
|
+
chromium.launch do |browser|
|
17
|
+
page = browser.new_page
|
18
|
+
page.goto('https://example.com/')
|
21
19
|
|
22
|
-
|
23
|
-
run(playwright)
|
20
|
+
# other actions
|
24
21
|
|
22
|
+
end
|
23
|
+
end
|
25
24
|
```
|
26
25
|
|
27
26
|
## chromium
|
@@ -34,22 +33,20 @@ This object can be used to launch or connect to Chromium, returning instances of
|
|
34
33
|
|
35
34
|
Returns a dictionary of devices to be used with [Browser#new_context](./browser#new_context) or [Browser#new_page](./browser#new_page).
|
36
35
|
|
37
|
-
```
|
38
|
-
|
36
|
+
```ruby
|
37
|
+
require 'playwright'
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
browser = webkit.launch()
|
39
|
+
Playwright.create(playwright_cli_executable_path: 'npx playwright') do |playwright|
|
40
|
+
iphone = playwright.devices["iPhone 6"]
|
41
|
+
playwright.webkit.launch do |browser|
|
44
42
|
context = browser.new_context(**iphone)
|
45
|
-
page = context.new_page
|
46
|
-
page.goto(
|
47
|
-
# other actions...
|
48
|
-
browser.close()
|
43
|
+
page = context.new_page
|
44
|
+
page.goto('https://example.com/')
|
49
45
|
|
50
|
-
|
51
|
-
run(playwright)
|
46
|
+
# other actions
|
52
47
|
|
48
|
+
end
|
49
|
+
end
|
53
50
|
```
|
54
51
|
|
55
52
|
## firefox
|
@@ -21,38 +21,33 @@ Selectors must be registered before creating the page.
|
|
21
21
|
|
22
22
|
An example of registering selector engine that queries elements based on a tag name:
|
23
23
|
|
24
|
-
```
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
browser.close()
|
54
|
-
|
55
|
-
with sync_playwright() as playwright:
|
56
|
-
run(playwright)
|
57
|
-
|
24
|
+
```ruby
|
25
|
+
tag_selector = <<~JAVASCRIPT
|
26
|
+
{
|
27
|
+
// Returns the first element matching given selector in the root's subtree.
|
28
|
+
query(root, selector) {
|
29
|
+
return root.querySelector(selector);
|
30
|
+
},
|
31
|
+
// Returns all elements matching given selector in the root's subtree.
|
32
|
+
queryAll(root, selector) {
|
33
|
+
return Array.from(root.querySelectorAll(selector));
|
34
|
+
}
|
35
|
+
}
|
36
|
+
JAVASCRIPT
|
37
|
+
|
38
|
+
# Register the engine. Selectors will be prefixed with "tag=".
|
39
|
+
playwright.selectors.register("tag", script: tag_selector)
|
40
|
+
playwright.chromium.launch do |browser|
|
41
|
+
page = browser.new_page
|
42
|
+
page.content = '<div><button>Click me</button></div>'
|
43
|
+
|
44
|
+
# Use the selector prefixed with its name.
|
45
|
+
button = page.locator('tag=button')
|
46
|
+
# Combine it with other selector engines.
|
47
|
+
page.locator('tag=div').get_by_text('Click me').click
|
48
|
+
|
49
|
+
# Can use it in any methods supporting selectors.
|
50
|
+
button_count = page.locator('tag=button').count
|
51
|
+
button_count # => 1
|
52
|
+
end
|
58
53
|
```
|
@@ -33,7 +33,7 @@ end
|
|
33
33
|
|
34
34
|
### Update timeout
|
35
35
|
|
36
|
-
Capybara sets the default value of timeout to
|
36
|
+
Capybara sets the default value of timeout to _2 seconds_. Generally it is too short to wait for HTTP responses.
|
37
37
|
|
38
38
|
It is recommended to set the timeout to 15-30 seconds for Playwright driver.
|
39
39
|
|
@@ -56,50 +56,50 @@ It is not mandatry. Without changing the default driver, you can still use Playw
|
|
56
56
|
|
57
57
|
These parameters can be passed into `Capybara::Playwright::Driver.new`
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
59
|
+
- `playwright_cli_executable_path`
|
60
|
+
- Refer [this article](./download_playwright_driver) to understand what to specify.
|
61
|
+
- `browser_type`
|
62
|
+
- `:chromium` (default), `:firefox`, or `:webkit`
|
63
|
+
- Parameters for [Playwright::BrowserType#launch](/docs/api/browser_type#launch)
|
64
|
+
- args
|
65
|
+
- channel
|
66
|
+
- `chrome`, `msedge`, `chrome-beta`, `chrome-dev`, `chrome-canary`, `msedge-beta`, `msedge-dev` Browser distribution channel. Read more about using [Google Chrome & Microsoft Edge](https://playwright.dev/docs/browsers#google-chrome--microsoft-edge)
|
67
|
+
- devtools
|
68
|
+
- downloadsPath
|
69
|
+
- env
|
70
|
+
- executablePath
|
71
|
+
- firefoxUserPrefs
|
72
|
+
- headless
|
73
|
+
- ignoreDefaultArgs
|
74
|
+
- proxy
|
75
|
+
- slowMo
|
76
|
+
- timeout
|
77
|
+
- Parameters for [Playwright::Browser#new_context](/docs/api/browser#new_context)
|
78
|
+
- bypassCSP
|
79
|
+
- colorScheme
|
80
|
+
- deviceScaleFactor
|
81
|
+
- extraHTTPHeaders
|
82
|
+
- geolocation
|
83
|
+
- hasTouch
|
84
|
+
- httpCredentials
|
85
|
+
- ignoreHTTPSErrors
|
86
|
+
- isMobile
|
87
|
+
- javaScriptEnabled
|
88
|
+
- locale
|
89
|
+
- noViewport
|
90
|
+
- offline
|
91
|
+
- permissions
|
92
|
+
- proxy
|
93
|
+
- record_har_omit_content
|
94
|
+
- record_har_path
|
95
|
+
- record_video_dir
|
96
|
+
- record_video_size
|
97
|
+
- screen
|
98
|
+
- serviceWorkers
|
99
|
+
- storageState
|
100
|
+
- timezoneId
|
101
|
+
- userAgent
|
102
|
+
- viewport
|
103
103
|
|
104
104
|
```ruby
|
105
105
|
driver_opts = {
|
@@ -119,14 +119,13 @@ driver_opts = {
|
|
119
119
|
Capybara::Playwright::Driver.new(app, driver_opts)
|
120
120
|
```
|
121
121
|
|
122
|
-
|
123
122
|
## Available functions and Limitations
|
124
123
|
|
125
124
|
### Capybara DSL
|
126
125
|
|
127
126
|
Most of the methods of `Capybara::Session` and `Capybara::Node::Element` are available. However the following method is not yet implemented.
|
128
127
|
|
129
|
-
|
128
|
+
- `Capybara::Node::Element#drop`
|
130
129
|
|
131
130
|
### Playwright-native scripting
|
132
131
|
|
@@ -181,7 +180,6 @@ end
|
|
181
180
|
|
182
181
|
For more details, refer [Recording video](./recording_video.md#using-screen-recording-from-capybara-driver)
|
183
182
|
|
184
|
-
|
185
183
|
### Screenshot just before teardown
|
186
184
|
|
187
185
|
In addition to `Capybara::Session#save_screenshot`, capybara-playwright-driver have another method for storing last screen state just before teardown.
|
@@ -201,8 +199,39 @@ before do |example|
|
|
201
199
|
end
|
202
200
|
```
|
203
201
|
|
202
|
+
### Tracing for postmortem
|
203
|
+
|
204
|
+
Playwright users often expect to see what happened in the browser when the test failed. `capybara-playwright-driver` provides a feature to store the trace easily.
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
before do |example|
|
208
|
+
Capybara.current_session.driver.on_save_trace do |trace_zip_path|
|
209
|
+
Allure.add_attachment(
|
210
|
+
name: "trace - #{example.description}",
|
211
|
+
source: File.read(trace_zip_path),
|
212
|
+
type: 'application/zip',
|
213
|
+
test_case: true,
|
214
|
+
)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
219
|
+
This example code would attach the trace zip file to Allure report for each test case.
|
220
|
+
|
221
|
+
![add trace image](https://user-images.githubusercontent.com/11763113/282307106-520d800b-67ac-4e14-98bb-75a8bbb98a1f.png)
|
222
|
+
|
223
|
+
We can download and show the trace with `playwright show-trace` command.
|
224
|
+
|
225
|
+
```
|
226
|
+
npx playwright show-trace ababcdcdefef.zip
|
227
|
+
```
|
228
|
+
|
229
|
+
![show-trace image](https://user-images.githubusercontent.com/11763113/282307098-a4167c32-d5e7-4631-a3b6-62d278efbeef.png)
|
230
|
+
|
231
|
+
Instead of the easy configuration using `on_save_trace`, we can also use `page.driver.start_tracing` / `page.driver.stop_tracing` or `page.driver.with_trace do { ... }` for storing the trace with detailed options. See [the PR](https://github.com/YusukeIwaki/capybara-playwright-driver/pull/66) for more details including example codes for RSpec.
|
232
|
+
|
204
233
|
### Limitations
|
205
234
|
|
206
|
-
|
207
|
-
|
208
|
-
|
235
|
+
- Playwright doesn't allow clicking invisible DOM elements or moving elements. `click` sometimes doesn't work as Selenium does. See the detail in https://playwright.dev/docs/actionability/
|
236
|
+
- `current_window.maximize` and `current_window.fullscreen` work only on headful (non-headless) mode, as selenium driver does.
|
237
|
+
- `Capybara::Node::Element#drag_to` does not accept `html5` parameter. HTML5 drag and drop is not fully supported in Playwright.
|
@@ -0,0 +1,59 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 5
|
3
|
+
---
|
4
|
+
|
5
|
+
# Web-First assertions for RSpec
|
6
|
+
|
7
|
+
Playwright introduces clever assertions for E2E testing, so called [web-first assertions](https://playwright.dev/docs/test-assertions).
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
it 'should show username after login' do
|
11
|
+
page.fill('input[name="username"]', 'playwright')
|
12
|
+
page.fill('input[name="password"]', 'password123')
|
13
|
+
page.expect_navigation do
|
14
|
+
page.locator('button[type="submit"]').click
|
15
|
+
end
|
16
|
+
|
17
|
+
dashboard_container = page.locator('.dashboard')
|
18
|
+
|
19
|
+
# Not web-first assertion
|
20
|
+
expect(dashboard_container.text_content).to include('Hi, playwright!')
|
21
|
+
|
22
|
+
# Web-first assertion
|
23
|
+
expect(dashboard_container).to have_text('Hi, playwright!')
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
The spec above have 2 similar expectations. The first one is a normal assertion, which is not web-first. The second one is a web-first assertion, which is introduced by Playwright.
|
28
|
+
|
29
|
+
Imagine the case that 'Hi, playwright!' is shown after loading some data from API server. In this case, the first assertion may fail because 'Hi, playwright!' is not present soon after login. On the other hand, the second assertion automatically waits for the 'Hi, playwright!' to be shown.
|
30
|
+
|
31
|
+
## Configure
|
32
|
+
|
33
|
+
For avoiding matcher name conflicts, web-first assertions are not loaded by default. To enable web-first assertions, we have to configure RSpec as below:
|
34
|
+
|
35
|
+
```ruby title=spec/support/web_first_assertion.rb
|
36
|
+
require 'playwright/test'
|
37
|
+
|
38
|
+
RSpec.configure do |config|
|
39
|
+
# include web-first assertions just for feature specs.
|
40
|
+
config.include Playwright::RSpec::Matchers, type: :feature
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
If you want to use web-first assertions only for some specs, you can include `Playwright::RSpec::Matchers` in the spec file directly.
|
45
|
+
|
46
|
+
```ruby title=spec/system/example_spec.rb
|
47
|
+
require 'rails_helper'
|
48
|
+
require 'playwright/test'
|
49
|
+
|
50
|
+
describe 'example' do
|
51
|
+
include Playwright::RSpec::Matchers
|
52
|
+
|
53
|
+
it 'should work' do
|
54
|
+
...
|
55
|
+
```
|
56
|
+
|
57
|
+
## Matchers
|
58
|
+
|
59
|
+
Please refer to [API doc](/docs/api/locator_assertions).
|
@@ -527,6 +527,49 @@
|
|
527
527
|
|
528
528
|
* ~~new_context~~
|
529
529
|
|
530
|
+
## LocatorAssertions
|
531
|
+
|
532
|
+
* not_to_be_attached
|
533
|
+
* not_to_be_checked
|
534
|
+
* not_to_be_disabled
|
535
|
+
* not_to_be_editable
|
536
|
+
* not_to_be_empty
|
537
|
+
* not_to_be_enabled
|
538
|
+
* not_to_be_focused
|
539
|
+
* not_to_be_hidden
|
540
|
+
* not_to_be_in_viewport
|
541
|
+
* not_to_be_visible
|
542
|
+
* not_to_contain_text
|
543
|
+
* not_to_have_attribute
|
544
|
+
* not_to_have_class
|
545
|
+
* not_to_have_count
|
546
|
+
* not_to_have_css
|
547
|
+
* not_to_have_id
|
548
|
+
* not_to_have_js_property
|
549
|
+
* not_to_have_text
|
550
|
+
* not_to_have_value
|
551
|
+
* not_to_have_values
|
552
|
+
* to_be_attached
|
553
|
+
* to_be_checked
|
554
|
+
* to_be_disabled
|
555
|
+
* to_be_editable
|
556
|
+
* to_be_empty
|
557
|
+
* to_be_enabled
|
558
|
+
* to_be_focused
|
559
|
+
* to_be_hidden
|
560
|
+
* to_be_in_viewport
|
561
|
+
* to_be_visible
|
562
|
+
* to_contain_text
|
563
|
+
* to_have_attribute
|
564
|
+
* to_have_class
|
565
|
+
* to_have_count
|
566
|
+
* to_have_css
|
567
|
+
* to_have_id
|
568
|
+
* to_have_js_property
|
569
|
+
* to_have_text
|
570
|
+
* to_have_value
|
571
|
+
* to_have_values
|
572
|
+
|
530
573
|
## Android
|
531
574
|
|
532
575
|
* ~~connect~~
|
@@ -81,7 +81,7 @@ module.exports = {
|
|
81
81
|
],
|
82
82
|
},
|
83
83
|
],
|
84
|
-
copyright: `Copyright © ${new Date().getFullYear()} @YusukeIwaki. <p>Built with <a href="https://
|
84
|
+
copyright: `Copyright © ${new Date().getFullYear()} @YusukeIwaki. <p>Built with <a href="https://docusaurus.io/">Docusaurus</a>.</p>`,
|
85
85
|
},
|
86
86
|
prism: {
|
87
87
|
additionalLanguages: ['bash', 'ruby'],
|
data/documentation/package.json
CHANGED
@@ -14,14 +14,14 @@
|
|
14
14
|
"write-heading-ids": "docusaurus write-heading-ids"
|
15
15
|
},
|
16
16
|
"dependencies": {
|
17
|
-
"@docusaurus/core": "^
|
18
|
-
"@docusaurus/preset-classic": "^
|
19
|
-
"@mdx-js/react": "^
|
20
|
-
"@svgr/webpack": "^
|
21
|
-
"clsx": "^
|
17
|
+
"@docusaurus/core": "^3.0.0",
|
18
|
+
"@docusaurus/preset-classic": "^3.0.0",
|
19
|
+
"@mdx-js/react": "^3.0.0",
|
20
|
+
"@svgr/webpack": "^8.1.0",
|
21
|
+
"clsx": "^2.0.0",
|
22
22
|
"file-loader": "^6.2.0",
|
23
|
-
"react": "^18.
|
24
|
-
"react-dom": "^18.
|
23
|
+
"react": "^18.2.0",
|
24
|
+
"react-dom": "^18.2.0",
|
25
25
|
"url-loader": "^4.1.1"
|
26
26
|
},
|
27
27
|
"browserslist": {
|