playwright-ruby-client 1.62.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/documentation/docs/api/api_request_context.md +3 -0
  3. data/documentation/docs/api/browser_context.md +3 -3
  4. data/documentation/docs/api/frame.md +12 -1
  5. data/documentation/docs/api/frame_locator.md +20 -0
  6. data/documentation/docs/api/locator.md +28 -0
  7. data/documentation/docs/api/page.md +12 -1
  8. data/documentation/docs/api/tracing.md +3 -1
  9. data/documentation/docs/article/guides/playwright_on_alpine_linux.md +1 -1
  10. data/documentation/docs/include/api_coverage.md +1 -0
  11. data/lib/playwright/api_request_impl.rb +3 -1
  12. data/lib/playwright/channel.rb +2 -1
  13. data/lib/playwright/channel_owners/browser.rb +1 -0
  14. data/lib/playwright/channel_owners/browser_context.rb +17 -2
  15. data/lib/playwright/channel_owners/frame.rb +2 -2
  16. data/lib/playwright/channel_owners/page.rb +2 -1
  17. data/lib/playwright/channel_owners/tracing.rb +43 -13
  18. data/lib/playwright/events.rb +2 -0
  19. data/lib/playwright/frame_locator_impl.rb +20 -5
  20. data/lib/playwright/locator_impl.rb +4 -0
  21. data/lib/playwright/utils.rb +12 -0
  22. data/lib/playwright/version.rb +2 -2
  23. data/lib/playwright_api/api_request_context.rb +9 -7
  24. data/lib/playwright_api/browser.rb +6 -6
  25. data/lib/playwright_api/browser_context.rb +17 -17
  26. data/lib/playwright_api/browser_type.rb +6 -6
  27. data/lib/playwright_api/cdp_session.rb +6 -6
  28. data/lib/playwright_api/dialog.rb +6 -6
  29. data/lib/playwright_api/element_handle.rb +6 -6
  30. data/lib/playwright_api/frame.rb +25 -14
  31. data/lib/playwright_api/frame_locator.rb +20 -0
  32. data/lib/playwright_api/js_handle.rb +6 -6
  33. data/lib/playwright_api/locator.rb +25 -0
  34. data/lib/playwright_api/page.rb +28 -17
  35. data/lib/playwright_api/playwright.rb +6 -6
  36. data/lib/playwright_api/request.rb +8 -8
  37. data/lib/playwright_api/response.rb +6 -6
  38. data/lib/playwright_api/route.rb +6 -6
  39. data/lib/playwright_api/tracing.rb +10 -8
  40. data/lib/playwright_api/web_socket.rb +6 -6
  41. data/lib/playwright_api/worker.rb +8 -8
  42. data/sig/playwright.rbs +9 -8
  43. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c78e6a1f2ee45aadb2b8a027d08a0264560172b843419e23376c80f74095ccd
4
- data.tar.gz: b31e8c1c972865e68312f65ee23a821535f14592affadcc65580b10169819b81
3
+ metadata.gz: 275e62d0e3c798dd08cdb59a52299af990f93b7fd5fe1cf2a1f9b1c5441a1680
4
+ data.tar.gz: 1711ed5665344b5c52b6f45c2621e03e2ac8983d698e6717303cad3bbb80659b
5
5
  SHA512:
6
- metadata.gz: de6ea998c746c0fa3107850695144b7204105c01daa6209f646c2a172bd59eb906e169b4b7ed7dca436e8084611496def05fc81bb23134d8475bedbc480d6fd5
7
- data.tar.gz: 907612d4a87117af9d0c57ada0ec4144f7451f7a75176b2b93d3cf896ff6ce8492f7e72ff8a2c04ce1d5d2871fdf9af2f967de9e5175010574d09c276b160300
6
+ metadata.gz: 9180d7ceb51f46c828e8a08aaffdd1e813bc57b842f268556990030a9003686841842cd8d3f5c98ea8b5c2ea3e6fdb63a4ff45afb6e44adb2b2a9a6c7c6ef861
7
+ data.tar.gz: 5efd8cd40f2e8b5d2cf2e22943ae6df4e3791b66874ca3cb0f72bbb66a1bd50442e8e481c990eed9fe958f4bfe82102e58634c5bfd2bc1823a0ff25b16036bbf
@@ -298,3 +298,6 @@ The method will populate request cookies from the context and update
298
298
  context cookies from the response. The method will automatically follow redirects.
299
299
 
300
300
  ## tracing
301
+
302
+
303
+ Tracing recorder for requests made through this API request context.
@@ -434,11 +434,11 @@ alias: `offline=`
434
434
  ## storage_state
435
435
 
436
436
  ```
437
- def storage_state(credentials: nil, 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, IndexedDB snapshot and virtual WebAuthn credentials.
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,7 @@ def set_storage_state(storageState)
448
448
  alias: `storage_state=`
449
449
 
450
450
 
451
- Clears the existing cookies, local storage, IndexedDB entries and virtual WebAuthn credentials, and sets the new 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
452
  state. When the storage state contains credentials, the virtual WebAuthn authenticator is installed (equivalent to
453
453
  [Credentials#install](./credentials#install)), preventing all real authenticators from working in this context.
454
454
 
@@ -391,13 +391,17 @@ puts frame == content_frame # => true
391
391
  ## frame_locator
392
392
 
393
393
  ```
394
- def frame_locator(selector)
394
+ def frame_locator(selector = nil)
395
395
  ```
396
396
 
397
397
 
398
398
  When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements
399
399
  in that iframe.
400
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
+
401
405
  **Usage**
402
406
 
403
407
  Following snippet locates element with text "Submit" in the iframe with id `my-frame`, like `<iframe id="my-frame">`:
@@ -407,6 +411,13 @@ locator = frame.frame_locator("#my-iframe").get_by_text("Submit")
407
411
  locator.click
408
412
  ```
409
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
+
410
421
  ## get_attribute
411
422
 
412
423
  ```
@@ -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).
@@ -1531,6 +1531,34 @@ If the element is detached from the DOM at any moment during the action, this me
1531
1531
  When all steps combined have not finished during the specified `timeout`, this method throws a
1532
1532
  `TimeoutError`. Passing zero timeout disables this.
1533
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
+
1534
1562
  ## wait_for
1535
1563
 
1536
1564
  ```
@@ -585,13 +585,17 @@ frame = page.frame(url: /.*domain.*/)
585
585
  ## frame_locator
586
586
 
587
587
  ```
588
- def frame_locator(selector)
588
+ def frame_locator(selector = nil)
589
589
  ```
590
590
 
591
591
 
592
592
  When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements
593
593
  in that iframe.
594
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
+
595
599
  **Usage**
596
600
 
597
601
  Following snippet locates element with text "Submit" in the iframe with id `my-frame`,
@@ -602,6 +606,13 @@ locator = page.frame_locator("#my-iframe").get_by_text("Submit")
602
606
  locator.click
603
607
  ```
604
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
+
605
616
  ## frames
606
617
 
607
618
  ```
@@ -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 [BrowserContext](./browser_context).
91
+ Only one HAR recording can be active at a time per [Tracing](./tracing) instance.
90
92
 
91
93
  **Usage**
92
94
 
@@ -83,7 +83,7 @@ If custom Docker image is preferred, build it as follows:
83
83
  FROM mcr.microsoft.com/playwright
84
84
 
85
85
  WORKDIR /root
86
- ARG PLAYWRIGHT_CORE_VERSION=1.62.1
86
+ ARG PLAYWRIGHT_CORE_VERSION=1.63.0
87
87
  RUN npm install "playwright-core@$PLAYWRIGHT_CORE_VERSION" && ./node_modules/.bin/playwright-core install
88
88
 
89
89
  ENV PORT 8888
@@ -530,6 +530,7 @@
530
530
  * text_content
531
531
  * type
532
532
  * uncheck
533
+ * visible
533
534
  * wait_for
534
535
  * wait_for_function
535
536
 
@@ -3,6 +3,8 @@ require 'json'
3
3
 
4
4
  module Playwright
5
5
  define_api_implementation :APIRequestImpl do
6
+ include Utils::PrepareHttpCredentials
7
+
6
8
  def initialize(playwright)
7
9
  @playwright = playwright
8
10
  end
@@ -24,7 +26,7 @@ module Playwright
24
26
  clientCertificates: prepare_client_certificates(clientCertificates),
25
27
  extraHTTPHeaders: extraHTTPHeaders ? HttpHeaders.new(extraHTTPHeaders).as_serialized : nil,
26
28
  failOnStatusCode: failOnStatusCode,
27
- httpCredentials: httpCredentials,
29
+ httpCredentials: prepare_http_credentials(httpCredentials),
28
30
  ignoreHTTPSErrors: ignoreHTTPSErrors,
29
31
  maxRedirects: maxRedirects,
30
32
  proxy: proxy,
@@ -75,7 +75,8 @@ module Playwright
75
75
  wallTime: (Time.now.to_f * 1000).to_i,
76
76
  apiName: api_name,
77
77
  stack: stacks.map do |loc|
78
- { file: loc.absolute_path || '', line: loc.lineno, function: loc.label }
78
+ # Ruby backtraces do not provide a column, but the trace protocol requires one.
79
+ { file: loc.absolute_path || '', line: loc.lineno, column: 0, function: loc.label }
79
80
  end,
80
81
  }
81
82
  end
@@ -156,6 +156,7 @@ module Playwright
156
156
 
157
157
  private def setup_browser_context(context)
158
158
  context.tracing.send(:update_traces_dir, @traces_dir)
159
+ context.request.tracing.send(:update_traces_dir, @traces_dir)
159
160
  @browser_type.send(:playwright_selectors_browser_contexts) << context
160
161
  end
161
162
 
@@ -42,6 +42,11 @@ module Playwright
42
42
  @channel.on('dialog', ->(params) {
43
43
  on_dialog(ChannelOwners::Dialog.from(params['dialog']))
44
44
  })
45
+ @channel.on('dialogClosed', ->(params) {
46
+ dialog = ChannelOwners::Dialog.from(params['dialog'])
47
+ emit(Events::BrowserContext::DialogClosed, dialog)
48
+ dialog.page&.emit(Events::Page::DialogClosed, dialog)
49
+ })
45
50
  @channel.on('request', ->(params) {
46
51
  on_request(
47
52
  ChannelOwners::Request.from(params['request']),
@@ -69,6 +74,7 @@ module Playwright
69
74
  set_event_to_subscription_mapping({
70
75
  Events::BrowserContext::Console => 'console',
71
76
  Events::BrowserContext::Dialog => 'dialog',
77
+ Events::BrowserContext::DialogClosed => 'dialogClosed',
72
78
  Events::BrowserContext::Request => "request",
73
79
  Events::BrowserContext::Response => "response",
74
80
  Events::BrowserContext::RequestFinished => "requestFinished",
@@ -93,6 +99,7 @@ module Playwright
93
99
  private def update_options(context_options:, browser_options:)
94
100
  @options = context_options
95
101
  @tracing.send(:update_traces_dir, browser_options[:tracesDir])
102
+ @request.tracing.send(:update_traces_dir, browser_options[:tracesDir])
96
103
  end
97
104
 
98
105
  private def on_page(page)
@@ -418,6 +425,7 @@ module Playwright
418
425
  @browser.browser_type.send(:playwright_selectors_browser_contexts).delete(self)
419
426
  end
420
427
  @tracing.send(:reset_stack_counter)
428
+ @request.tracing.send(:reset_stack_counter)
421
429
  emit(Events::BrowserContext::Close)
422
430
  @closed_promise.fulfill(true)
423
431
  end
@@ -427,9 +435,15 @@ module Playwright
427
435
  @close_was_called = true
428
436
  @close_reason = reason
429
437
  @request.dispose(reason: reason)
430
- @tracing.send(:export_all_hars)
438
+ har_error = nil
439
+ begin
440
+ @tracing.send(:export_all_hars)
441
+ rescue => error
442
+ har_error = error
443
+ end
431
444
  @channel.send_message_to_server('close', { reason: reason }.compact)
432
445
  @closed_promise.value!
446
+ raise har_error if har_error
433
447
  nil
434
448
  end
435
449
 
@@ -462,9 +476,10 @@ module Playwright
462
476
  @channel.send_message_to_server('pause')
463
477
  end
464
478
 
465
- def storage_state(path: nil, indexedDB: nil, credentials: nil)
479
+ def storage_state(path: nil, indexedDB: nil, opfs: nil, credentials: nil)
466
480
  params = {
467
481
  indexedDB: indexedDB,
482
+ opfs: opfs,
468
483
  credentials: credentials,
469
484
  }.compact
470
485
  @channel.send_message_to_server_result('storageState', params).tap do |result|
@@ -506,8 +506,8 @@ module Playwright
506
506
  hasText: hasText)
507
507
  end
508
508
 
509
- def frame_locator(selector)
510
- FrameLocatorImpl.new(frame: self, frame_selector: selector)
509
+ def frame_locator(selector = nil)
510
+ FrameLocatorImpl.new(frame: self, frame_selector: selector || 'internal:control=any-frame')
511
511
  end
512
512
 
513
513
  def focus(selector, strict: nil, timeout: nil)
@@ -72,6 +72,7 @@ module Playwright
72
72
  set_event_to_subscription_mapping({
73
73
  Events::Page::Console => "console",
74
74
  Events::Page::Dialog => "dialog",
75
+ Events::Page::DialogClosed => "dialogClosed",
75
76
  Events::Page::Request => "request",
76
77
  Events::Page::Response => "response",
77
78
  Events::Page::RequestFinished => "requestFinished",
@@ -723,7 +724,7 @@ module Playwright
723
724
  hasText: hasText)
724
725
  end
725
726
 
726
- def frame_locator(selector)
727
+ def frame_locator(selector = nil)
727
728
  @main_frame.frame_locator(selector)
728
729
  end
729
730
 
@@ -5,15 +5,16 @@ module Playwright
5
5
  @har_id = nil
6
6
  end
7
7
 
8
- def start(name: nil, title: nil, screenshots: nil, snapshots: nil, sources: nil, live: nil)
8
+ def start(name: nil, title: nil, screenshots: nil, snapshots: nil, ariaSnapshots: nil, screenSnapshots: nil, sources: nil, live: nil)
9
9
  params = {
10
10
  name: name,
11
- screenshots: screenshots,
12
- snapshots: snapshots,
13
- sources: sources,
11
+ screencast: screenshots,
12
+ snapshotDom: snapshots,
13
+ snapshotAria: ariaSnapshots,
14
+ snapshotScreen: screenSnapshots,
14
15
  live: live,
15
16
  }.compact
16
- @include_sources = params[:sources] || false
17
+ @include_sources = sources || false
17
18
  @channel.send_message_to_server('tracingStart', params)
18
19
  trace_name = @channel.send_message_to_server('tracingStartChunk', { title: title, name: name }.compact)
19
20
  start_collecting_stacks(trace_name)
@@ -38,19 +39,43 @@ module Playwright
38
39
  end
39
40
 
40
41
  def stop(path: nil)
41
- do_stop_chunk(file_path: path)
42
+ save_error = nil
43
+ begin
44
+ do_stop_chunk(file_path: path)
45
+ rescue => error
46
+ save_error = error
47
+ end
42
48
  @channel.send_message_to_server('tracingStop')
49
+ raise save_error if save_error
43
50
  end
44
51
 
45
52
  private def do_stop_chunk(file_path:)
46
53
  reset_stack_counter
54
+ stacks_id = @stacks_id
55
+ @stacks_id = nil
56
+ begin
57
+ save_chunk(file_path: file_path, stacks_id: stacks_id)
58
+ rescue
59
+ # Release the session even if saving fails so subsequent traces start fresh.
60
+ if stacks_id
61
+ begin
62
+ @connection.local_utils&.trace_discarded(stacks_id)
63
+ rescue
64
+ # Preserve the error from saving the trace.
65
+ end
66
+ end
67
+ raise
68
+ end
69
+ end
70
+
71
+ private def save_chunk(file_path:, stacks_id:)
47
72
  local_utils = @connection.local_utils
48
73
 
49
74
  unless file_path
50
75
  # Not interested in any artifacts
51
76
  @channel.send_message_to_server('tracingStopChunk', mode: 'discard')
52
- if @stacks_id
53
- local_utils.trace_discarded(@stacks_id) if local_utils
77
+ if stacks_id
78
+ local_utils.trace_discarded(stacks_id) if local_utils
54
79
  end
55
80
 
56
81
  return
@@ -66,7 +91,7 @@ module Playwright
66
91
  local_utils.zip(
67
92
  zipFile: file_path,
68
93
  entries: result['entries'],
69
- stacksId: @stacks_id,
94
+ stacksId: stacks_id,
70
95
  mode: 'write',
71
96
  includeSources: @include_sources,
72
97
  )
@@ -78,8 +103,8 @@ module Playwright
78
103
  result = @channel.send_message_to_server_result('tracingStopChunk', mode: 'archive')
79
104
  # The artifact may be missing if the browser closed while stopping tracing.
80
105
  unless result['artifact']
81
- if @stacks_id
82
- local_utils.trace_discarded(@stacks_id) if local_utils
106
+ if stacks_id
107
+ local_utils.trace_discarded(stacks_id) if local_utils
83
108
  end
84
109
 
85
110
  return
@@ -87,7 +112,12 @@ module Playwright
87
112
 
88
113
  # Save trace to the final local file.
89
114
  artifact = ChannelOwners::Artifact.from(result['artifact'])
90
- artifact.save_as(file_path)
115
+ begin
116
+ artifact.save_as(file_path)
117
+ rescue
118
+ artifact.delete rescue nil
119
+ raise
120
+ end
91
121
  artifact.delete
92
122
 
93
123
  return unless local_utils
@@ -95,7 +125,7 @@ module Playwright
95
125
  local_utils.zip(
96
126
  zipFile: file_path,
97
127
  entries: [],
98
- stacksId: @stacks_id,
128
+ stacksId: stacks_id,
99
129
  mode: 'append',
100
130
  includeSources: @include_sources,
101
131
  )
@@ -29,6 +29,7 @@ end
29
29
  Close: 'close',
30
30
  Console: 'console',
31
31
  Dialog: 'dialog',
32
+ DialogClosed: 'dialogclosed',
32
33
  Download: 'download',
33
34
  FrameAttached: 'frameattached',
34
35
  FrameDetached: 'framedetached',
@@ -53,6 +54,7 @@ end
53
54
  Crash: 'crash',
54
55
  Console: 'console',
55
56
  Dialog: 'dialog',
57
+ DialogClosed: 'dialogclosed',
56
58
  Download: 'download',
57
59
  FileChooser: 'filechooser',
58
60
  DOMContentLoaded: 'domcontentloaded',
@@ -13,6 +13,21 @@ module Playwright
13
13
  @frame.send(:_timeout, timeout)
14
14
  end
15
15
 
16
+ private def child_selector(selector)
17
+ if @frame_selector == 'internal:control=any-frame'
18
+ "#{@frame_selector} >> #{selector}"
19
+ else
20
+ "#{@frame_selector} >> internal:control=enter-frame >> #{selector}"
21
+ end
22
+ end
23
+
24
+ private def nth_selector(index)
25
+ if @frame_selector == 'internal:control=any-frame'
26
+ raise 'Selecting the nth frame is not allowed on frameLocator().'
27
+ end
28
+ "#{@frame_selector} >> nth=#{index}"
29
+ end
30
+
16
31
  def locator(
17
32
  selector,
18
33
  has: nil,
@@ -21,7 +36,7 @@ module Playwright
21
36
  hasText: nil)
22
37
  LocatorImpl.new(
23
38
  frame: @frame,
24
- selector: "#{@frame_selector} >> internal:control=enter-frame >> #{selector}",
39
+ selector: child_selector(selector),
25
40
  has: has,
26
41
  hasNot: hasNot,
27
42
  hasNotText: hasNotText,
@@ -38,28 +53,28 @@ module Playwright
38
53
  def frame_locator(selector)
39
54
  FrameLocatorImpl.new(
40
55
  frame: @frame,
41
- frame_selector: "#{@frame_selector} >> internal:control=enter-frame >> #{selector}",
56
+ frame_selector: child_selector(selector),
42
57
  )
43
58
  end
44
59
 
45
60
  def first
46
61
  FrameLocatorImpl.new(
47
62
  frame: @frame,
48
- frame_selector: "#{@frame_selector} >> nth=0",
63
+ frame_selector: nth_selector(0),
49
64
  )
50
65
  end
51
66
 
52
67
  def last
53
68
  FrameLocatorImpl.new(
54
69
  frame: @frame,
55
- frame_selector: "#{@frame_selector} >> nth=-1",
70
+ frame_selector: nth_selector(-1),
56
71
  )
57
72
  end
58
73
 
59
74
  def nth(index)
60
75
  FrameLocatorImpl.new(
61
76
  frame: @frame,
62
- frame_selector: "#{@frame_selector} >> nth=#{index}",
77
+ frame_selector: nth_selector(index),
63
78
  )
64
79
  end
65
80
  end
@@ -296,6 +296,10 @@ module Playwright
296
296
  )
297
297
  end
298
298
 
299
+ def visible
300
+ filter(visible: true)
301
+ end
302
+
299
303
  def first
300
304
  LocatorImpl.new(
301
305
  frame: @frame,
@@ -18,9 +18,21 @@ module Playwright
18
18
  end
19
19
 
20
20
  module Utils
21
+ module PrepareHttpCredentials
22
+ private def prepare_http_credentials(credentials)
23
+ return nil unless credentials
24
+
25
+ list = credentials.is_a?(Array) ? credentials : [credentials]
26
+ list.empty? ? nil : list
27
+ end
28
+ end
29
+
21
30
  module PrepareBrowserContextOptions
31
+ include PrepareHttpCredentials
32
+
22
33
  # @see https://github.com/microsoft/playwright/blob/5a2cfdbd47ed3c3deff77bb73e5fac34241f649d/src/client/browserContext.ts#L265
23
34
  private def prepare_browser_context_options(params)
35
+ params[:httpCredentials] = prepare_http_credentials(params[:httpCredentials])
24
36
  if params[:noViewport] == 0
25
37
  params.delete(:noViewport)
26
38
  params[:noDefaultViewport] = true
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playwright
4
- VERSION = '1.62.0'
5
- COMPATIBLE_PLAYWRIGHT_VERSION = '1.62.1'
4
+ VERSION = '1.63.0'
5
+ COMPATIBLE_PLAYWRIGHT_VERSION = '1.63.0'
6
6
  end
@@ -67,6 +67,8 @@ module Playwright
67
67
  # ```
68
68
  class APIRequestContext < PlaywrightApi
69
69
 
70
+ #
71
+ # Tracing recorder for requests made through this API request context.
70
72
  def tracing # property
71
73
  wrap_impl(@impl.tracing)
72
74
  end
@@ -286,26 +288,26 @@ module Playwright
286
288
 
287
289
  #
288
290
  # Returns storage state for this request context, contains current cookies and local storage snapshot if it was passed to the constructor.
289
- def storage_state(indexedDB: nil, path: nil)
291
+ def storage_state(indexedDB: nil, opfs: nil, path: nil)
290
292
  raise NotImplementedError.new('storage_state is not implemented yet.')
291
293
  end
292
294
 
293
295
  # -- inherited from EventEmitter --
294
296
  # @nodoc
295
- def once(event, callback)
296
- event_emitter_proxy.once(event, callback)
297
+ def off(event, callback)
298
+ event_emitter_proxy.off(event, callback)
297
299
  end
298
300
 
299
301
  # -- inherited from EventEmitter --
300
302
  # @nodoc
301
- def on(event, callback)
302
- event_emitter_proxy.on(event, callback)
303
+ def once(event, callback)
304
+ event_emitter_proxy.once(event, callback)
303
305
  end
304
306
 
305
307
  # -- inherited from EventEmitter --
306
308
  # @nodoc
307
- def off(event, callback)
308
- event_emitter_proxy.off(event, callback)
309
+ def on(event, callback)
310
+ event_emitter_proxy.on(event, callback)
309
311
  end
310
312
 
311
313
  private def event_emitter_proxy
@@ -217,20 +217,20 @@ module Playwright
217
217
 
218
218
  # -- inherited from EventEmitter --
219
219
  # @nodoc
220
- def once(event, callback)
221
- event_emitter_proxy.once(event, callback)
220
+ def off(event, callback)
221
+ event_emitter_proxy.off(event, callback)
222
222
  end
223
223
 
224
224
  # -- inherited from EventEmitter --
225
225
  # @nodoc
226
- def on(event, callback)
227
- event_emitter_proxy.on(event, callback)
226
+ def once(event, callback)
227
+ event_emitter_proxy.once(event, callback)
228
228
  end
229
229
 
230
230
  # -- inherited from EventEmitter --
231
231
  # @nodoc
232
- def off(event, callback)
233
- event_emitter_proxy.off(event, callback)
232
+ def on(event, callback)
233
+ event_emitter_proxy.on(event, callback)
234
234
  end
235
235
 
236
236
  private def event_emitter_proxy