view_component 2.58.0 → 2.61.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.

Potentially problematic release.


This version of view_component might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73dd7bae94ee1c5a5886e248924ccfea872df61e783e713c0744390d6729d128
4
- data.tar.gz: e70c67571e32098ee5997b7912d07e65d427e265766c5caa398bcd47d06d3e55
3
+ metadata.gz: f46bf10c68e5273401ec52134ae2cf55d844f9b01c55121e082146364194e144
4
+ data.tar.gz: 81ec5867c81158b0c06fdab309674f2f5a9cef7cf0546575308084ac928116c6
5
5
  SHA512:
6
- metadata.gz: '080f91f8f3f6aa9e0db95a4b533643c627be1e31fe8fcd32cea979556e52a351f956a9b01000f0a4654039f2588d88fa6680107f5b94c1103fa4a5c0190953f3'
7
- data.tar.gz: 7c4e322ca388053c13ad36ad8d79e706aede23d5a2e25d15cdadb2e2e8c6776c95a5981c5588134061534037fd89a11c859fe74110418072378ee4b14e10b8d6
6
+ metadata.gz: 05450d5c3e5376fe7aa4a2a934ee2b7179cafb91681cf1b6ed7f1469bd3db29f92d0ba6e96930e36403f7e250a3b7b8aeb7cc061aa30954d2d8524c6d7081d6b
7
+ data.tar.gz: 91101a168fee89fd23dad833c769027db7022a852b07b918d427b40a8b1997b861827724f7390dd470f4e69e1a8351638a43cd2d34f6df9bf20c64be0eb61d43
data/docs/CHANGELOG.md CHANGED
@@ -9,6 +9,67 @@ title: Changelog
9
9
 
10
10
  ## main
11
11
 
12
+ ## 2.61.0
13
+
14
+ * Ensure side-effects in `content` are consistently evaluated before components are rendered. This change effectively means that `content` is evaluated for every component render where `render?` returns true. As a result, code that is passed to a component via a block/content will now always be evaluated, before `#call`, which can reveal bugs in existing components.
15
+
16
+ *Blake Williams*
17
+
18
+ ## 2.60.0
19
+
20
+ * Add support for `render_preview` in RSpec tests.
21
+
22
+ *Thomas Hutterer*
23
+
24
+ ## 2.59.0
25
+
26
+ * Expose Capybara DSL methods directly inside tests.
27
+
28
+ The following Capybara methods are now available directly without having to use the `page` method:
29
+
30
+ * [`all`](https://rubydoc.info/github/teamcapybara/capybara/Capybara%2FNode%2FFinders:all)
31
+ * [`first`](https://rubydoc.info/github/teamcapybara/capybara/Capybara%2FNode%2FFinders:first)
32
+ * [`text`](https://rubydoc.info/github/teamcapybara/capybara/Capybara%2FNode%2FSimple:text)
33
+ * [`find`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FFinders:find)
34
+ * [`find_all`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FFinders:find_all)
35
+ * [`find_button`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FFinders:find_button)
36
+ * [`find_by_id`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FFinders:find_by_id)
37
+ * [`find_field`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FFinders:find_field)
38
+ * [`find_link`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FFinders:find_link)
39
+ * [`has_content?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_content%3F)
40
+ * [`has_text?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_text%3F)
41
+ * [`has_css?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_css%3F)
42
+ * [`has_no_content?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_content%3F)
43
+ * [`has_no_text?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_text%3F)
44
+ * [`has_no_css?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_css%3F)
45
+ * [`has_no_xpath?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_xpath%3F)
46
+ * [`has_xpath?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_xpath%3F)
47
+ * [`has_link?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_link%3F)
48
+ * [`has_no_link?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_link%3F)
49
+ * [`has_button?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_button%3F)
50
+ * [`has_no_button?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_button%3F)
51
+ * [`has_field?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_field%3F)
52
+ * [`has_no_field?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_field%3F)
53
+ * [`has_checked_field?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_checked_field%3F)
54
+ * [`has_unchecked_field?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_unchecked_field%3F)
55
+ * [`has_no_table?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_table%3F)
56
+ * [`has_table?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_table%3F)
57
+ * [`has_select?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_select%3F)
58
+ * [`has_no_select?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_select%3F)
59
+ * [`has_selector?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_selector%3F)
60
+ * [`has_no_selector?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_selector%3F)
61
+ * [`has_no_checked_field?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_checked_field%3F)
62
+ * [`has_no_unchecked_field?`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FNode%2FMatchers:has_no_unchecked_field%3F)
63
+
64
+ * Add support for `within*` Capybara DLS methods:
65
+
66
+ * [`within`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FSession:within)
67
+ * [`within_element`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FSession:within)
68
+ * [`within_fieldset`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FSession:within_fieldset)
69
+ * [`within_table`](https://rubydoc.info/github/teamcapybara/capybara/master/Capybara%2FSession:within_table)
70
+
71
+ *Jacob Carlborg*
72
+
12
73
  ## 2.58.0
13
74
 
14
75
  * Switch to `standardrb`.
@@ -124,6 +124,10 @@ module ViewComponent
124
124
  before_render
125
125
 
126
126
  if render?
127
+ # preload content to support slot delegation and to consistently perform
128
+ # side-effects that may exist in the block
129
+ content
130
+
127
131
  perform_render
128
132
  else
129
133
  ""
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ # This is a simpler version of {Capybara::Session}.
5
+ #
6
+ # It only includes {Capybara::Node::Finders}, {Capybara::Node::Matchers},
7
+ # {#within} and {#within_element}. It is useful in that it does not require a
8
+ # session, an application or a driver, but can still use Capybara's finders
9
+ # and matchers on any string that contains HTML.
10
+ class CapybaraSimpleSession
11
+ # Most of the code in this class is shamelessly stolen from the
12
+ # {Capybara::Session} class in the Capybara gem
13
+ # (https://github.com/teamcapybara/capybara/blob/e704d00879fb1d1e1a0cc01e04c101bcd8af4a68/lib/capybara/session.rb#L38).
14
+
15
+ NODE_METHODS = %i[
16
+ all
17
+ first
18
+ text
19
+
20
+ find
21
+ find_all
22
+ find_button
23
+ find_by_id
24
+ find_field
25
+ find_link
26
+
27
+ has_content?
28
+ has_text?
29
+ has_css?
30
+ has_no_content?
31
+ has_no_text?
32
+ has_no_css?
33
+ has_no_xpath?
34
+ has_xpath?
35
+ has_link?
36
+ has_no_link?
37
+ has_button?
38
+ has_no_button?
39
+ has_field?
40
+ has_no_field?
41
+ has_checked_field?
42
+ has_unchecked_field?
43
+ has_no_table?
44
+ has_table?
45
+ has_select?
46
+ has_no_select?
47
+ has_selector?
48
+ has_no_selector?
49
+ has_no_checked_field?
50
+ has_no_unchecked_field?
51
+
52
+ assert_selector
53
+ assert_no_selector
54
+ assert_all_of_selectors
55
+ assert_none_of_selectors
56
+ assert_any_of_selectors
57
+ assert_text
58
+ assert_no_text
59
+ ].freeze
60
+
61
+ private_constant :NODE_METHODS
62
+
63
+ SESSION_METHODS = %i[within within_element within_fieldset within_table].freeze
64
+
65
+ private_constant :SESSION_METHODS
66
+
67
+ DSL_METHODS = (NODE_METHODS + SESSION_METHODS).freeze
68
+
69
+ # Stolen from: https://github.com/teamcapybara/capybara/blob/e704d00879fb1d1e1a0cc01e04c101bcd8af4a68/lib/capybara/session.rb#L767-L774.
70
+ NODE_METHODS.each do |method|
71
+ if RUBY_VERSION >= "2.7"
72
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
73
+ def #{method}(...)
74
+ current_scope.#{method}(...)
75
+ end
76
+ METHOD
77
+ else
78
+ define_method method do |*args, &block|
79
+ current_scope.send(method, *args, &block)
80
+ end
81
+ end
82
+ end
83
+
84
+ # Initializes the receiver with the given string of HTML.
85
+ #
86
+ # @param html [String] the HTML to create the session out of
87
+ def initialize(html)
88
+ @document = Capybara::Node::Simple.new(html)
89
+ end
90
+
91
+ # (see Capybara::Session#within)
92
+ def within(*args, **kw_args)
93
+ new_scope = args.first.respond_to?(:to_capybara_node) ? args.first.to_capybara_node : find(*args, **kw_args)
94
+ begin
95
+ scopes.push(new_scope)
96
+ yield if block_given?
97
+ ensure
98
+ scopes.pop
99
+ end
100
+ end
101
+
102
+ # (see Capybara::Session#within_element)
103
+ alias_method :within_element, :within
104
+
105
+ # (see Capybara::Session#within_fieldset)
106
+ def within_fieldset(locator, &block)
107
+ within(:fieldset, locator, &block)
108
+ end
109
+
110
+ # (see Capybara::Session#within_table)
111
+ def within_table(locator, &block)
112
+ within(:table, locator, &block)
113
+ end
114
+
115
+ # (see Capybara::Node::Element#native)
116
+ def native
117
+ current_scope.native
118
+ end
119
+
120
+ private
121
+
122
+ attr_reader :document
123
+
124
+ def scopes
125
+ @scopes ||= [nil]
126
+ end
127
+
128
+ def current_scope
129
+ scopes.last.presence || document
130
+ end
131
+ end
132
+ end
@@ -15,11 +15,21 @@ module ViewComponent
15
15
  #
16
16
  # MyComponentTest -> MyComponentPreview etc.
17
17
  #
18
+ # In RSpec, `Preview` is appended to `described_class`.
19
+ #
18
20
  # @param preview [String] The name of the preview to be rendered.
19
21
  # @return [Nokogiri::HTML]
20
22
  def render_preview(name)
21
23
  begin
22
- preview_klass = self.class.name.gsub("Test", "Preview")
24
+ preview_klass = if respond_to?(:described_class)
25
+ if described_class.nil?
26
+ raise "`render_preview` expected a described_class, but it is nil."
27
+ end
28
+
29
+ "#{described_class}Preview"
30
+ else
31
+ self.class.name.gsub("Test", "Preview")
32
+ end
23
33
  preview_klass = preview_klass.constantize
24
34
  rescue NameError
25
35
  raise NameError.new(
@@ -1,15 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "view_component/render_preview_helper"
4
+ require "view_component/capybara_simple_session"
4
5
 
5
6
  module ViewComponent
6
7
  module TestHelpers
7
8
  begin
8
9
  require "capybara/minitest"
10
+
9
11
  include Capybara::Minitest::Assertions
10
12
 
13
+ CapybaraSimpleSession::DSL_METHODS.each do |method|
14
+ if RUBY_VERSION >= "2.7"
15
+ class_eval <<~METHOD, __FILE__, __LINE__ + 1
16
+ def #{method}(...)
17
+ page.method("#{method}").call(...)
18
+ end
19
+ METHOD
20
+ else
21
+ define_method method do |*args, &block|
22
+ page.send method, *args, &block
23
+ end
24
+ end
25
+ end
26
+
27
+ def self.included(mod)
28
+ Capybara::Node::Simple.send(:define_method, :to_capybara_node) do
29
+ self
30
+ end
31
+ end
32
+
11
33
  def page
12
- Capybara::Node::Simple.new(@rendered_content)
34
+ @page ||= CapybaraSimpleSession.new(rendered_content)
13
35
  end
14
36
 
15
37
  def refute_component_rendered
@@ -55,6 +77,7 @@ module ViewComponent
55
77
  # @param component [ViewComponent::Base, ViewComponent::Collection] The instance of the component to be rendered.
56
78
  # @return [Nokogiri::HTML]
57
79
  def render_inline(component, **args, &block)
80
+ @page = nil
58
81
  @rendered_content =
59
82
  if Rails.version.to_f >= 6.1
60
83
  controller.view_context.render(component, args, &block)
@@ -76,6 +99,7 @@ module ViewComponent
76
99
  # assert_text("Hello, World!")
77
100
  # ```
78
101
  def render_in_view_context(&block)
102
+ @page = nil
79
103
  @rendered_content = controller.view_context.instance_exec(&block)
80
104
  Nokogiri::HTML.fragment(@rendered_content)
81
105
  end
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 58
6
+ MINOR = 61
7
7
  PATCH = 0
8
8
 
9
9
  STRING = [MAJOR, MINOR, PATCH].join(".")
@@ -7,6 +7,7 @@ module ViewComponent
7
7
  extend ActiveSupport::Autoload
8
8
 
9
9
  autoload :Base
10
+ autoload :CapybaraSimpleSession
10
11
  autoload :Compiler
11
12
  autoload :CompileCache
12
13
  autoload :ComponentError
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.58.0
4
+ version: 2.61.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Open Source
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-13 00:00:00.000000000 Z
11
+ date: 2022-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -325,6 +325,7 @@ files:
325
325
  - lib/rails/generators/test_unit/templates/component_test.rb.tt
326
326
  - lib/view_component.rb
327
327
  - lib/view_component/base.rb
328
+ - lib/view_component/capybara_simple_session.rb
328
329
  - lib/view_component/collection.rb
329
330
  - lib/view_component/compile_cache.rb
330
331
  - lib/view_component/compiler.rb