capybara-playwright-driver 0.5.7 → 0.5.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36e3eb177b25d9c711d190e31beeeebc7fcba4a40b5c1ffa6d2e995ac2b34219
4
- data.tar.gz: 961a358b0aeb9cf2ededd3491b0850e8df4ce9ccdf3c3a895cd69fea589923ad
3
+ metadata.gz: fe14f82e64d08efc962dda883c9c4a6b54b794c75bb5458c522fbf88e839267a
4
+ data.tar.gz: 59156f6e1a5db3dd787b1342cafd5c9f8aca74df33042013304cdd029875e64c
5
5
  SHA512:
6
- metadata.gz: d62a3e62ceee42b31676fa7e2728e1d49e24592f32b889a7cf8732ad076bfae839b4009ee56f4031657c6906f2906e412f1df442482ac79b0974a35722fa07a4
7
- data.tar.gz: 12d105953dd329eb5eb118d1ab81370f395810004b2e940dc356f5457f36db96ede3fc75938727374124cc9cccb0fb83fe4d71e65b167071bdea7d47a7b8e634
6
+ metadata.gz: 3bbf39026f4bc9dfdce2c319510c709e00b6eb5a890e8057566f57a2b804e2890ff3ee97d67a8ba5da3fe7ede58c526f4b239cd425fe6ac47f049075a83a0a7d
7
+ data.tar.gz: 813ccb3ce551cb1a3484d261096d8847d045cd694b6dc8275ba27f4012fab798ed23ad2bf36f2996818b653bf6ed4d0213d8f7c9f131cccf1c242450ea86327c
data/README.md CHANGED
@@ -43,10 +43,27 @@ end
43
43
 
44
44
  Refer the [documentation](https://playwright-ruby-client.vercel.app/docs/article/guides/rails_integration) for more detailed configuration.
45
45
 
46
+ ## Development
47
+
48
+ Prepare to run tests:
49
+
50
+ ```bash
51
+ bundle install
52
+ export PLAYWRIGHT_CLI_VERSION=$(bundle exec ruby -e 'require "playwright"; puts Playwright::COMPATIBLE_PLAYWRIGHT_VERSION.strip')
53
+ npm install playwright@${PLAYWRIGHT_CLI_VERSION}
54
+ ./node_modules/.bin/playwright install --with-deps
55
+ ```
56
+
57
+ Now, run tests: note that they are run in a virtual framebuffer (Xvfb).
58
+
59
+ ```bash
60
+ PLAYWRIGHT_CLI_EXECUTABLE_PATH=./node_modules/.bin/playwright xvfb-run bundle exec rspec
61
+ ```
62
+
46
63
  ## License
47
64
 
48
65
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
49
66
 
50
67
  ## Code of Conduct
51
68
 
52
- Everyone interacting in the Capybara::Playwright project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/capybara-playwright/blob/master/CODE_OF_CONDUCT.md).
69
+ Everyone interacting in the Capybara::Playwright project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/YusukeIwaki/capybara-playwright-driver/blob/main/CODE_OF_CONDUCT.md).
@@ -20,8 +20,6 @@ Gem::Specification.new do |spec|
20
20
  f.match(%r{^(test|spec|features)/}) || f.include?('.git')
21
21
  end
22
22
  end
23
- spec.bindir = 'exe'
24
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
23
  spec.require_paths = ['lib']
26
24
 
27
25
  spec.required_ruby_version = '>= 2.4'
@@ -84,7 +84,8 @@ module Capybara
84
84
  path
85
85
  end
86
86
 
87
- @playwright_page.capybara_current_frame.goto(url)
87
+ response = @playwright_page.capybara_current_frame.goto(url)
88
+ @playwright_page.capybara_set_last_response(response)
88
89
  }
89
90
  end
90
91
 
@@ -144,13 +145,15 @@ module Capybara
144
145
 
145
146
  def go_back
146
147
  assert_page_alive {
147
- @playwright_page.go_back
148
+ response = @playwright_page.go_back
149
+ @playwright_page.capybara_set_last_response(response)
148
150
  }
149
151
  end
150
152
 
151
153
  def go_forward
152
154
  assert_page_alive {
153
- @playwright_page.go_forward
155
+ response = @playwright_page.go_forward
156
+ @playwright_page.capybara_set_last_response(response)
154
157
  }
155
158
  end
156
159
 
@@ -90,8 +90,8 @@ module Capybara
90
90
  end
91
91
  end
92
92
 
93
- # video path can be aquired only before closing context.
94
- # video is completedly saved only after closing context.
93
+ # video path can be acquired only before closing context.
94
+ # video is completely saved only after closing context.
95
95
  video_path = @browser&.video_path
96
96
 
97
97
  # [NOTE] @playwright_browser should keep alive for better performance.
@@ -30,6 +30,75 @@ module Capybara
30
30
  end
31
31
  Node::Element.prepend(WithElementHandlePatch)
32
32
 
33
+ module NodeActionsAllowLabelClickPatch
34
+ def choose(locator = nil, **options)
35
+ _playwright_check_via_get_by_label(locator, checked: true, **options) { super }
36
+ end
37
+
38
+ def check(locator = nil, **options)
39
+ _playwright_check_via_get_by_label(locator, checked: true, **options) { super }
40
+ end
41
+
42
+ def uncheck(locator = nil, **options)
43
+ _playwright_check_via_get_by_label(locator, checked: false, **options) { super }
44
+ end
45
+
46
+ private def _playwright_check_via_get_by_label(locator, checked:, allow_label_click: session_options.automatic_label_click, **options)
47
+ unless _playwright_use_get_by_label?(locator, allow_label_click, options)
48
+ return yield
49
+ end
50
+
51
+ return self if _playwright_try_get_by_label(locator, checked: checked)
52
+
53
+ yield
54
+ end
55
+
56
+ private def _playwright_use_get_by_label?(locator, allow_label_click, options)
57
+ return false if locator.nil?
58
+ return false unless allow_label_click
59
+ return false unless driver.is_a?(Capybara::Playwright::Driver)
60
+ return false if Hash.try_convert(allow_label_click)
61
+ return false unless options.empty?
62
+
63
+ true
64
+ end
65
+
66
+ private def _playwright_try_get_by_label(locator, checked:)
67
+ handled = false
68
+ driver.with_playwright_page do |playwright_page|
69
+ begin
70
+ control_locator = playwright_page.get_by_label(locator.to_s)
71
+ control = control_locator
72
+
73
+ if control.evaluate('el => !!el.checked') != checked
74
+ label = control.evaluate_handle('(el) => (el.labels && el.labels[0]) || el.closest("label") || null')
75
+ next unless label.is_a?(::Playwright::ElementHandle)
76
+
77
+ label.click
78
+ end
79
+
80
+ next unless control.evaluate('el => !!el.checked') == checked
81
+
82
+ handled = true
83
+ rescue ::Playwright::Error
84
+ handled = false
85
+ end
86
+ end
87
+
88
+ handled
89
+ rescue StandardError
90
+ false
91
+ end
92
+ end
93
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7')
94
+ # Prepend to Node::Base instead of Node::Actions because Ruby < 3.1
95
+ # does not propagate Module#prepend to classes that have already
96
+ # included the target module. Node::Base includes Node::Actions at
97
+ # load time, so prepending to Node::Actions afterwards has no effect
98
+ # on Node::Document / Node::Element in older Rubies.
99
+ Node::Base.prepend(NodeActionsAllowLabelClickPatch)
100
+ end
101
+
33
102
  module CapybaraObscuredPatch
34
103
  # ref: https://github.com/teamcapybara/capybara/blob/f7ab0b5cd5da86185816c2d5c30d58145fe654ed/lib/capybara/selenium/node.rb#L523
35
104
  OBSCURED_OR_OFFSET_SCRIPT = <<~JAVASCRIPT
@@ -97,6 +166,8 @@ module Capybara
97
166
  raise StaleReferenceError.new(err)
98
167
  when /error in channel "content::page": exception while running method "adoptNode"/ # for Firefox
99
168
  raise StaleReferenceError.new(err)
169
+ when /(: Shadow DOM element - no XPath :)/
170
+ raise StaleReferenceError.new(err)
100
171
  else
101
172
  raise
102
173
  end
@@ -905,6 +976,9 @@ module Capybara
905
976
  xpath = el.nodeName.toUpperCase()+"["+pos+"]/"+xpath;
906
977
  }
907
978
  el = el.parentNode;
979
+ if (!el) {
980
+ throw "(: Shadow DOM element - no XPath :)";
981
+ }
908
982
  }
909
983
  xpath = '/'+xml.documentElement.nodeName.toUpperCase()+'/'+xpath;
910
984
  xpath = xpath.replace(/\\/$/, '');
@@ -17,7 +17,7 @@ module Capybara
17
17
  end
18
18
 
19
19
  private def capybara_initialize
20
- @capybara_all_responses = {}
20
+ @capybara_response_mutex = Mutex.new
21
21
  @capybara_last_response = nil
22
22
  @capybara_frames = []
23
23
 
@@ -31,13 +31,9 @@ module Capybara
31
31
  Thread.new(dest) { |_dest| download.save_as(_dest) }
32
32
  })
33
33
  on('response', -> (response) {
34
- @capybara_all_responses[response.url] = response
35
- })
36
- on('framenavigated', -> (frame) {
37
- @capybara_last_response = @capybara_all_responses[frame.url]
38
- })
39
- on('load', -> (page) {
40
- @capybara_all_responses.clear
34
+ if response.request.navigation_request?
35
+ capybara_set_last_response(response)
36
+ end
41
37
  })
42
38
  end
43
39
 
@@ -146,6 +142,12 @@ module Capybara
146
142
  end
147
143
  end
148
144
 
145
+ def capybara_set_last_response(response)
146
+ @capybara_response_mutex.synchronize do
147
+ @capybara_last_response = response
148
+ end
149
+ end
150
+
149
151
  class Headers < Hash
150
152
  def [](key)
151
153
  # Playwright accepts lower-cased keys.
@@ -155,7 +157,7 @@ module Capybara
155
157
  end
156
158
 
157
159
  def capybara_response_headers
158
- headers = @capybara_last_response&.headers || {}
160
+ headers = @capybara_response_mutex.synchronize { @capybara_last_response&.headers || {} }
159
161
 
160
162
  Headers.new.tap do |h|
161
163
  headers.each do |key, value|
@@ -165,7 +167,7 @@ module Capybara
165
167
  end
166
168
 
167
169
  def capybara_status_code
168
- @capybara_last_response&.status.to_i
170
+ @capybara_response_mutex.synchronize { @capybara_last_response&.status.to_i }
169
171
  end
170
172
 
171
173
  def capybara_reset_frames
@@ -5,12 +5,12 @@ module Capybara
5
5
  class ShadowRootNode < Node
6
6
  def initialize(driver, internal_logger, page, element)
7
7
  super
8
- @shadow_roow_element = element.evaluate_handle('el => el.shadowRoot')
8
+ @shadow_root_element = element.evaluate_handle('el => el.shadowRoot')
9
9
  end
10
10
 
11
11
  def all_text
12
12
  assert_element_not_stale {
13
- text = @shadow_roow_element.text_content
13
+ text = @shadow_root_element.text_content
14
14
  text.to_s.gsub(/[\u200b\u200e\u200f]/, '')
15
15
  .gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
16
16
  .gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
@@ -25,7 +25,7 @@ module Capybara
25
25
  return '' unless visible?
26
26
 
27
27
  # https://github.com/teamcapybara/capybara/blob/1c164b608fa6452418ec13795b293655f8a0102a/lib/capybara/rack_test/node.rb#L18
28
- displayed_text = @shadow_roow_element.text_content.to_s.
28
+ displayed_text = @shadow_root_element.text_content.to_s.
29
29
  gsub(/[\u200b\u200e\u200f]/, '').
30
30
  gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
31
31
  displayed_text.squeeze(' ')
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Playwright
5
- VERSION = '0.5.7'
5
+ VERSION = '0.5.8'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-playwright-driver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.7
4
+ version: 0.5.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - YusukeIwaki
8
- autorequire:
9
- bindir: exe
8
+ bindir: bin
10
9
  cert_chain: []
11
- date: 2025-08-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: addressable
@@ -52,7 +51,6 @@ dependencies:
52
51
  - - ">="
53
52
  - !ruby/object:Gem::Version
54
53
  version: 1.16.0
55
- description:
56
54
  email:
57
55
  - q7w8e9w8q7w8e9@yahoo.co.jp
58
56
  executables: []
@@ -86,7 +84,6 @@ homepage: https://github.com/YusukeIwaki/capybara-playwright-driver
86
84
  licenses:
87
85
  - MIT
88
86
  metadata: {}
89
- post_install_message:
90
87
  rdoc_options: []
91
88
  require_paths:
92
89
  - lib
@@ -101,8 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
98
  - !ruby/object:Gem::Version
102
99
  version: '0'
103
100
  requirements: []
104
- rubygems_version: 3.5.22
105
- signing_key:
101
+ rubygems_version: 3.6.9
106
102
  specification_version: 4
107
103
  summary: Playwright driver for Capybara
108
104
  test_files: []