chop 0.37.0 → 0.38.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f913987c39cc9d3a8c36fbd479af12e59fd8319415c15b24fcbd32e737af1aa
4
- data.tar.gz: e85ac13a6ceabcad966813e1050ed5ce21f5d2db012453407458019c4c1c7a1e
3
+ metadata.gz: 0daeb281cda901500a0d95a2aee5ce2362322a930c36a395440093b6dcd41e5b
4
+ data.tar.gz: 73f5b4b2bc8ded47e68210efa01785842d8444770c68430a049aeb32e8f6d98f
5
5
  SHA512:
6
- metadata.gz: 96d2f1ae11404d221fdc04d37b8d9f322fa5d1dc9f90e0dba798fcdc964d6492c5558d6c9911f5643318a7b2eb6bc850bc4790daca7737830b61101d4543ca22
7
- data.tar.gz: 904edaee4530b7ed62c11f65791f5b1c55eaf9432e66d4b0b3dbe1f7bdb7c3813710fc295b4972a85f487cb66a40a7051f7d59ffb0cd2d5125b5b4a48c2247c3
6
+ metadata.gz: 375fba97039e7e2ad8f63ea1c111e66d0499193e458311c909497851115a8759f2ac1259df90a0fe5886748d73c75b040a48261170196d72295b694e2604d467
7
+ data.tar.gz: c95e301a217166638a1c6129334b59abc62f1b8950dd6317e7b9c2cf8c7223bceffba18db6aa91308682ac98c6b74d02aedba60ba59bc04db7a8a12cc2b355d6
data/README.md CHANGED
@@ -26,6 +26,7 @@ All these methods accept blocks for customization.
26
26
  ### Configuration methods for `Chop`:
27
27
 
28
28
  * `.register_creation_strategy`: Provide a key and a block to register alternate strategies for `.create!`, e.g. FactoryGirl.
29
+ * `.atomic_diff=`: When set to `true`, `#diff!` captures the root element's HTML in a single read and parses it locally with Nokogiri, avoiding multiple CDP round-trips that can cause stale element errors during DOM morphs (e.g. Turbo). Off by default. Can be overridden per-call with the `atomic:` keyword argument.
29
30
 
30
31
  ### Block methods for `#create!`:
31
32
 
@@ -55,7 +56,10 @@ Lifecycle hooks:
55
56
 
56
57
  Transform the table of Capybara nodes before converting them to text and passing to `diff!`.
57
58
 
58
- Overide Capybara finders:
59
+ Options (keyword arguments):
60
+ * `atomic: true/false`: Override the global `Chop.atomic_diff` setting for this call. Example: `table.diff! "table", atomic: true`
61
+
62
+ Override Capybara finders:
59
63
  * `#rows`: overrides existing default row finder.
60
64
  * `#cells`: overrides existing default cell finder.
61
65
  * `#text`: overrides existing default text finder.
data/lib/chop/config.rb CHANGED
@@ -1,7 +1,11 @@
1
1
  module Chop
2
2
  module Config
3
+ attr_accessor :atomic_diff
4
+
3
5
  def register_creation_strategy *args, &block
4
6
  Chop::Create.register_creation_strategy *args, &block
5
7
  end
6
8
  end
9
+
10
+ extend Config
7
11
  end
data/lib/chop/diff.rb CHANGED
@@ -2,15 +2,18 @@ require "active_support/core_ext/string/inflections"
2
2
  require "active_support/core_ext/object/blank"
3
3
  require "active_support/core_ext/class/attribute"
4
4
  require "active_support/hash_with_indifferent_access"
5
+ require "chop/config"
5
6
  require "chop/regex_templates"
6
7
 
7
8
  module Chop
8
9
  class Diff < Struct.new(:selector, :table, :session, :timeout, :block)
9
- def self.diff! selector, table, session: Capybara.current_session, timeout: Capybara.default_max_wait_time, errors: [], **kwargs, &block
10
+ def self.diff! selector, table, session: Capybara.current_session, timeout: Capybara.default_max_wait_time, atomic: Chop.atomic_diff, errors: [], **kwargs, &block
10
11
  errors += session.driver.invalid_element_errors
11
12
  errors += [Cucumber::MultilineArgument::DataTable::Different]
12
13
  session.document.synchronize timeout, errors: errors do
13
- new(selector, table, session, timeout, block).diff! **kwargs
14
+ instance = new(selector, table, session, timeout, block)
15
+ instance.instance_variable_set(:@atomic, atomic)
16
+ instance.diff! **kwargs
14
17
  end
15
18
  end
16
19
 
@@ -145,7 +148,10 @@ module Chop
145
148
  end
146
149
 
147
150
  rows.map do |row|
148
- row.map { |cell| text_finder.call(cell) }
151
+ row.map do |cell|
152
+ text = text_finder.call(cell)
153
+ @atomic && text.is_a?(String) ? normalize_atomic_text(text) : text
154
+ end
149
155
  end
150
156
  end
151
157
 
@@ -172,13 +178,31 @@ module Chop
172
178
  end
173
179
  end
174
180
 
181
+ # Normalize text from a Nokogiri snapshot to match what Capybara drivers
182
+ # return from visible_text. Replicates Capybara::Node::WhitespaceNormalizer#normalize_spacing.
183
+ def normalize_atomic_text(text)
184
+ text
185
+ .delete("\u200b\u200e\u200f")
186
+ .tr(" \n\f\t\v\u2028\u2029", " ")
187
+ .squeeze(" ")
188
+ .sub(/\A[[:space:]&&[^\u00a0]]+/, "")
189
+ .sub(/[[:space:]&&[^\u00a0]]+\z/, "")
190
+ .tr("\u00a0", " ")
191
+ end
192
+
175
193
  def root
176
194
  @root ||= begin
177
- if selector.is_a?(Capybara::Node::Element)
195
+ element = if selector.is_a?(Capybara::Node::Element)
178
196
  selector
179
197
  else
180
198
  session.find(selector, wait: timeout)
181
199
  end
200
+ if @atomic
201
+ html = element["outerHTML"] || element.native.to_html
202
+ Node(html)
203
+ else
204
+ element
205
+ end
182
206
  rescue Capybara::ElementNotFound
183
207
  raise unless @allow_not_found
184
208
  Node("")
data/lib/chop/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Chop
2
- VERSION = "0.37.0"
2
+ VERSION = "0.38.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.37.0
4
+ version: 0.38.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micah Geisel
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-02-04 00:00:00.000000000 Z
11
+ date: 2026-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord