view_component 2.58.0 → 2.61.0

Sign up to get free protection for your applications and to get access to all the features.

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