Skip to content

Commit

Permalink
Add support for using view components in rails engine (#1951)
Browse files Browse the repository at this point in the history
* Add module namespacing to generated components and other files

First step to add support for using view components in rails engine

* Config#default_preview_paths should include preview paths generated for rails engine

* Add some dummy tests

* Create test group for engine tests

* Fix test and simplecov setup for engine tests

* Tweak tests

* Allow to run tests with 'm' ;)

* Fix tests

* Improve tests

* Fix preview paths

* Return unique values for default_preview_path

* One step closer with tests

* Remove trailing whitespaces

* Update CHANGELOG

* Update contributors list

* Remove .keep

* Update changelog - be more precise in changes description

* Don't wrap with module namespace in tests and specs

Instead of wraping test/spec with module namespacing
pass module namespace inline with described class

* Rename Dummy => TestEngine

---------

Co-authored-by: Joel Hawksley <joel@hawksley.org>
  • Loading branch information
tkowalewski and joelhawksley authored Aug 27, 2024
1 parent 2d48c49 commit 80c7c8e
Show file tree
Hide file tree
Showing 22 changed files with 209 additions and 6 deletions.
10 changes: 8 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ require "yard/mattr_accessor_handler"
Rake::TestTask.new(:test) do |t|
t.libs << "test"
t.libs << "lib"
t.test_files = FileList["test/**/*_test.rb"]
t.test_files = FileList["test/sandbox/**/*_test.rb", "test/view_component/**/*_test.rb"]
end

Rake::TestTask.new(:engine_test) do |t|
t.libs << "test/test_engine"
t.libs << "test/test_engine/lib"
t.test_files = FileList["test/test_engine/**/*_test.rb"]
end

begin
Expand Down Expand Up @@ -128,4 +134,4 @@ namespace :docs do
end
end

task default: :test
task default: [:test, :engine_test]
4 changes: 4 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ nav_order: 5

## main

* Add Rails engine support to generators.

*Tomasz Kowalewski*

## 3.14.0

* Defer to built-in caching for language environment setup, rather than manually using `actions/cache` in CI.
Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ ViewComponent is built by over a hundred members of the community, including:
<img src="https://avatars.githubusercontent.com/neanias?s=64" alt="neanias" width="32" />
<img src="https://avatars.githubusercontent.com/allan-pires?s=64" alt="allan-pires" width="32" />
<img src="https://avatars.githubusercontent.com/jasonkim?s=64" alt="jasonkim" width="32" />
<img src="https://avatars.githubusercontent.com/tkowalewski" alt="tkowalewski" width="32" />

## Who uses ViewComponent?

Expand Down
3 changes: 2 additions & 1 deletion lib/rails/generators/component/templates/component.rb.tt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

<% module_namespacing do -%>
class <%= class_name %>Component < <%= parent_class %>
<%- if initialize_signature -%>
def initialize(<%= initialize_signature %>)
Expand All @@ -11,5 +12,5 @@ class <%= class_name %>Component < <%= parent_class %>
content_tag :h1, "Hello world!"<%= ", data: { controller: \"#{stimulus_controller}\" }" if options["stimulus"] %>
end
<%- end -%>

end
<% end -%>
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# frozen_string_literal: true

<% module_namespacing do -%>
class <%= class_name %>ComponentPreview < ViewComponent::Preview
def default
render(<%= class_name %>Component.new<%= "(#{render_signature})" if render_signature %>)
end
end
<% end -%>
2 changes: 1 addition & 1 deletion lib/rails/generators/rspec/templates/component_spec.rb.tt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require "rails_helper"

RSpec.describe <%= class_name %>Component, type: :component do
RSpec.describe <%= namespaced? ? "#{namespace.name}::" : '' %><%= class_name %>Component, type: :component do
pending "add some examples to (or delete) #{__FILE__}"

# it "renders something useful" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require "test_helper"

class <%= class_name %>ComponentTest < ViewComponent::TestCase
class <%= namespaced? ? "#{namespace.name}::" : '' %><%= class_name %>ComponentTest < ViewComponent::TestCase
def test_component_renders_something_useful
# assert_equal(
# %(<span>Hello, components!</span>),
Expand Down
18 changes: 18 additions & 0 deletions lib/view_component/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,29 @@ def defaults
# Defaults to `false`.

def default_preview_paths
(default_rails_preview_paths + default_rails_engines_preview_paths).uniq
end

def default_rails_preview_paths
return [] unless defined?(Rails.root) && Dir.exist?("#{Rails.root}/test/components/previews")

["#{Rails.root}/test/components/previews"]
end

def default_rails_engines_preview_paths
return [] unless defined?(Rails::Engine)

registered_rails_engines_with_previews.map do |descendant|
"#{descendant.root}/test/components/previews"
end
end

def registered_rails_engines_with_previews
Rails::Engine.descendants.select do |descendant|
defined?(descendant.root) && Dir.exist?("#{descendant.root}/test/components/previews")
end
end

def default_generate_options
options = ActiveSupport::OrderedOptions.new(false)
options.preview_path = ""
Expand Down
16 changes: 15 additions & 1 deletion test/sandbox/test/generators/component_generator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def test_component
run_generator

assert_file "app/components/user_component.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponent < ViewComponent::Base/, component)
assert_no_match(/def initialize/, component)
end
Expand All @@ -25,6 +26,7 @@ def test_component_tests
run_generator %w[user --test-framework test_unit]

assert_file "test/components/user_component_test.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponentTest < /, component)
assert_match(/def test_component_renders_something_useful/, component)
end
Expand All @@ -35,6 +37,7 @@ def test_component_preview
run_generator %w[user --preview]

assert_file "test/components/previews/user_component_preview.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponentPreview < /, component)
assert_match(/render\(UserComponent.new\)/, component)
end
Expand All @@ -45,6 +48,7 @@ def test_component_with_arguments
run_generator %w[user name]

assert_file "app/components/user_component.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponent < /, component)
assert_match(/def initialize\(name:\)/, component)
end
Expand All @@ -65,6 +69,7 @@ def test_component_with_parent
run_generator %w[user --parent MyOtherBaseComponent]

assert_file "app/components/user_component.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponent < MyOtherBaseComponent/, component)
end
end
Expand All @@ -74,6 +79,7 @@ def test_component_with_parent_and_application_component_class
run_generator %w[user --parent MyOtherBaseComponent]

assert_file "app/components/user_component.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponent < MyOtherBaseComponent/, component)
end
end
Expand All @@ -84,6 +90,7 @@ def test_component_with_parent_and_custom_component_parent_class
run_generator %w[user --parent MyOtherBaseComponent]

assert_file "app/components/user_component.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponent < MyOtherBaseComponent/, component)
end
end
Expand All @@ -92,13 +99,17 @@ def test_component_with_parent_and_custom_component_parent_class
def test_component_with_namespace
run_generator %w[admins/user]

assert_file "app/components/admins/user_component.rb", /class Admins::UserComponent < /
assert_file "app/components/admins/user_component.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class Admins::UserComponent < /, component)
end
end

def test_component_tests_with_namespace
run_generator %w[admins/user --test-framework test_unit]

assert_file "test/components/admins/user_component_test.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class Admins::UserComponentTest < /, component)
assert_match(/def test_component_renders_something_useful/, component)
end
Expand Down Expand Up @@ -142,6 +153,7 @@ def test_generating_components_with_application_component_class
run_generator %w[user]

assert_file "app/components/user_component.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponent < ApplicationComponent/, component)
end
end
Expand All @@ -152,6 +164,7 @@ def test_generating_components_with_custom_component_parent_class
run_generator %w[user]

assert_file "app/components/user_component.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponent < MyBaseComponent/, component)
end
end
Expand All @@ -163,6 +176,7 @@ def test_generating_components_with_application_component_class_and_custom_paren
run_generator %w[user]

assert_file "app/components/user_component.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponent < MyBaseComponent/, component)
end
end
Expand Down
7 changes: 7 additions & 0 deletions test/sandbox/test/generators/preview_generator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def test_component_preview
run_generator %w[user --preview]

assert_file "test/components/previews/user_component_preview.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponentPreview < /, component)
assert_match(/render\(UserComponent.new\)/, component)
end
Expand All @@ -29,6 +30,7 @@ def test_component_preview_with_preview_path_option
run_generator %w[user --preview --preview-path other/test/components/previews]

assert_file "other/test/components/previews/user_component_preview.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponentPreview < /, component)
assert_match(/render\(UserComponent.new\)/, component)
end
Expand All @@ -40,6 +42,7 @@ def test_component_preview_with_one_overridden_preview_path
run_generator %w[user --preview]

assert_file "spec/components/previews/user_component_preview.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponentPreview < /, component)
assert_match(/render\(UserComponent.new\)/, component)
end
Expand All @@ -61,6 +64,7 @@ def test_component_preview_with_two_overridden_preview_paths_and_preview_path_op
run_generator %w[user --preview --preview-path other/test/components/previews]

assert_file "other/test/components/previews/user_component_preview.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class UserComponentPreview < /, component)
assert_match(/render\(UserComponent.new\)/, component)
end
Expand All @@ -72,6 +76,7 @@ def test_component_preview_with_namespace
run_generator %w[admins/user --preview]

assert_file "test/components/previews/admins/user_component_preview.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class Admins::UserComponentPreview < /, component)
assert_match(/render\(Admins::UserComponent.new\)/, component)
end
Expand All @@ -83,6 +88,7 @@ def test_component_generator_with_attributes
run_generator %w[user nickname fullname]

assert_file "test/components/previews/user_component_preview.rb" do |preview|
assert_no_match(/module/, preview)
assert_match(/class UserComponentPreview/, preview)
assert_match(/render\(UserComponent.new\(nickname: "nickname", fullname: "fullname"\)\)/, preview)
end
Expand All @@ -94,6 +100,7 @@ def test_component_with_namespace_and_attributes
run_generator %w[admins/user nickname fullname]

assert_file "test/components/previews/admins/user_component_preview.rb" do |preview|
assert_no_match(/module/, preview)
assert_match(/class Admins::UserComponentPreview/, preview)
assert_match(/render\(Admins::UserComponent.new\(nickname: "nickname", fullname: "fullname"\)\)/, preview)
end
Expand Down
1 change: 1 addition & 0 deletions test/sandbox/test/generators/test_unit_generator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def test_generates_component
run_generator %w[Dummy data]

assert_file "test/components/dummy_component_test.rb" do |content|
assert_no_match(/module/, content)
assert_match(
/render_inline\(DummyComponent.new\(message: "Hello, components!"\)\).css\("span"\).to_html/, content
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div>Add Example template here</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

module TestEngine
class ExampleComponent < ViewComponent::Base; end
end
6 changes: 6 additions & 0 deletions test/test_engine/lib/test_engine.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require "test_engine/version"
require "test_engine/engine"

module TestEngine
# Your code goes here...
end
5 changes: 5 additions & 0 deletions test/test_engine/lib/test_engine/engine.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module TestEngine
class Engine < ::Rails::Engine
isolate_namespace TestEngine
end
end
3 changes: 3 additions & 0 deletions test/test_engine/lib/test_engine/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module TestEngine
VERSION = "0.1.0"
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module TestEngine
class ExampleComponentPreview < ViewComponent::Preview
def default
render(ExampleComponent.new)
end
end
end
23 changes: 23 additions & 0 deletions test/test_engine/test/config_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

require_relative "../test_helper"

module ViewComponent
class ConfigTest < TestCase
def setup
@config = ViewComponent::Config.new
end

def test_defaults_are_correct
assert_equal @config.generate, {preview_path: ""}
assert_equal @config.preview_controller, "ViewComponentsController"
assert_equal @config.preview_route, "/rails/view_components"
assert_equal @config.show_previews_source, false
assert_equal @config.instrumentation_enabled, false
assert_equal @config.use_deprecated_instrumentation_name, true
assert_equal @config.render_monkey_patch_enabled, true
assert_equal @config.show_previews, true
assert_equal @config.preview_paths, ["#{TestEngine::Engine.root}/test/components/previews"]
end
end
end
20 changes: 20 additions & 0 deletions test/test_engine/test/generators/component_generator_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

require_relative "../../test_helper"
require "rails/generators/component/component_generator"

class ComponentGeneratorTest < Rails::Generators::TestCase
tests Rails::Generators::ComponentGenerator
destination Dir.mktmpdir
setup :prepare_destination

def test_component
run_generator %w[example]

assert_file "app/components/test_engine/example_component.rb" do |component|
assert_match(/module TestEngine/, component)
assert_match(/class ExampleComponent < ViewComponent::Base/, component)
assert_no_match(/def initialize/, component)
end
end
end
22 changes: 22 additions & 0 deletions test/test_engine/test/generators/preview_generator_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

require_relative "../../test_helper"
require "rails/generators/preview/component_generator"

class PreviewGeneratorTest < Rails::Generators::TestCase
tests Preview::Generators::ComponentGenerator
destination Dir.mktmpdir
setup :prepare_destination

def test_component_preview
with_preview_paths([]) do
run_generator %w[example --preview]

assert_file "test/components/previews/test_engine/example_component_preview.rb" do |component|
assert_match(/module TestEngine/, component)
assert_match(/class ExampleComponentPreview < /, component)
assert_match(/render\(ExampleComponent.new\)/, component)
end
end
end
end
20 changes: 20 additions & 0 deletions test/test_engine/test/generators/test_unit_generator_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

require_relative "../../test_helper"
require "rails/generators/test_unit/component_generator"

class TestUnitGeneratorTest < Rails::Generators::TestCase
tests TestUnit::Generators::ComponentGenerator
destination Dir.mktmpdir
setup :prepare_destination

def test_component_tests
run_generator %w[example --test-framework test_unit]

assert_file "test/components/test_engine/example_component_test.rb" do |component|
assert_no_match(/module/, component)
assert_match(/class TestEngine::ExampleComponentTest < /, component)
assert_match(/def test_component_renders_something_useful/, component)
end
end
end
Loading

0 comments on commit 80c7c8e

Please sign in to comment.