playwright-ruby-client 1.25.0 → 1.27.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/documentation/docs/api/api_request_context.md +93 -0
  3. data/documentation/docs/api/browser_context.md +3 -3
  4. data/documentation/docs/api/browser_type.md +8 -0
  5. data/documentation/docs/api/download.md +1 -1
  6. data/documentation/docs/api/element_handle.md +1 -1
  7. data/documentation/docs/api/file_chooser.md +1 -1
  8. data/documentation/docs/api/frame.md +103 -4
  9. data/documentation/docs/api/frame_locator.md +105 -5
  10. data/documentation/docs/api/locator.md +121 -6
  11. data/documentation/docs/api/page.md +119 -10
  12. data/documentation/docs/api/tracing.md +1 -1
  13. data/documentation/docs/article/guides/rails_integration_with_null_driver.md +59 -0
  14. data/documentation/docs/include/api_coverage.md +29 -0
  15. data/documentation/src/components/HomepageFeatures.js +1 -1
  16. data/lib/playwright/channel_owners/api_request_context.rb +23 -120
  17. data/lib/playwright/channel_owners/browser_context.rb +4 -5
  18. data/lib/playwright/channel_owners/dialog.rb +1 -1
  19. data/lib/playwright/channel_owners/frame.rb +4 -0
  20. data/lib/playwright/channel_owners/page.rb +7 -6
  21. data/lib/playwright/channel_owners/selectors.rb +4 -0
  22. data/lib/playwright/frame_locator_impl.rb +6 -2
  23. data/lib/playwright/locator_impl.rb +7 -31
  24. data/lib/playwright/locator_utils.rb +142 -0
  25. data/lib/playwright/route_handler.rb +2 -2
  26. data/lib/playwright/version.rb +2 -2
  27. data/lib/playwright_api/api_request_context.rb +92 -7
  28. data/lib/playwright_api/browser_context.rb +3 -3
  29. data/lib/playwright_api/browser_type.rb +6 -0
  30. data/lib/playwright_api/download.rb +1 -1
  31. data/lib/playwright_api/element_handle.rb +1 -1
  32. data/lib/playwright_api/file_chooser.rb +1 -1
  33. data/lib/playwright_api/frame.rb +78 -4
  34. data/lib/playwright_api/frame_locator.rb +79 -4
  35. data/lib/playwright_api/locator.rb +94 -5
  36. data/lib/playwright_api/page.rb +93 -10
  37. data/lib/playwright_api/request.rb +4 -4
  38. data/lib/playwright_api/response.rb +4 -4
  39. data/lib/playwright_api/selectors.rb +11 -0
  40. data/lib/playwright_api/tracing.rb +1 -1
  41. data/lib/playwright_api/worker.rb +4 -4
  42. metadata +4 -3
@@ -276,6 +276,20 @@ def drag_and_drop(
276
276
  trial: nil)
277
277
  ```
278
278
 
279
+ This method drags the source element to the target element. It will first move to the source element, perform a
280
+ `mousedown`, then move to the target element and perform a `mouseup`.
281
+
282
+ ```ruby
283
+ page.drag_and_drop("#source", "#target")
284
+ # or specify exact positions relative to the top-left corners of the elements:
285
+ page.drag_and_drop(
286
+ "#source",
287
+ "#target",
288
+ sourcePosition: { x: 34, y: 7 },
289
+ targetPosition: { x: 10, y: 20 },
290
+ )
291
+ ```
292
+
279
293
 
280
294
 
281
295
  ## emulate_media
@@ -592,7 +606,7 @@ that iframe. Following snippet locates element with text "Submit" in the iframe
592
606
  id="my-frame">`:
593
607
 
594
608
  ```ruby
595
- locator = page.frame_locator("#my-iframe").locator("text=Submit")
609
+ locator = page.frame_locator("#my-iframe").get_by_text("Submit")
596
610
  locator.click
597
611
  ```
598
612
 
@@ -614,6 +628,103 @@ def get_attribute(selector, name, strict: nil, timeout: nil)
614
628
 
615
629
  Returns element attribute value.
616
630
 
631
+ ## get_by_alt_text
632
+
633
+ ```
634
+ def get_by_alt_text(text, exact: nil)
635
+ ```
636
+
637
+ Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
638
+
639
+ ```html
640
+ <img alt='Castle'>
641
+ ```
642
+
643
+
644
+ ## get_by_label
645
+
646
+ ```
647
+ def get_by_label(text, exact: nil)
648
+ ```
649
+
650
+ Allows locating input elements by the text of the associated label. For example, this method will find the input by
651
+ label text Password in the following DOM:
652
+
653
+ ```html
654
+ <label for="password-input">Password:</label>
655
+ <input id="password-input">
656
+ ```
657
+
658
+
659
+ ## get_by_placeholder
660
+
661
+ ```
662
+ def get_by_placeholder(text, exact: nil)
663
+ ```
664
+
665
+ Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
666
+ "Country":
667
+
668
+ ```html
669
+ <input placeholder="Country">
670
+ ```
671
+
672
+
673
+ ## get_by_role
674
+
675
+ ```
676
+ def get_by_role(
677
+ role,
678
+ checked: nil,
679
+ disabled: nil,
680
+ expanded: nil,
681
+ includeHidden: nil,
682
+ level: nil,
683
+ name: nil,
684
+ pressed: nil,
685
+ selected: nil)
686
+ ```
687
+
688
+ Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
689
+ [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
690
+ [accessible name](https://w3c.github.io/accname/#dfn-accessible-name). Note that role selector **does not replace**
691
+ accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
692
+
693
+ Note that many html elements have an implicitly
694
+ [defined role](https://w3c.github.io/html-aam/#html-element-role-mappings) that is recognized by the role selector. You
695
+ can find all the [supported roles here](https://www.w3.org/TR/wai-aria-1.2/#role_definitions). ARIA guidelines **do not
696
+ recommend** duplicating implicit roles and attributes by setting `role` and/or `aria-*` attributes to default values.
697
+
698
+ ## get_by_test_id
699
+
700
+ ```
701
+ def get_by_test_id(testId)
702
+ ```
703
+
704
+ Locate element by the test id. By default, the `data-testid` attribute is used as a test id. Use
705
+ [Selectors#set_test_id_attribute](./selectors#set_test_id_attribute) to configure a different test id attribute if necessary.
706
+
707
+ ## get_by_text
708
+
709
+ ```
710
+ def get_by_text(text, exact: nil)
711
+ ```
712
+
713
+ Allows locating elements that contain given text.
714
+
715
+ ## get_by_title
716
+
717
+ ```
718
+ def get_by_title(text, exact: nil)
719
+ ```
720
+
721
+ Allows locating elements by their title. For example, this method will find the button by its title "Submit":
722
+
723
+ ```html
724
+ <button title='Place the order'>Order Now</button>
725
+ ```
726
+
727
+
617
728
  ## go_back
618
729
 
619
730
  ```
@@ -780,14 +891,12 @@ considered not visible.
780
891
  def locator(selector, has: nil, hasText: nil)
781
892
  ```
782
893
 
783
- The method returns an element locator that can be used to perform actions on the page. Locator is resolved to the
784
- element immediately before performing an action, so a series of actions on the same locator can in fact be performed on
785
- different DOM elements. That would happen if the DOM structure between those actions has changed.
894
+ The method returns an element locator that can be used to perform actions on this page / frame. Locator is resolved to
895
+ the element immediately before performing an action, so a series of actions on the same locator can in fact be performed
896
+ on different DOM elements. That would happen if the DOM structure between those actions has changed.
786
897
 
787
898
  [Learn more about locators](https://playwright.dev/python/docs/locators).
788
899
 
789
- Shortcut for main frame's [Frame#locator](./frame#locator).
790
-
791
900
  ## main_frame
792
901
 
793
902
  ```
@@ -1364,7 +1473,7 @@ value. Will throw an error if the page is closed before the event is fired. Retu
1364
1473
 
1365
1474
  ```ruby
1366
1475
  frame = page.expect_event("framenavigated") do
1367
- page.click("button")
1476
+ page.get_by_role("button")
1368
1477
  end
1369
1478
  ```
1370
1479
 
@@ -1415,13 +1524,13 @@ This resolves when the page reaches a required load state, `load` by default. Th
1415
1524
  when this method is called. If current document has already reached the required state, resolves immediately.
1416
1525
 
1417
1526
  ```ruby
1418
- page.click("button") # click triggers navigation.
1527
+ page.get_by_role("button").click # click triggers navigation.
1419
1528
  page.wait_for_load_state # the promise resolves after "load" event.
1420
1529
  ```
1421
1530
 
1422
1531
  ```ruby
1423
1532
  popup = page.expect_popup do
1424
- page.click("button") # click triggers a popup.
1533
+ page.get_by_role("button").click # click triggers a popup.
1425
1534
  end
1426
1535
 
1427
1536
  # Following resolves after "domcontentloaded" event.
@@ -1541,7 +1650,7 @@ Returns when element specified by selector satisfies `state` option. Returns `nu
1541
1650
  `detached`.
1542
1651
 
1543
1652
  > NOTE: Playwright automatically waits for element to be ready before performing an action. Using [Locator](./locator) objects and
1544
- web-first assertions make the code wait-for-selector-free.
1653
+ web-first assertions makes the code wait-for-selector-free.
1545
1654
 
1546
1655
  Wait for the `selector` to satisfy `state` option (either appear/disappear from dom, or become visible/hidden). If at
1547
1656
  the moment of calling the method `selector` already satisfies the condition, the method will return immediately. If the
@@ -58,7 +58,7 @@ page = context.new_page
58
58
  page.goto("https://playwright.dev")
59
59
 
60
60
  context.tracing.start_chunk
61
- page.locator("text=Get Started").click
61
+ page.get_by_text("Get Started").click
62
62
  # Everything between start_chunk and stop_chunk will be recorded in the trace.
63
63
  context.tracing.stop_chunk(path: "trace1.zip")
64
64
 
@@ -84,3 +84,62 @@ describe 'example', driver: :null do
84
84
  end
85
85
  end
86
86
  ```
87
+
88
+ ## Minitest Usage
89
+
90
+ We can do something similar with the default Rails setup using Minitest. Here's the same example written with Minitest:
91
+
92
+ ```rb
93
+ # test/application_system_test_case.rb
94
+
95
+ require 'playwright'
96
+
97
+ class CapybaraNullDriver < Capybara::Driver::Base
98
+ def needs_server?
99
+ true
100
+ end
101
+ end
102
+
103
+ Capybara.register_driver(:null) { CapybaraNullDriver.new }
104
+
105
+ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
106
+ driven_by :null
107
+
108
+ def self.playwright
109
+ @playwright ||= Playwright.create(playwright_cli_executable_path: Rails.root.join("node_modules/.bin/playwright"))
110
+ end
111
+
112
+ def before_setup
113
+ super
114
+ base_url = Capybara.current_session.server.base_url
115
+ @playwright_browser = self.class.playwright.playwright.chromium.launch(headless: false)
116
+ @playwright_page = @playwright_browser.new_page(baseURL: base_url)
117
+ end
118
+
119
+ def after_teardown
120
+ super
121
+ @browser.close
122
+ end
123
+ end
124
+ ```
125
+
126
+ And here is the same test:
127
+
128
+ ```rb
129
+ require "application_system_test_case"
130
+
131
+ class ExampleTest < ApplicationSystemTestCase
132
+ def setup
133
+ @user = User.create!
134
+ @page = @playwright_page
135
+ end
136
+
137
+ test 'can browse' do
138
+ @page.goto("/tests/#{user.id}")
139
+ @page.wait_for_selector('input').type('hoge')
140
+ @page.keyboard.press('Enter')
141
+
142
+ assert @page.text_content('#content').include?('hoge')
143
+ end
144
+ end
145
+ ```
@@ -159,6 +159,13 @@
159
159
  * frame_element
160
160
  * frame_locator
161
161
  * get_attribute
162
+ * get_by_alt_text
163
+ * get_by_label
164
+ * get_by_placeholder
165
+ * get_by_role
166
+ * get_by_test_id
167
+ * get_by_text
168
+ * get_by_title
162
169
  * goto
163
170
  * hover
164
171
  * inner_html
@@ -204,6 +211,7 @@
204
211
  ## Selectors
205
212
 
206
213
  * register
214
+ * ~~set_test_id_attribute~~
207
215
 
208
216
  ## ConsoleMessage
209
217
 
@@ -258,6 +266,13 @@
258
266
  * frame_locator
259
267
  * frames
260
268
  * get_attribute
269
+ * get_by_alt_text
270
+ * get_by_label
271
+ * get_by_placeholder
272
+ * get_by_role
273
+ * get_by_test_id
274
+ * get_by_text
275
+ * get_by_title
261
276
  * go_back
262
277
  * go_forward
263
278
  * goto
@@ -423,6 +438,13 @@
423
438
  * focus
424
439
  * frame_locator
425
440
  * get_attribute
441
+ * get_by_alt_text
442
+ * get_by_label
443
+ * get_by_placeholder
444
+ * get_by_role
445
+ * get_by_test_id
446
+ * get_by_text
447
+ * get_by_title
426
448
  * highlight
427
449
  * hover
428
450
  * inner_html
@@ -455,6 +477,13 @@
455
477
 
456
478
  * first
457
479
  * frame_locator
480
+ * get_by_alt_text
481
+ * get_by_label
482
+ * get_by_placeholder
483
+ * get_by_role
484
+ * get_by_test_id
485
+ * get_by_text
486
+ * get_by_title
458
487
  * last
459
488
  * locator
460
489
  * nth
@@ -13,7 +13,7 @@ const FeatureList = [
13
13
  ),
14
14
  },
15
15
  {
16
- title: 'Make more relyable tests',
16
+ title: 'Make more reliable tests',
17
17
  Svg: require('../../static/img/undraw_dropdown_menu.svg').default,
18
18
  description: (
19
19
  <>
@@ -10,136 +10,34 @@ module Playwright
10
10
  @channel.send_message_to_server('dispose')
11
11
  end
12
12
 
13
- def delete(
14
- url,
15
- data: nil,
16
- failOnStatusCode: nil,
17
- form: nil,
18
- headers: nil,
19
- ignoreHTTPSErrors: nil,
20
- multipart: nil,
21
- params: nil,
22
- timeout: nil)
23
- fetch(
24
- url,
25
- method: 'DELETE',
26
- data: data,
27
- failOnStatusCode: failOnStatusCode,
28
- form: form,
29
- headers: headers,
30
- ignoreHTTPSErrors: ignoreHTTPSErrors,
31
- multipart: multipart,
32
- params: params,
33
- timeout: timeout,
34
- )
13
+ def delete(url, **options)
14
+ fetch_options = options.merge(method: 'DELETE')
15
+ fetch(url, **fetch_options)
35
16
  end
36
17
 
37
- def head(
38
- url,
39
- failOnStatusCode: nil,
40
- headers: nil,
41
- ignoreHTTPSErrors: nil,
42
- params: nil,
43
- timeout: nil)
44
- fetch(
45
- url,
46
- method: 'HEAD',
47
- failOnStatusCode: failOnStatusCode,
48
- headers: headers,
49
- ignoreHTTPSErrors: ignoreHTTPSErrors,
50
- params: params,
51
- timeout: timeout,
52
- )
18
+ def head(url, **options)
19
+ fetch_options = options.merge(method: 'HEAD')
20
+ fetch(url, **fetch_options)
53
21
  end
54
22
 
55
- def get(
56
- url,
57
- failOnStatusCode: nil,
58
- headers: nil,
59
- ignoreHTTPSErrors: nil,
60
- params: nil,
61
- timeout: nil)
62
- fetch(
63
- url,
64
- method: 'GET',
65
- failOnStatusCode: failOnStatusCode,
66
- headers: headers,
67
- ignoreHTTPSErrors: ignoreHTTPSErrors,
68
- params: params,
69
- timeout: timeout,
70
- )
23
+ def get(url, **options)
24
+ fetch_options = options.merge(method: 'GET')
25
+ fetch(url, **fetch_options)
71
26
  end
72
27
 
73
- def patch(
74
- url,
75
- data: nil,
76
- failOnStatusCode: nil,
77
- form: nil,
78
- headers: nil,
79
- ignoreHTTPSErrors: nil,
80
- multipart: nil,
81
- params: nil,
82
- timeout: nil)
83
- fetch(
84
- url,
85
- method: 'PATCH',
86
- data: data,
87
- failOnStatusCode: failOnStatusCode,
88
- form: form,
89
- headers: headers,
90
- ignoreHTTPSErrors: ignoreHTTPSErrors,
91
- multipart: multipart,
92
- params: params,
93
- timeout: timeout,
94
- )
28
+ def patch(url, **options)
29
+ fetch_options = options.merge(method: 'PATCH')
30
+ fetch(url, **fetch_options)
95
31
  end
96
32
 
97
- def put(
98
- url,
99
- data: nil,
100
- failOnStatusCode: nil,
101
- form: nil,
102
- headers: nil,
103
- ignoreHTTPSErrors: nil,
104
- multipart: nil,
105
- params: nil,
106
- timeout: nil)
107
- fetch(
108
- url,
109
- method: 'PUT',
110
- data: data,
111
- failOnStatusCode: failOnStatusCode,
112
- form: form,
113
- headers: headers,
114
- ignoreHTTPSErrors: ignoreHTTPSErrors,
115
- multipart: multipart,
116
- params: params,
117
- timeout: timeout,
118
- )
33
+ def put(url, **options)
34
+ fetch_options = options.merge(method: 'PUT')
35
+ fetch(url, **fetch_options)
119
36
  end
120
37
 
121
- def post(
122
- url,
123
- data: nil,
124
- failOnStatusCode: nil,
125
- form: nil,
126
- headers: nil,
127
- ignoreHTTPSErrors: nil,
128
- multipart: nil,
129
- params: nil,
130
- timeout: nil)
131
- fetch(
132
- url,
133
- method: 'POST',
134
- data: data,
135
- failOnStatusCode: failOnStatusCode,
136
- form: form,
137
- headers: headers,
138
- ignoreHTTPSErrors: ignoreHTTPSErrors,
139
- multipart: multipart,
140
- params: params,
141
- timeout: timeout,
142
- )
38
+ def post(url, **options)
39
+ fetch_options = options.merge(method: 'POST')
40
+ fetch(url, **fetch_options)
143
41
  end
144
42
 
145
43
  def fetch(
@@ -149,6 +47,7 @@ module Playwright
149
47
  form: nil,
150
48
  headers: nil,
151
49
  ignoreHTTPSErrors: nil,
50
+ maxRedirects: nil,
152
51
  method: nil,
153
52
  multipart: nil,
154
53
  params: nil,
@@ -160,6 +59,9 @@ module Playwright
160
59
  if [data, form, multipart].compact.count > 1
161
60
  raise ArgumentError.new("Only one of 'data', 'form' or 'multipart' can be specified")
162
61
  end
62
+ if maxRedirects && maxRedirects < 0
63
+ raise ArgumentError.new("'maxRedirects' should be greater than or equal to '0'")
64
+ end
163
65
 
164
66
  request = urlOrRequest.is_a?(ChannelOwners::Request) ? urlOrRequest : nil
165
67
  headers_obj = headers || request&.headers
@@ -212,6 +114,7 @@ module Playwright
212
114
  fetch_params[:timeout] = timeout
213
115
  fetch_params[:failOnStatusCode] = failOnStatusCode
214
116
  fetch_params[:ignoreHTTPSErrors] = ignoreHTTPSErrors
117
+ fetch_params[:maxRedirects] = maxRedirects
215
118
  fetch_params.compact!
216
119
  response = @channel.send_message_to_server('fetch', fetch_params)
217
120
 
@@ -26,7 +26,7 @@ module Playwright
26
26
  @channel.on('page', ->(params) { on_page(ChannelOwners::Page.from(params['page']) )})
27
27
  @channel.on('route', ->(params) {
28
28
  Concurrent::Promises.future {
29
- on_route(ChannelOwners::Route.from(params['route']), ChannelOwners::Request.from(params['request']))
29
+ on_route(ChannelOwners::Route.from(params['route']))
30
30
  }.rescue do |err|
31
31
  puts err, err.backtrace
32
32
  end
@@ -83,22 +83,21 @@ module Playwright
83
83
  emit(Events::BrowserContext::BackgroundPage, page)
84
84
  end
85
85
 
86
- private def on_route(route, request)
86
+ private def on_route(route)
87
87
  # It is not desired to use PlaywrightApi.wrap directly.
88
88
  # However it is a little difficult to define wrapper for `handler` parameter in generate_api.
89
89
  # Just a workaround...
90
90
  wrapped_route = PlaywrightApi.wrap(route)
91
- wrapped_request = PlaywrightApi.wrap(request)
92
91
 
93
92
  handled = @routes.any? do |handler_entry|
94
- next false unless handler_entry.match?(request.url)
93
+ next false unless handler_entry.match?(route.request.url)
95
94
 
96
95
  promise = Concurrent::Promises.resolvable_future
97
96
  route.send(:set_handling_future, promise)
98
97
 
99
98
  promise_handled = Concurrent::Promises.zip(
100
99
  promise,
101
- handler_entry.async_handle(wrapped_route, wrapped_request)
100
+ handler_entry.async_handle(wrapped_route)
102
101
  ).value!.first
103
102
 
104
103
  promise_handled
@@ -13,7 +13,7 @@ module Playwright
13
13
  end
14
14
 
15
15
  def accept(promptText: nil)
16
- accept_async(prompt_text: promptText).value!
16
+ accept_async(promptText: promptText).value!
17
17
  end
18
18
 
19
19
  def accept_async(promptText: nil)
@@ -1,6 +1,10 @@
1
+ require_relative '../locator_utils'
2
+
1
3
  module Playwright
2
4
  # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_frame.py
3
5
  define_channel_owner :Frame do
6
+ include LocatorUtils
7
+
4
8
  private def after_initialize
5
9
  if @initializer['parentFrame']
6
10
  @parent_frame = ChannelOwners::Frame.from(@initializer['parentFrame'])
@@ -1,9 +1,11 @@
1
1
  require 'base64'
2
+ require_relative '../locator_utils'
2
3
 
3
4
  module Playwright
4
5
  # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_page.py
5
6
  define_channel_owner :Page do
6
7
  include Utils::Errors::SafeCloseError
8
+ include LocatorUtils
7
9
  attr_writer :owned_context
8
10
 
9
11
  private def after_initialize
@@ -58,7 +60,7 @@ module Playwright
58
60
  })
59
61
  @channel.on('route', ->(params) {
60
62
  Concurrent::Promises.future {
61
- on_route(ChannelOwners::Route.from(params['route']), ChannelOwners::Request.from(params['request']))
63
+ on_route(ChannelOwners::Route.from(params['route']))
62
64
  }.rescue do |err|
63
65
  puts err, err.backtrace
64
66
  end
@@ -93,22 +95,21 @@ module Playwright
93
95
  emit(Events::Page::FrameDetached, frame)
94
96
  end
95
97
 
96
- private def on_route(route, request)
98
+ private def on_route(route)
97
99
  # It is not desired to use PlaywrightApi.wrap directly.
98
100
  # However it is a little difficult to define wrapper for `handler` parameter in generate_api.
99
101
  # Just a workaround...
100
102
  wrapped_route = PlaywrightApi.wrap(route)
101
- wrapped_request = PlaywrightApi.wrap(request)
102
103
 
103
104
  handled = @routes.any? do |handler_entry|
104
- next false unless handler_entry.match?(request.url)
105
+ next false unless handler_entry.match?(route.request.url)
105
106
 
106
107
  promise = Concurrent::Promises.resolvable_future
107
108
  route.send(:set_handling_future, promise)
108
109
 
109
110
  promise_handled = Concurrent::Promises.zip(
110
111
  promise,
111
- handler_entry.async_handle(wrapped_route, wrapped_request)
112
+ handler_entry.async_handle(wrapped_route)
112
113
  ).value!.first
113
114
 
114
115
  promise_handled
@@ -120,7 +121,7 @@ module Playwright
120
121
  end
121
122
 
122
123
  unless handled
123
- @browser_context.send(:on_route, route, request)
124
+ @browser_context.send(:on_route, route)
124
125
  end
125
126
  end
126
127
 
@@ -18,5 +18,9 @@ module Playwright
18
18
 
19
19
  nil
20
20
  end
21
+
22
+ def text_id_attribute=(attribute_name)
23
+ ::Playwright::LocatorUtils.instance_variable_set(:@test_id_attribute_name, attribute_name)
24
+ end
21
25
  end
22
26
  end
@@ -1,5 +1,9 @@
1
+ require_relative './locator_utils'
2
+
1
3
  module Playwright
2
4
  define_api_implementation :FrameLocatorImpl do
5
+ include LocatorUtils
6
+
3
7
  def initialize(frame:, timeout_settings:, frame_selector:)
4
8
  @frame = frame
5
9
  @timeout_settings = timeout_settings
@@ -10,7 +14,7 @@ module Playwright
10
14
  LocatorImpl.new(
11
15
  frame: @frame,
12
16
  timeout_settings: @timeout_settings,
13
- selector: "#{@frame_selector} >> control=enter-frame >> #{selector}",
17
+ selector: "#{@frame_selector} >> internal:control=enter-frame >> #{selector}",
14
18
  hasText: hasText,
15
19
  has: has,
16
20
  )
@@ -20,7 +24,7 @@ module Playwright
20
24
  FrameLocatorImpl.new(
21
25
  frame: @frame,
22
26
  timeout_settings: @timeout_settings,
23
- frame_selector: "#{@frame_selector} >> control=enter-frame >> #{selector}",
27
+ frame_selector: "#{@frame_selector} >> internal:control=enter-frame >> #{selector}",
24
28
  )
25
29
  end
26
30