playwright-ruby-client 1.15.beta1 → 1.16.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -14
  3. data/documentation/docs/api/browser.md +2 -0
  4. data/documentation/docs/api/browser_context.md +5 -1
  5. data/documentation/docs/api/browser_type.md +1 -0
  6. data/documentation/docs/api/element_handle.md +27 -1
  7. data/documentation/docs/api/experimental/android_device.md +1 -0
  8. data/documentation/docs/api/fetch_request.md +10 -0
  9. data/documentation/docs/api/frame.md +28 -0
  10. data/documentation/docs/api/locator.md +47 -0
  11. data/documentation/docs/api/mouse.md +11 -0
  12. data/documentation/docs/api/page.md +35 -2
  13. data/documentation/docs/api/request.md +34 -1
  14. data/documentation/docs/api/response.md +37 -2
  15. data/documentation/docs/api/tracing.md +42 -8
  16. data/documentation/docs/article/getting_started.md +10 -1
  17. data/documentation/docs/article/guides/download_playwright_driver.md +9 -0
  18. data/documentation/docs/article/guides/inspector.md +1 -1
  19. data/documentation/docs/article/guides/playwright_on_alpine_linux.md +56 -3
  20. data/documentation/docs/article/guides/rails_integration.md +4 -2
  21. data/documentation/docs/article/guides/rails_integration_with_null_driver.md +86 -0
  22. data/documentation/docs/article/guides/recording_video.md +1 -1
  23. data/documentation/docs/article/guides/semi_automation.md +1 -1
  24. data/documentation/docs/article/guides/use_storage_state.md +1 -1
  25. data/documentation/docs/include/api_coverage.md +23 -0
  26. data/documentation/docusaurus.config.js +1 -0
  27. data/documentation/package.json +2 -2
  28. data/documentation/src/pages/index.js +0 -1
  29. data/documentation/static/img/playwright-ruby-client.png +0 -0
  30. data/documentation/yarn.lock +1810 -1790
  31. data/lib/playwright/channel.rb +36 -2
  32. data/lib/playwright/channel_owners/artifact.rb +6 -2
  33. data/lib/playwright/channel_owners/browser.rb +4 -0
  34. data/lib/playwright/channel_owners/browser_context.rb +21 -14
  35. data/lib/playwright/channel_owners/element_handle.rb +10 -2
  36. data/lib/playwright/channel_owners/fetch_request.rb +4 -0
  37. data/lib/playwright/channel_owners/frame.rb +11 -1
  38. data/lib/playwright/channel_owners/page.rb +20 -4
  39. data/lib/playwright/channel_owners/request.rb +53 -17
  40. data/lib/playwright/channel_owners/response.rb +48 -5
  41. data/lib/playwright/connection.rb +5 -3
  42. data/lib/playwright/http_headers.rb +0 -6
  43. data/lib/playwright/locator_impl.rb +12 -0
  44. data/lib/playwright/mouse_impl.rb +9 -0
  45. data/lib/playwright/raw_headers.rb +61 -0
  46. data/lib/playwright/{route_handler_entry.rb → route_handler.rb} +30 -2
  47. data/lib/playwright/tracing_impl.rb +18 -7
  48. data/lib/playwright/transport.rb +2 -0
  49. data/lib/playwright/utils.rb +8 -0
  50. data/lib/playwright/version.rb +2 -2
  51. data/lib/playwright/web_socket_transport.rb +2 -0
  52. data/lib/playwright.rb +2 -1
  53. data/lib/playwright_api/android.rb +6 -6
  54. data/lib/playwright_api/android_device.rb +10 -9
  55. data/lib/playwright_api/browser.rb +10 -8
  56. data/lib/playwright_api/browser_context.rb +12 -8
  57. data/lib/playwright_api/browser_type.rb +8 -7
  58. data/lib/playwright_api/cdp_session.rb +7 -7
  59. data/lib/playwright_api/console_message.rb +6 -6
  60. data/lib/playwright_api/dialog.rb +6 -6
  61. data/lib/playwright_api/element_handle.rb +31 -8
  62. data/lib/playwright_api/fetch_request.rb +77 -0
  63. data/lib/playwright_api/frame.rb +31 -6
  64. data/lib/playwright_api/js_handle.rb +6 -6
  65. data/lib/playwright_api/locator.rb +39 -0
  66. data/lib/playwright_api/mouse.rb +8 -0
  67. data/lib/playwright_api/page.rb +40 -10
  68. data/lib/playwright_api/playwright.rb +6 -6
  69. data/lib/playwright_api/request.rb +30 -4
  70. data/lib/playwright_api/response.rb +31 -8
  71. data/lib/playwright_api/route.rb +6 -6
  72. data/lib/playwright_api/selectors.rb +6 -6
  73. data/lib/playwright_api/tracing.rb +33 -4
  74. data/lib/playwright_api/web_socket.rb +6 -6
  75. data/lib/playwright_api/worker.rb +8 -8
  76. metadata +10 -4
@@ -30,16 +30,50 @@ module Playwright
30
30
  # @param params [Hash]
31
31
  # @return [Hash]
32
32
  def send_message_to_server_result(method, params)
33
- @connection.send_message_to_server(@guid, method, params)
33
+ with_logging do |metadata|
34
+ @connection.send_message_to_server(@guid, method, params, metadata: metadata)
35
+ end
34
36
  end
35
37
 
36
38
  # @param method [String]
37
39
  # @param params [Hash]
38
40
  # @returns nil
39
41
  def async_send_message_to_server(method, params = {})
40
- @connection.async_send_message_to_server(@guid, method, params)
42
+ with_logging do |metadata|
43
+ @connection.async_send_message_to_server(@guid, method, params, metadata: metadata)
44
+ end
41
45
 
42
46
  nil
43
47
  end
48
+
49
+ private def with_logging(&block)
50
+ locations = caller_locations
51
+ first_api_call_location_idx = locations.index { |loc| loc.absolute_path.include?('playwright_api') }
52
+ unless first_api_call_location_idx
53
+ return block.call(nil)
54
+ end
55
+
56
+ locations = locations.slice(first_api_call_location_idx..-1)
57
+
58
+ api_call_location = locations.shift
59
+
60
+ api_class = File.basename(api_call_location.absolute_path, '.rb')
61
+ api_method = api_call_location.label
62
+ api_name = "#{api_class}##{api_method}"
63
+
64
+ stacks = locations
65
+
66
+ metadata = build_metadata_payload_from(api_name, stacks)
67
+ block.call(metadata)
68
+ end
69
+
70
+ private def build_metadata_payload_from(api_name, stacks)
71
+ {
72
+ apiName: api_name,
73
+ stack: stacks.map do |loc|
74
+ { file: loc.absolute_path, line: loc.lineno, function: loc.label }
75
+ end,
76
+ }
77
+ end
44
78
  end
45
79
  end
@@ -1,14 +1,14 @@
1
1
  module Playwright
2
2
  define_channel_owner :Artifact do
3
3
  private def after_initialize
4
- @is_remote = false
4
+ @remote = false
5
5
  @absolute_path = @initializer['absolutePath']
6
6
  end
7
7
 
8
8
  attr_reader :absolute_path
9
9
 
10
10
  def path_after_finished
11
- if @is_remote
11
+ if @remote
12
12
  raise "Path is not available when using browser_type.connect(). Use save_as() to save a local copy."
13
13
  end
14
14
  @channel.send_message_to_server('pathAfterFinished')
@@ -30,5 +30,9 @@ module Playwright
30
30
  def cancel
31
31
  @channel.send_message_to_server('cancel')
32
32
  end
33
+
34
+ private def update_as_remote
35
+ @remote = true
36
+ end
33
37
  end
34
38
  end
@@ -104,6 +104,10 @@ module Playwright
104
104
  @remote = true
105
105
  end
106
106
 
107
+ private def remote?
108
+ @remote
109
+ end
110
+
107
111
  # called from BrowserContext#on_close with send(:remove_context), so keep private.
108
112
  private def remove_context(context)
109
113
  @contexts.delete(context)
@@ -30,7 +30,7 @@ module Playwright
30
30
  @channel.on('request', ->(params) {
31
31
  on_request(
32
32
  ChannelOwners::Request.from(params['request']),
33
- ChannelOwners::Request.from_nullable(params['page']),
33
+ ChannelOwners::Page.from_nullable(params['page']),
34
34
  )
35
35
  })
36
36
  @channel.on('requestFailed', ->(params) {
@@ -38,20 +38,14 @@ module Playwright
38
38
  ChannelOwners::Request.from(params['request']),
39
39
  params['responseEndTiming'],
40
40
  params['failureText'],
41
- ChannelOwners::Request.from_nullable(params['page']),
42
- )
43
- })
44
- @channel.on('requestFinished', ->(params) {
45
- on_request_finished(
46
- ChannelOwners::Request.from(params['request']),
47
- params['responseEndTiming'],
48
- ChannelOwners::Request.from_nullable(params['page']),
41
+ ChannelOwners::Page.from_nullable(params['page']),
49
42
  )
50
43
  })
44
+ @channel.on('requestFinished', method(:on_request_finished))
51
45
  @channel.on('response', ->(params) {
52
46
  on_response(
53
47
  ChannelOwners::Response.from(params['response']),
54
- ChannelOwners::Request.from_nullable(params['page']),
48
+ ChannelOwners::Page.from_nullable(params['page']),
55
49
  )
56
50
  })
57
51
 
@@ -95,10 +89,15 @@ module Playwright
95
89
  page&.emit(Events::Page::RequestFailed, request)
96
90
  end
97
91
 
98
- private def on_request_finished(request, response_end_timing, page)
99
- request.send(:update_response_end_timing, response_end_timing)
92
+ private def on_request_finished(params)
93
+ request = ChannelOwners::Request.from(params['request'])
94
+ response = ChannelOwners::Response.from_nullable(params['response'])
95
+ page = ChannelOwners::Page.from_nullable(params['page'])
96
+
97
+ request.send(:update_response_end_timing, params['responseEndTiming'])
100
98
  emit(Events::BrowserContext::RequestFinished, request)
101
99
  page&.emit(Events::Page::RequestFinished, request)
100
+ response&.send(:mark_as_finished)
102
101
  end
103
102
 
104
103
  private def on_request(request, page)
@@ -236,8 +235,8 @@ module Playwright
236
235
  expose_binding(name, ->(_source, *args) { callback.call(*args) }, )
237
236
  end
238
237
 
239
- def route(url, handler)
240
- entry = RouteHandlerEntry.new(url, base_url, handler)
238
+ def route(url, handler, times: nil)
239
+ entry = RouteHandler.new(url, base_url, handler, times)
241
240
  @routes.unshift(entry)
242
241
  if @routes.count >= 1
243
242
  @channel.send_message_to_server('setNetworkInterceptionEnabled', enabled: true)
@@ -270,6 +269,14 @@ module Playwright
270
269
  end
271
270
 
272
271
  def close
272
+ if @options && @options.key?(:recordHar)
273
+ har = ChannelOwners::Artifact.from(@channel.send_message_to_server('harExport'))
274
+ if @browser.send(:remote?)
275
+ har.update_as_remote
276
+ end
277
+ har.save_as(@options[:recordHar][:path])
278
+ har.delete
279
+ end
273
280
  @channel.send_message_to_server('close')
274
281
  @closed_promise.value!
275
282
  nil
@@ -268,6 +268,14 @@ module Playwright
268
268
  nil
269
269
  end
270
270
 
271
+ def set_checked(checked, **options)
272
+ if checked
273
+ check(**options)
274
+ else
275
+ uncheck(**options)
276
+ end
277
+ end
278
+
271
279
  def bounding_box
272
280
  @channel.send_message_to_server('boundingBox')
273
281
  end
@@ -322,8 +330,8 @@ module Playwright
322
330
  nil
323
331
  end
324
332
 
325
- def wait_for_selector(selector, state: nil, timeout: nil)
326
- params = { selector: selector, state: state, timeout: timeout }.compact
333
+ def wait_for_selector(selector, state: nil, strict: nil, timeout: nil)
334
+ params = { selector: selector, state: state, strict: strict, timeout: timeout }.compact
327
335
  resp = @channel.send_message_to_server('waitForSelector', params)
328
336
 
329
337
  ChannelOwners::ElementHandle.from_nullable(resp)
@@ -0,0 +1,4 @@
1
+ module Playwright
2
+ define_channel_owner :FetchRequest do
3
+ end
4
+ end
@@ -584,8 +584,18 @@ module Playwright
584
584
  nil
585
585
  end
586
586
 
587
+ def set_checked(selector, checked, **options)
588
+ if checked
589
+ check(selector, **options)
590
+ else
591
+ uncheck(selector, **options)
592
+ end
593
+ end
594
+
587
595
  def wait_for_timeout(timeout)
588
- sleep(timeout / 1000.0)
596
+ @channel.send_message_to_server('waitForTimeout', timeout: timeout)
597
+
598
+ nil
589
599
  end
590
600
 
591
601
  def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
@@ -132,17 +132,24 @@ module Playwright
132
132
  end
133
133
 
134
134
  private def on_download(params)
135
+ artifact = ChannelOwners::Artifact.from(params['artifact'])
136
+ if @browser_context.browser.send(:remote?)
137
+ artifact.update_as_remote
138
+ end
135
139
  download = DownloadImpl.new(
136
140
  page: self,
137
141
  url: params['url'],
138
142
  suggested_filename: params['suggestedFilename'],
139
- artifact: ChannelOwners::Artifact.from(params['artifact']),
143
+ artifact: artifact,
140
144
  )
141
145
  emit(Events::Page::Download, download)
142
146
  end
143
147
 
144
148
  private def on_video(params)
145
149
  artifact = ChannelOwners::Artifact.from(params['artifact'])
150
+ if @browser_context.browser.send(:remote?)
151
+ artifact.update_as_remote
152
+ end
146
153
  video.send(:set_artifact, artifact)
147
154
  end
148
155
 
@@ -345,9 +352,10 @@ module Playwright
345
352
  ChannelOwners::Response.from_nullable(resp)
346
353
  end
347
354
 
348
- def emulate_media(colorScheme: nil, media: nil, reducedMotion: nil)
355
+ def emulate_media(colorScheme: nil, forcedColors: nil, media: nil, reducedMotion: nil)
349
356
  params = {
350
357
  colorScheme: colorScheme,
358
+ forcedColors: forcedColors,
351
359
  media: media,
352
360
  reducedMotion: reducedMotion,
353
361
  }.compact
@@ -381,8 +389,8 @@ module Playwright
381
389
  nil
382
390
  end
383
391
 
384
- def route(url, handler)
385
- entry = RouteHandlerEntry.new(url, @browser_context.send(:base_url), handler)
392
+ def route(url, handler, times: nil)
393
+ entry = RouteHandler.new(url, @browser_context.send(:base_url), handler, times)
386
394
  @routes.unshift(entry)
387
395
  if @routes.count >= 1
388
396
  @channel.send_message_to_server('setNetworkInterceptionEnabled', enabled: true)
@@ -702,6 +710,14 @@ module Playwright
702
710
  trial: trial)
703
711
  end
704
712
 
713
+ def set_checked(selector, checked, **options)
714
+ if checked
715
+ check(selector, **options)
716
+ else
717
+ uncheck(selector, **options)
718
+ end
719
+ end
720
+
705
721
  def wait_for_timeout(timeout)
706
722
  @main_frame.wait_for_timeout(timeout)
707
723
  end
@@ -6,6 +6,7 @@ module Playwright
6
6
  private def after_initialize
7
7
  @redirected_from = ChannelOwners::Request.from_nullable(@initializer['redirectedFrom'])
8
8
  @redirected_from&.send(:update_redirected_to, self)
9
+ @provisional_headers = RawHeaders.new(@initializer['headers'])
9
10
  @timing = {
10
11
  startTime: 0,
11
12
  domainLookupStart: -1,
@@ -17,7 +18,6 @@ module Playwright
17
18
  responseStart: -1,
18
19
  responseEnd: -1,
19
20
  }
20
- @headers = parse_headers(@initializer['headers'])
21
21
  end
22
22
 
23
23
  def url
@@ -40,7 +40,7 @@ module Playwright
40
40
  data = post_data
41
41
  return unless data
42
42
 
43
- content_type = @headers['content-type']
43
+ content_type = headers['content-type']
44
44
  return unless content_type
45
45
 
46
46
  if content_type == "application/x-www-form-urlencoded"
@@ -59,10 +59,6 @@ module Playwright
59
59
  end
60
60
  end
61
61
 
62
- def headers
63
- @headers
64
- end
65
-
66
62
  def response
67
63
  resp = @channel.send_message_to_server('response')
68
64
  ChannelOwners::Response.from_nullable(resp)
@@ -80,7 +76,57 @@ module Playwright
80
76
  @failure_text
81
77
  end
82
78
 
83
- attr_reader :headers, :redirected_from, :redirected_to, :timing
79
+ attr_reader :redirected_from, :redirected_to, :timing
80
+
81
+ def headers
82
+ @provisional_headers.headers
83
+ end
84
+
85
+ # @return [RawHeaders|nil]
86
+ private def actual_headers
87
+ @actual_headers ||= response&.send(:raw_request_headers)
88
+ end
89
+
90
+ def all_headers
91
+ if actual_headers
92
+ actual_headers.headers
93
+ else
94
+ @provisional_headers.headers
95
+ end
96
+ end
97
+
98
+ def headers_array
99
+ if actual_headers
100
+ actual_headers.headers_array
101
+ else
102
+ @provisional_headers.headers_array
103
+ end
104
+ end
105
+
106
+ def header_value(name)
107
+ if actual_headers
108
+ actual_headers.get(name)
109
+ else
110
+ @provisional_headers.get(name)
111
+ end
112
+ end
113
+
114
+ def header_values(name)
115
+ if actual_headers
116
+ actual_headers.get_all(name)
117
+ else
118
+ @provisional_headers.get_all(name)
119
+ end
120
+ end
121
+
122
+ def sizes
123
+ res = response
124
+ unless res
125
+ raise 'Unable to fetch sizes for failed request'
126
+ end
127
+
128
+ res.send(:sizes)
129
+ end
84
130
 
85
131
  private def update_redirected_to(request)
86
132
  @redirected_to = request
@@ -110,18 +156,8 @@ module Playwright
110
156
  @timing[:responseStart] = response_start
111
157
  end
112
158
 
113
- private def update_headers(headers)
114
- @headers = parse_headers(headers)
115
- end
116
-
117
159
  private def update_response_end_timing(response_end_timing)
118
160
  @timing[:responseEnd] = response_end_timing
119
161
  end
120
-
121
- private def parse_headers(headers)
122
- headers.map do |header|
123
- [header['name'].downcase, header['value']]
124
- end.to_h
125
- end
126
162
  end
127
163
  end
@@ -5,6 +5,7 @@ module Playwright
5
5
  # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_network.py
6
6
  define_channel_owner :Response do
7
7
  private def after_initialize
8
+ @provisional_headers = RawHeaders.new(@initializer['headers'])
8
9
  @request = ChannelOwners::Request.from(@initializer['request'])
9
10
  timing = @initializer['timing']
10
11
  @request.send(:update_timings,
@@ -17,7 +18,7 @@ module Playwright
17
18
  request_start: timing["requestStart"],
18
19
  response_start: timing["responseStart"],
19
20
  )
20
- @request.send(:update_headers, @initializer['requestHeaders'])
21
+ @finished_promise = Concurrent::Promises.resolvable_future
21
22
  end
22
23
  attr_reader :request
23
24
 
@@ -39,9 +40,36 @@ module Playwright
39
40
  end
40
41
 
41
42
  def headers
42
- @initializer['headers'].map do |header|
43
- [header['name'].downcase, header['value']]
44
- end.to_h
43
+ @provisional_headers.headers
44
+ end
45
+
46
+ # @return [RawHeaders]
47
+ private def actual_headers
48
+ @actual_headers ||= raw_response_headers
49
+ end
50
+
51
+ private def raw_request_headers
52
+ RawHeaders.new(@channel.send_message_to_server('rawRequestHeaders'))
53
+ end
54
+
55
+ private def raw_response_headers
56
+ RawHeaders.new(@channel.send_message_to_server('rawResponseHeaders'))
57
+ end
58
+
59
+ def all_headers
60
+ actual_headers.headers
61
+ end
62
+
63
+ def headers_array
64
+ actual_headers.headers_array
65
+ end
66
+
67
+ def header_value(name)
68
+ actual_headers.get(name)
69
+ end
70
+
71
+ def header_values(name)
72
+ actual_headers.get_all(name)
45
73
  end
46
74
 
47
75
  def server_addr
@@ -53,7 +81,7 @@ module Playwright
53
81
  end
54
82
 
55
83
  def finished
56
- @channel.send_message_to_server('finished')
84
+ @finished_promise.value!
57
85
  end
58
86
 
59
87
  def body
@@ -69,5 +97,20 @@ module Playwright
69
97
  def frame
70
98
  @request.frame
71
99
  end
100
+
101
+ private def sizes
102
+ resp = @channel.send_message_to_server('sizes')
103
+
104
+ {
105
+ requestBodySize: resp['requestBodySize'],
106
+ requestHeadersSize: resp['requestHeadersSize'],
107
+ responseBodySize: resp['responseBodySize'],
108
+ responseHeadersSize: resp['responseHeadersSize'],
109
+ }
110
+ end
111
+
112
+ private def mark_as_finished
113
+ @finished_promise.fulfill(nil)
114
+ end
72
115
  end
73
116
  end
@@ -36,7 +36,7 @@ module Playwright
36
36
  ChannelOwners::Playwright.from(result['playwright'])
37
37
  end
38
38
 
39
- def async_send_message_to_server(guid, method, params)
39
+ def async_send_message_to_server(guid, method, params, metadata: nil)
40
40
  callback = Concurrent::Promises.resolvable_future
41
41
 
42
42
  with_generated_id do |id|
@@ -49,7 +49,9 @@ module Playwright
49
49
  guid: guid,
50
50
  method: method,
51
51
  params: replace_channels_with_guids(params),
52
+ metadata: metadata || {},
52
53
  }
54
+
53
55
  begin
54
56
  @transport.send_message(message)
55
57
  rescue => err
@@ -62,8 +64,8 @@ module Playwright
62
64
  callback
63
65
  end
64
66
 
65
- def send_message_to_server(guid, method, params)
66
- async_send_message_to_server(guid, method, params).value!
67
+ def send_message_to_server(guid, method, params, metadata: nil)
68
+ async_send_message_to_server(guid, method, params, metadata: metadata).value!
67
69
  end
68
70
 
69
71
  private
@@ -10,11 +10,5 @@ module Playwright
10
10
  { name: key, value: value }
11
11
  end
12
12
  end
13
-
14
- def self.parse_serialized(serialized_headers)
15
- new(serialized_headers.map do |header|
16
- [header['name'].downcase, header['value']]
17
- end.to_h)
18
- end
19
13
  end
20
14
  end
@@ -303,6 +303,18 @@ module Playwright
303
303
  trial: trial)
304
304
  end
305
305
 
306
+ def wait_for(state: nil, timeout: nil)
307
+ @frame.wait_for_selector(@selector, strict: true, state: state, timeout: timeout)
308
+ end
309
+
310
+ def set_checked(checked, **options)
311
+ if checked
312
+ check(**options)
313
+ else
314
+ uncheck(**options)
315
+ end
316
+ end
317
+
306
318
  def all_inner_texts
307
319
  @frame.eval_on_selector_all(@selector, 'ee => ee.map(e => e.innerText)')
308
320
  end
@@ -44,5 +44,14 @@ module Playwright
44
44
  def dblclick(x, y, button: nil, delay: nil)
45
45
  click(x, y, button: button, clickCount: 2, delay: delay)
46
46
  end
47
+
48
+ def wheel(deltaX, deltaY)
49
+ params = {
50
+ deltaX: deltaX,
51
+ deltaY: deltaY,
52
+ }
53
+ @channel.send_message_to_server('mouseWheel', params)
54
+ nil
55
+ end
47
56
  end
48
57
  end
@@ -0,0 +1,61 @@
1
+ module Playwright
2
+ class RawHeaders
3
+ def initialize(headers_array)
4
+ h_array = []
5
+ h_map = {}
6
+ headers_array.each do |header|
7
+ name = header['name']
8
+ key = name.downcase
9
+ value = header['value']
10
+
11
+ h_array << [name, value]
12
+ h_map[key] ||= []
13
+ h_map[key] << value
14
+ end
15
+
16
+ @headers_array = h_array
17
+ @headers_map = h_map
18
+ end
19
+
20
+ # @return [String|nil]
21
+ def get(name)
22
+ key = name.downcase
23
+ values = @headers_map[key]
24
+ if values
25
+ join(key, values)
26
+ else
27
+ nil
28
+ end
29
+ end
30
+
31
+ # @return [Array<String>]
32
+ def get_all(name)
33
+ values = @headers_map[name.downcase]
34
+ if values
35
+ values.dup
36
+ else
37
+ []
38
+ end
39
+ end
40
+
41
+ def headers
42
+ @headers_map.map do |key, values|
43
+ [key, join(key, values)]
44
+ end.to_h
45
+ end
46
+
47
+ def headers_array
48
+ @headers_array.map do |name, value|
49
+ { name: name, value: value }
50
+ end
51
+ end
52
+
53
+ private def join(key, values)
54
+ if key == 'set-cookie'
55
+ values.join("\n")
56
+ else
57
+ values.join(", ")
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,15 +1,43 @@
1
1
  module Playwright
2
- class RouteHandlerEntry
2
+ class RouteHandler
3
+ class CountDown
4
+ def initialize(count)
5
+ @count = count
6
+ end
7
+
8
+ def handle
9
+ return false if @count <= 0
10
+
11
+ @count = @count - 1
12
+ true
13
+ end
14
+ end
15
+
16
+ class StubCounter
17
+ def handle
18
+ true
19
+ end
20
+ end
21
+
3
22
  # @param url [String]
4
23
  # @param base_url [String|nil]
5
24
  # @param handler [Proc]
6
- def initialize(url, base_url, handler)
25
+ # @param times [Integer|nil]
26
+ def initialize(url, base_url, handler, times)
7
27
  @url_value = url
8
28
  @url_matcher = UrlMatcher.new(url, base_url: base_url)
9
29
  @handler = handler
30
+ @counter =
31
+ if times
32
+ CountDown.new(times)
33
+ else
34
+ StubCounter.new
35
+ end
10
36
  end
11
37
 
12
38
  def handle(route, request)
39
+ return false unless @counter.handle
40
+
13
41
  if @url_matcher.match?(request.url)
14
42
  @handler.call(route, request)
15
43
  true