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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/documentation/docs/api/api_request_context.md +1 -2
  3. data/documentation/docs/api/browser.md +10 -14
  4. data/documentation/docs/api/browser_context.md +32 -51
  5. data/documentation/docs/api/browser_type.md +8 -12
  6. data/documentation/docs/api/dialog.md +15 -18
  7. data/documentation/docs/api/download.md +10 -12
  8. data/documentation/docs/api/element_handle.md +9 -7
  9. data/documentation/docs/api/frame.md +28 -55
  10. data/documentation/docs/api/locator.md +24 -23
  11. data/documentation/docs/api/locator_assertions.md +652 -0
  12. data/documentation/docs/api/page.md +53 -103
  13. data/documentation/docs/api/playwright.md +20 -23
  14. data/documentation/docs/api/selectors.md +29 -34
  15. data/documentation/docs/article/guides/rails_integration.md +80 -51
  16. data/documentation/docs/article/guides/rspec_integration.md +59 -0
  17. data/documentation/docs/include/api_coverage.md +43 -0
  18. data/documentation/docusaurus.config.js +1 -1
  19. data/documentation/package.json +7 -7
  20. data/documentation/yarn.lock +4641 -5023
  21. data/lib/playwright/api_response_impl.rb +2 -2
  22. data/lib/playwright/channel.rb +1 -1
  23. data/lib/playwright/channel_owners/api_request_context.rb +12 -3
  24. data/lib/playwright/channel_owners/browser.rb +11 -7
  25. data/lib/playwright/channel_owners/browser_context.rb +35 -15
  26. data/lib/playwright/channel_owners/frame.rb +38 -14
  27. data/lib/playwright/channel_owners/page.rb +29 -16
  28. data/lib/playwright/channel_owners/web_socket.rb +8 -13
  29. data/lib/playwright/connection.rb +18 -2
  30. data/lib/playwright/errors.rb +22 -2
  31. data/lib/playwright/input_files.rb +4 -4
  32. data/lib/playwright/javascript/value_serializer.rb +1 -1
  33. data/lib/playwright/locator_assertions_impl.rb +417 -0
  34. data/lib/playwright/locator_impl.rb +24 -5
  35. data/lib/playwright/test.rb +68 -0
  36. data/lib/playwright/utils.rb +3 -10
  37. data/lib/playwright/version.rb +2 -2
  38. data/lib/playwright/waiter.rb +146 -0
  39. data/lib/playwright.rb +1 -1
  40. data/lib/playwright_api/api_request_context.rb +1 -2
  41. data/lib/playwright_api/browser.rb +2 -2
  42. data/lib/playwright_api/browser_context.rb +3 -3
  43. data/lib/playwright_api/browser_type.rb +2 -1
  44. data/lib/playwright_api/download.rb +1 -2
  45. data/lib/playwright_api/element_handle.rb +4 -1
  46. data/lib/playwright_api/frame.rb +4 -1
  47. data/lib/playwright_api/locator.rb +9 -1
  48. data/lib/playwright_api/locator_assertions.rb +561 -0
  49. data/lib/playwright_api/page.rb +16 -13
  50. data/lib/playwright_api/request.rb +4 -4
  51. data/lib/playwright_api/worker.rb +4 -4
  52. data/sig/playwright.rbs +48 -5
  53. metadata +9 -4
  54. 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
- ```python sync title=example_94e620cdbdfd41e2c9b14d561052ffa89535fc346038c4584ea4dd8520f5401c.py
16
- from playwright.sync_api import sync_playwright, Playwright
17
-
18
- def run(playwright: Playwright):
19
- webkit = playwright.webkit
20
- browser = webkit.launch()
21
- context = browser.new_context()
22
- page = context.new_page()
23
- page.goto("https://example.com")
24
- page.screenshot(path="screenshot.png")
25
- browser.close()
26
-
27
- with sync_playwright() as playwright:
28
- run(playwright)
29
-
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
- - [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event)
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
- ```python sync title=example_4f7d99a72aaea957cc5678ed8728965338d78598d7772f47fbf23c28f0eba52d.py
475
- from playwright.sync_api import sync_playwright, Playwright
476
-
477
- def run(playwright: Playwright):
478
- webkit = playwright.webkit
479
- browser = webkit.launch(headless=false)
480
- context = browser.new_context()
481
- page = context.new_page()
482
- page.expose_binding("pageURL", lambda source: source["page"].url)
483
- page.set_content("""
484
- <script>
485
- async function onClick() {
486
- document.querySelector('div').textContent = await window.pageURL();
487
- }
488
- </script>
489
- <button onclick="onClick()">Click me</button>
490
- <div></div>
491
- """)
492
- page.click("button")
493
-
494
- with sync_playwright() as playwright:
495
- run(playwright)
496
-
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
- ```python sync title=example_0f68a39bdff02a3df161c74e81cabb8a2ff1f09f0d09f6ef9b799a6f2f19a280.py
541
- import hashlib
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
- with sync_playwright() as playwright:
567
- run(playwright)
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
- ```python sync title=example_8260034c740933903e5a39d30a4f4e388bdffa9e82acd9a5fe1fb774752a505a.py
1359
- # Single selection matching the value or label
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="blue")
1334
+ page.select_option("select#colors", label: "blue")
1363
1335
  # multiple selection
1364
- page.select_option("select#colors", value=["red", "green", "blue"])
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
- ```python sync title=example_83eed1f1f00ad73f641bf4a49f672e81c4faf1ca098a4a5070afeeabb88312f5.py
1680
- from playwright.sync_api import sync_playwright, Playwright
1681
-
1682
- def run(playwright: Playwright):
1683
- webkit = playwright.webkit
1684
- browser = webkit.launch()
1685
- page = browser.new_page()
1686
- page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);")
1687
- page.wait_for_function("() => window.x > 0")
1688
- browser.close()
1689
-
1690
- with sync_playwright() as playwright:
1691
- run(playwright)
1692
-
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
- ```python sync title=example_903c7325fd65fcdf6f22c77fc159922a568841abce60ae1b7c54ab5837401862.py
1861
- from playwright.sync_api import sync_playwright, Playwright
1862
-
1863
- def run(playwright: Playwright):
1864
- chromium = playwright.chromium
1865
- browser = chromium.launch()
1866
- page = browser.new_page()
1867
- for current_url in ["https://google.com", "https://bbc.com"]:
1868
- page.goto(current_url, wait_until="domcontentloaded")
1869
- element = page.wait_for_selector("img")
1870
- print("Loaded image: " + str(element.get_attribute("src")))
1871
- browser.close()
1872
-
1873
- with sync_playwright() as playwright:
1874
- run(playwright)
1875
-
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
- ```python sync title=example_6647e5a44b0440884026a6142606dfddad75ba1e643919b015457df4ed2e198f.py
12
- from playwright.sync_api import sync_playwright, Playwright
11
+ ```ruby
12
+ require 'playwright'
13
13
 
14
- def run(playwright: Playwright):
15
- chromium = playwright.chromium # or "firefox" or "webkit".
16
- browser = chromium.launch()
17
- page = browser.new_page()
18
- page.goto("http://example.com")
19
- # other actions...
20
- browser.close()
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
- with sync_playwright() as playwright:
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
- ```python sync title=example_14d627977a4ad16a605ec5472d768a3324812fa8e7c57685561408fa6601e352.py
38
- from playwright.sync_api import sync_playwright, Playwright
36
+ ```ruby
37
+ require 'playwright'
39
38
 
40
- def run(playwright: Playwright):
41
- webkit = playwright.webkit
42
- iphone = playwright.devices["iPhone 6"]
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("http://example.com")
47
- # other actions...
48
- browser.close()
43
+ page = context.new_page
44
+ page.goto('https://example.com/')
49
45
 
50
- with sync_playwright() as playwright:
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
- ```python sync title=example_3e739d4f0e30e20a6a698e0e17605a841c35e65e75aa3c2642f8bfc368b33f9e.py
25
- from playwright.sync_api import sync_playwright, Playwright
26
-
27
- def run(playwright: Playwright):
28
- tag_selector = """
29
- {
30
- // Returns the first element matching given selector in the root's subtree.
31
- query(root, selector) {
32
- return root.querySelector(selector);
33
- },
34
- // Returns all elements matching given selector in the root's subtree.
35
- queryAll(root, selector) {
36
- return Array.from(root.querySelectorAll(selector));
37
- }
38
- }"""
39
-
40
- # Register the engine. Selectors will be prefixed with "tag=".
41
- playwright.selectors.register("tag", tag_selector)
42
- browser = playwright.chromium.launch()
43
- page = browser.new_page()
44
- page.set_content('<div><button>Click me</button></div>')
45
-
46
- # Use the selector prefixed with its name.
47
- button = page.locator('tag=button')
48
- # Combine it with built-in locators.
49
- page.locator('tag=div').get_by_text('Click me').click()
50
- # Can use it in any methods supporting selectors.
51
- button_count = page.locator('tag=button').count()
52
- print(button_count)
53
- browser.close()
54
-
55
- with sync_playwright() as playwright:
56
- run(playwright)
57
-
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 *2 seconds*. Generally it is too short to wait for HTTP responses.
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
- * `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
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
- * `Capybara::Node::Element#drop`
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
- * 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/
207
- * `current_window.maximize` and `current_window.fullscreen` work only on headful (non-headless) mode, as selenium driver does.
208
- * `Capybara::Node::Element#drag_to` does not accept `html5` parameter. HTML5 drag and drop is not fully supported in Playwright.
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://v2.docusaurus.io/">Docusaurus</a>.</p>`,
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'],
@@ -14,14 +14,14 @@
14
14
  "write-heading-ids": "docusaurus write-heading-ids"
15
15
  },
16
16
  "dependencies": {
17
- "@docusaurus/core": "^2.0.1",
18
- "@docusaurus/preset-classic": "^2.0.1",
19
- "@mdx-js/react": "^1.6.22",
20
- "@svgr/webpack": "^6.3.1",
21
- "clsx": "^1.2.1",
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.0.0",
24
- "react-dom": "^18.0.0",
23
+ "react": "^18.2.0",
24
+ "react-dom": "^18.2.0",
25
25
  "url-loader": "^4.1.1"
26
26
  },
27
27
  "browserslist": {