dommy-rails 0.13.0 → 0.15.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: decdc2f02ac2d15f9f1447da1f008fd9b406bb3c423f16c70f7d1c1251d25b45
4
- data.tar.gz: 61baf3154db33257f6e508ccc15b21c3274708ad1444fb13495d6bfff2cc4a24
3
+ metadata.gz: 3e832ec033a262705b85c5c72f9a28595dcb86536a8c4313e85eb306e468a3e1
4
+ data.tar.gz: 993d8b9e0642c801ac082431027d1c7bcf22b0f29a8235e4be8b02f9b00644d9
5
5
  SHA512:
6
- metadata.gz: 55439022b061482154d59c057654a8010edf7f7c1cf430cae0edfc4eb91e23822ea779d97acbe128820519642e699c4fd8fa2918e584d05503eae401fb66b3a2
7
- data.tar.gz: 5f307f03a7c9b6e745486ca6ef23a882ce0af09abe6d387708b21de98409aae35f6dc8fc90f0074ab62ee2fc947fb9bf7579c6e734383cc81a86eb9fe5d12e3c
6
+ metadata.gz: 579c17a1fac069aec1c73a8abeb9dbf820296f7e4239d2acd61eee9ae038c9d56772f53860435481ff1a2a75fd77c273fede031ae02c295b272909c46ccdc79f
7
+ data.tar.gz: 9635048cdd887fe04520855e3e02e95baff0d00f677637447cf565d53fe4f3e2177a911057ed296267117422d41a03b72ff355a3b17293e241047866e0cabb35
@@ -38,14 +38,10 @@ module Dommy
38
38
  # Greedy ordered-subsequence match: each expected child must match a later
39
39
  # actual child, allowing extra actual children in between.
40
40
  def children_match?(expected_children, actual_children)
41
- cursor = 0
42
- expected_children.each do |expected|
43
- cursor += 1 until cursor >= actual_children.size || node_match?(expected, actual_children[cursor])
44
- return false if cursor >= actual_children.size
45
-
46
- cursor += 1
41
+ remaining = actual_children.each
42
+ expected_children.all? do |expected|
43
+ remaining.any? { |actual| node_match?(expected, actual) }
47
44
  end
48
- true
49
45
  end
50
46
 
51
47
  # --- parsing (indentation outline -> Node tree) ---
@@ -25,7 +25,7 @@ module Dommy
25
25
  def self.included(base)
26
26
  if base.respond_to?(:after)
27
27
  base.after do |example|
28
- dir = dommy_browser_after(failed: example.exception ? true : false,
28
+ dir = dommy_browser_after(failed: !!example.exception,
29
29
  label: example.full_description, exception: example.exception)
30
30
  # Point the failure output at the saved bundle and the one command
31
31
  # that opens it in the standalone viewer.
@@ -13,9 +13,9 @@ module Dommy
13
13
  module_function
14
14
 
15
15
  def duplicate_ids(document)
16
- all_elements = document.query_selector_all("*[id]").to_a
17
- ids = all_elements.map { |el| el.get_attribute("id") }
18
- ids.select { |id| ids.count(id) > 1 }.uniq
16
+ document.query_selector_all("*[id]").to_a
17
+ .map { |el| el.get_attribute("id") }
18
+ .tally.select { |_, count| count > 1 }.keys
19
19
  end
20
20
 
21
21
  def invalid_aria_references(document)
@@ -8,25 +8,25 @@ module Dommy
8
8
  module_function
9
9
 
10
10
  def html_body(mail)
11
- if mail.respond_to?(:html_part) && mail.html_part
12
- mail.html_part.body.to_s
13
- elsif mail.respond_to?(:body)
14
- mail.body.to_s
15
- end
11
+ part_body(mail, :html_part)
16
12
  end
17
13
 
18
14
  def plain_body(mail)
19
- if mail.respond_to?(:text_part) && mail.text_part
20
- mail.text_part.body.to_s
21
- elsif mail.respond_to?(:body)
22
- mail.body.to_s
23
- end
15
+ part_body(mail, :text_part)
24
16
  end
25
17
 
26
18
  def html_document(mail)
27
19
  body = html_body(mail)
28
20
  body ? Dommy.parse(body).document : nil
29
21
  end
22
+
23
+ def part_body(mail, part_name)
24
+ part = mail.public_send(part_name) if mail.respond_to?(part_name)
25
+ return part.body.to_s if part
26
+
27
+ mail.body.to_s if mail.respond_to?(:body)
28
+ end
29
+ private_class_method :part_body
30
30
  end
31
31
  end
32
32
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dommy
2
4
  module Rails
3
5
  module Minitest
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "dommy/minitest"
2
4
  require_relative "../rails"
3
5
  require_relative "minitest/assertions"
@@ -120,7 +120,18 @@ module Dommy
120
120
  HavePlainText.new(text)
121
121
  end
122
122
 
123
+ # Negation is always the inverse of the positive match, so every
124
+ # matcher gets `does_not_match?` from here and only implements
125
+ # `matches?` plus its failure messages.
126
+ module Negatable
127
+ def does_not_match?(actual)
128
+ !matches?(actual)
129
+ end
130
+ end
131
+
123
132
  class HaveForm
133
+ include Negatable
134
+
124
135
  def initialize(action:, method:, model:)
125
136
  @action = action
126
137
  @method = method
@@ -132,10 +143,6 @@ module Dommy
132
143
  Dommy::Rails::FormInspector.matches?(@document, action: @action, method: @method, model: @model)
133
144
  end
134
145
 
135
- def does_not_match?(actual)
136
- !matches?(actual)
137
- end
138
-
139
146
  def description
140
147
  "have form #{criteria_description}"
141
148
  end
@@ -160,6 +167,8 @@ module Dommy
160
167
  end
161
168
 
162
169
  class HaveXPath
170
+ include Negatable
171
+
163
172
  def initialize(expression, text:, count:)
164
173
  @expression = expression
165
174
  @text = text
@@ -171,10 +180,6 @@ module Dommy
171
180
  Dommy::Internal::DomMatching.count_matches?(@matched.size, @count)
172
181
  end
173
182
 
174
- def does_not_match?(actual)
175
- !matches?(actual)
176
- end
177
-
178
183
  def description
179
184
  "have XPath #{@expression.inspect}"
180
185
  end
@@ -189,6 +194,8 @@ module Dommy
189
194
  end
190
195
 
191
196
  class HaveTitle
197
+ include Negatable
198
+
192
199
  def initialize(expected)
193
200
  @expected = expected
194
201
  end
@@ -198,10 +205,6 @@ module Dommy
198
205
  Dommy::Rails::PageInspector.title_matches?(@document, @expected)
199
206
  end
200
207
 
201
- def does_not_match?(actual)
202
- !matches?(actual)
203
- end
204
-
205
208
  def description
206
209
  "have title #{@expected.inspect}"
207
210
  end
@@ -219,6 +222,8 @@ module Dommy
219
222
  # snapshot (its nodes must appear in the actual tree, in order); names
220
223
  # may be `/regex/`.
221
224
  class MatchAriaSnapshot
225
+ include Negatable
226
+
222
227
  def initialize(expected)
223
228
  @expected = expected
224
229
  end
@@ -228,10 +233,6 @@ module Dommy
228
233
  Dommy::Rails::AriaSnapshotMatching.matches?(@actual, @expected)
229
234
  end
230
235
 
231
- def does_not_match?(actual)
232
- !matches?(actual)
233
- end
234
-
235
236
  def description
236
237
  "match aria snapshot"
237
238
  end
@@ -246,6 +247,8 @@ module Dommy
246
247
  end
247
248
 
248
249
  class HaveMeta
250
+ include Negatable
251
+
249
252
  def initialize(name:, property:, content:)
250
253
  @name = name
251
254
  @property = property
@@ -256,10 +259,6 @@ module Dommy
256
259
  Dommy::Rails::PageInspector.meta_matches?(MatchTarget.document(actual), name: @name, property: @property, content: @content)
257
260
  end
258
261
 
259
- def does_not_match?(actual)
260
- !matches?(actual)
261
- end
262
-
263
262
  def description
264
263
  "have meta #{criteria_description}"
265
264
  end
@@ -284,14 +283,12 @@ module Dommy
284
283
  end
285
284
 
286
285
  class HaveCsrfMetaTags
286
+ include Negatable
287
+
287
288
  def matches?(actual)
288
289
  Dommy::Rails::PageInspector.csrf_meta_tags?(MatchTarget.document(actual))
289
290
  end
290
291
 
291
- def does_not_match?(actual)
292
- !matches?(actual)
293
- end
294
-
295
292
  def description
296
293
  "have Rails CSRF meta tags"
297
294
  end
@@ -306,14 +303,12 @@ module Dommy
306
303
  end
307
304
 
308
305
  class HaveAuthenticityToken
306
+ include Negatable
307
+
309
308
  def matches?(actual)
310
309
  Dommy::Rails::PageInspector.authenticity_token?(MatchTarget.document(actual))
311
310
  end
312
311
 
313
- def does_not_match?(actual)
314
- !matches?(actual)
315
- end
316
-
317
312
  def description
318
313
  "have Rails authenticity token field"
319
314
  end
@@ -328,6 +323,8 @@ module Dommy
328
323
  end
329
324
 
330
325
  class HaveLink
326
+ include Negatable
327
+
331
328
  def initialize(text, href:, count:)
332
329
  @text = text
333
330
  @href = href
@@ -339,10 +336,6 @@ module Dommy
339
336
  Dommy::Internal::DomMatching.count_matches?(@matched.size, @count)
340
337
  end
341
338
 
342
- def does_not_match?(actual)
343
- !matches?(actual)
344
- end
345
-
346
339
  def description
347
340
  "have link"
348
341
  end
@@ -357,6 +350,8 @@ module Dommy
357
350
  end
358
351
 
359
352
  class HaveTurboFrame
353
+ include Negatable
354
+
360
355
  def initialize(id, text:, count:)
361
356
  @id = id
362
357
  @text = text
@@ -370,10 +365,6 @@ module Dommy
370
365
  ok
371
366
  end
372
367
 
373
- def does_not_match?(actual)
374
- !matches?(actual)
375
- end
376
-
377
368
  def description
378
369
  "have turbo-frame#{@id ? " ##{@id}" : ""}"
379
370
  end
@@ -388,6 +379,8 @@ module Dommy
388
379
  end
389
380
 
390
381
  class HaveSelect
382
+ include Negatable
383
+
391
384
  def initialize(name, label:, count:)
392
385
  @name = name
393
386
  @label = label
@@ -399,10 +392,6 @@ module Dommy
399
392
  Dommy::Internal::DomMatching.count_matches?(@matched.size, @count)
400
393
  end
401
394
 
402
- def does_not_match?(actual)
403
- !matches?(actual)
404
- end
405
-
406
395
  def description
407
396
  "have select"
408
397
  end
@@ -417,6 +406,8 @@ module Dommy
417
406
  end
418
407
 
419
408
  class HaveCheckableField
409
+ include Negatable
410
+
420
411
  def initialize(name, checked:)
421
412
  @name = name
422
413
  @checked = checked
@@ -427,10 +418,6 @@ module Dommy
427
418
  @matched.any?
428
419
  end
429
420
 
430
- def does_not_match?(actual)
431
- !matches?(actual)
432
- end
433
-
434
421
  def description
435
422
  "have #{@checked ? 'checked' : 'unchecked'} field"
436
423
  end
@@ -445,6 +432,8 @@ module Dommy
445
432
  end
446
433
 
447
434
  class HaveTurboStream
435
+ include Negatable
436
+
448
437
  def initialize(action:, target:)
449
438
  @action = action
450
439
  @target = target
@@ -456,10 +445,6 @@ module Dommy
456
445
  !stream.nil?
457
446
  end
458
447
 
459
- def does_not_match?(actual)
460
- !matches?(actual)
461
- end
462
-
463
448
  def description
464
449
  "have turbo-stream action=#{@action.inspect} target=#{@target.inspect}"
465
450
  end
@@ -474,6 +459,8 @@ module Dommy
474
459
  end
475
460
 
476
461
  class HaveStimulusController
462
+ include Negatable
463
+
477
464
  def initialize(name)
478
465
  @name = name
479
466
  end
@@ -482,10 +469,6 @@ module Dommy
482
469
  Dommy::Rails::Stimulus.controller?(MatchTarget.document(actual), @name)
483
470
  end
484
471
 
485
- def does_not_match?(actual)
486
- !matches?(actual)
487
- end
488
-
489
472
  def description
490
473
  "have Stimulus controller #{@name.inspect}"
491
474
  end
@@ -500,6 +483,8 @@ module Dommy
500
483
  end
501
484
 
502
485
  class HaveStimulusAction
486
+ include Negatable
487
+
503
488
  def initialize(action)
504
489
  @action = action
505
490
  end
@@ -508,10 +493,6 @@ module Dommy
508
493
  Dommy::Rails::Stimulus.action?(MatchTarget.document(actual), @action)
509
494
  end
510
495
 
511
- def does_not_match?(actual)
512
- !matches?(actual)
513
- end
514
-
515
496
  def description
516
497
  "have Stimulus action #{@action.inspect}"
517
498
  end
@@ -526,6 +507,8 @@ module Dommy
526
507
  end
527
508
 
528
509
  class HaveStimulusTarget
510
+ include Negatable
511
+
529
512
  def initialize(controller, target)
530
513
  @controller = controller
531
514
  @target = target
@@ -535,10 +518,6 @@ module Dommy
535
518
  Dommy::Rails::Stimulus.target?(MatchTarget.document(actual), @controller, @target)
536
519
  end
537
520
 
538
- def does_not_match?(actual)
539
- !matches?(actual)
540
- end
541
-
542
521
  def description
543
522
  "have Stimulus target #{@controller.inspect}.#{@target.inspect}"
544
523
  end
@@ -553,6 +532,8 @@ module Dommy
553
532
  end
554
533
 
555
534
  class HaveStimulusValue
535
+ include Negatable
536
+
556
537
  def initialize(controller, key, value)
557
538
  @controller = controller
558
539
  @key = key
@@ -563,10 +544,6 @@ module Dommy
563
544
  Dommy::Rails::Stimulus.value?(MatchTarget.document(actual), @controller, @key, @value)
564
545
  end
565
546
 
566
- def does_not_match?(actual)
567
- !matches?(actual)
568
- end
569
-
570
547
  def description
571
548
  "have Stimulus value #{@controller.inspect}.#{@key.inspect}"
572
549
  end
@@ -581,15 +558,13 @@ module Dommy
581
558
  end
582
559
 
583
560
  class HaveNoDuplicateIds
561
+ include Negatable
562
+
584
563
  def matches?(actual)
585
564
  @issues = Dommy::Rails::Lint.duplicate_ids(MatchTarget.document(actual))
586
565
  @issues.empty?
587
566
  end
588
567
 
589
- def does_not_match?(actual)
590
- !matches?(actual)
591
- end
592
-
593
568
  def description
594
569
  "have no duplicate ids"
595
570
  end
@@ -604,15 +579,13 @@ module Dommy
604
579
  end
605
580
 
606
581
  class HaveNoInvalidAriaReferences
582
+ include Negatable
583
+
607
584
  def matches?(actual)
608
585
  @issues = Dommy::Rails::Lint.invalid_aria_references(MatchTarget.document(actual))
609
586
  @issues.empty?
610
587
  end
611
588
 
612
- def does_not_match?(actual)
613
- !matches?(actual)
614
- end
615
-
616
589
  def description
617
590
  "have no invalid ARIA references"
618
591
  end
@@ -627,15 +600,13 @@ module Dommy
627
600
  end
628
601
 
629
602
  class HaveNoMissingFormLabels
603
+ include Negatable
604
+
630
605
  def matches?(actual)
631
606
  @issues = Dommy::Rails::Lint.missing_form_labels(MatchTarget.document(actual))
632
607
  @issues.empty?
633
608
  end
634
609
 
635
- def does_not_match?(actual)
636
- !matches?(actual)
637
- end
638
-
639
610
  def description
640
611
  "have no missing form labels"
641
612
  end
@@ -650,15 +621,13 @@ module Dommy
650
621
  end
651
622
 
652
623
  class HaveNoEmptyLinks
624
+ include Negatable
625
+
653
626
  def matches?(actual)
654
627
  @issues = Dommy::Rails::Lint.empty_links(MatchTarget.document(actual))
655
628
  @issues.empty?
656
629
  end
657
630
 
658
- def does_not_match?(actual)
659
- !matches?(actual)
660
- end
661
-
662
631
  def description
663
632
  "have no empty links"
664
633
  end
@@ -673,15 +642,13 @@ module Dommy
673
642
  end
674
643
 
675
644
  class HaveNoNestedInteractiveElements
645
+ include Negatable
646
+
676
647
  def matches?(actual)
677
648
  @issues = Dommy::Rails::Lint.nested_interactive_elements(MatchTarget.document(actual))
678
649
  @issues.empty?
679
650
  end
680
651
 
681
- def does_not_match?(actual)
682
- !matches?(actual)
683
- end
684
-
685
652
  def description
686
653
  "have no nested interactive elements"
687
654
  end
@@ -696,6 +663,8 @@ module Dommy
696
663
  end
697
664
 
698
665
  class HaveHtmlLink
666
+ include Negatable
667
+
699
668
  def initialize(text, href:, count:)
700
669
  @text = text
701
670
  @href = href
@@ -710,10 +679,6 @@ module Dommy
710
679
  Dommy::Internal::DomMatching.count_matches?(@matched.size, @count)
711
680
  end
712
681
 
713
- def does_not_match?(mail)
714
- !matches?(mail)
715
- end
716
-
717
682
  def description
718
683
  "have HTML link"
719
684
  end
@@ -730,6 +695,8 @@ module Dommy
730
695
  end
731
696
 
732
697
  class HaveHtmlText
698
+ include Negatable
699
+
733
700
  def initialize(text)
734
701
  @text = text
735
702
  end
@@ -742,10 +709,6 @@ module Dommy
742
709
  Dommy::Internal::DomMatching.text_matches?(@actual, @text)
743
710
  end
744
711
 
745
- def does_not_match?(mail)
746
- !matches?(mail)
747
- end
748
-
749
712
  def description
750
713
  "have HTML text #{@text.inspect}"
751
714
  end
@@ -762,6 +725,8 @@ module Dommy
762
725
  end
763
726
 
764
727
  class HavePlainText
728
+ include Negatable
729
+
765
730
  def initialize(text)
766
731
  @text = text
767
732
  end
@@ -771,10 +736,6 @@ module Dommy
771
736
  Dommy::Internal::DomMatching.text_matches?(@actual, @text)
772
737
  end
773
738
 
774
- def does_not_match?(mail)
775
- !matches?(mail)
776
- end
777
-
778
739
  def description
779
740
  "have plain text #{@text.inspect}"
780
741
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "cgi"
3
+ require "cgi/escape"
4
4
  require "uri"
5
5
 
6
6
  module Dommy
@@ -32,7 +32,7 @@ module Dommy
32
32
  path = path.chomp("/") unless path == "/"
33
33
 
34
34
  query = if uri.query
35
- params = URI.decode_www_form(uri.query).sort_by { |k, _| k }
35
+ params = URI.decode_www_form(uri.query).sort_by(&:first)
36
36
  URI.encode_www_form(params)
37
37
  end
38
38
 
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dommy
2
4
  module Rails
3
- VERSION = "0.13.0"
5
+ VERSION = "0.15.0"
4
6
  end
5
7
  end
data/lib/dommy/rails.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "dommy"
2
4
  require_relative "rails/version"
3
5
  require_relative "rails/form_inspector"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dommy-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - takahashim
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 0.13.0
18
+ version: 0.15.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 0.13.0
25
+ version: 0.15.0
26
26
  description: Rails-specific matchers and assertions for Dommy, including form helper
27
27
  understanding, Turbo Stream support, Stimulus attribute checking, and HTML quality
28
28
  linting.
@@ -73,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  requirements: []
76
- rubygems_version: 3.6.9
76
+ rubygems_version: 4.0.20
77
77
  specification_version: 4
78
78
  summary: Rails integration for Dommy DOM testing
79
79
  test_files: []