From 2ede47f745acd6b89349eb9a28be22662a2cbb8d Mon Sep 17 00:00:00 2001 From: Daniel Pence Date: Wed, 2 Jun 2021 16:52:07 -0500 Subject: [PATCH] Add stories_generator (#3) * Basic generator * Adds basic stories files generator * Rubocop * Add desc to generator * Add specs for stories generator * Make Rubocop happy * Coverage * Rework coverage config * Lint * Move usage to its own file * Rename storybook -> storybook_rails * Add section to README * Update README.md --- .github/workflows/ci.yml | 2 +- README.md | 7 +++ lib/action_view/storybook/engine.rb | 2 + lib/generators/storybook_rails/USAGE | 12 ++++ .../storybook_rails/stories_generator.rb | 22 +++++++ .../templates/stories.html.erb.tt | 1 + .../storybook_rails/templates/stories.rb.tt | 11 ++++ .../storybook_rails/stories_generator_spec.rb | 62 +++++++++++++++++++ spec/spec_helper.rb | 18 +++--- 9 files changed, 128 insertions(+), 9 deletions(-) create mode 100644 lib/generators/storybook_rails/USAGE create mode 100644 lib/generators/storybook_rails/stories_generator.rb create mode 100644 lib/generators/storybook_rails/templates/stories.html.erb.tt create mode 100644 lib/generators/storybook_rails/templates/stories.rb.tt create mode 100644 spec/action_view/generators/storybook_rails/stories_generator_spec.rb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cbc10aa..2039b0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} - - name: Build and test with Rake + - name: Build and test with Rspec run: | gem install bundler:1.17.3 bundle update diff --git a/README.md b/README.md index b5193d7..7ca2492 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,13 @@ And a story template to render individual stories: It's up to you how handle rendering your partials in Storybook, but `storybook_rails` will look for a view template that matches the story name (`buttons/button_stories.html.erb` in the example above. In addition, `storybook_rails` provides a `story_params` helper which provides quick access to the params and args specified in the story config. You can use these parameters in your view template to render each story dynamically. Or not. It's up to you. +### Generating Storybook Files +`storybook_rails` includes a Rails generator to make it easy to generate the files outlined in the section above. + +To generate the files above, we could have done this: `bin/rails generate storybook_rails:stories Button primary secondary outline`. + +For more detail, `bin/rails storybook_rails:stories --help`. + ### Generating Storybook Stories JSON Generate the Storybook JSON stories by running the rake task: diff --git a/lib/action_view/storybook/engine.rb b/lib/action_view/storybook/engine.rb index 8b3c69d..17aa7e8 100644 --- a/lib/action_view/storybook/engine.rb +++ b/lib/action_view/storybook/engine.rb @@ -39,7 +39,9 @@ class Engine < Rails::Engine end rake_tasks do + # :nocov: load File.join(__dir__, "tasks/write_stories_json.rake") + # :nocov: end end end diff --git a/lib/generators/storybook_rails/USAGE b/lib/generators/storybook_rails/USAGE new file mode 100644 index 0000000..c15436c --- /dev/null +++ b/lib/generators/storybook_rails/USAGE @@ -0,0 +1,12 @@ +Description: +============ + Generates a [NAME]_stories.rb file and matching view template with + the given NAME (if one does not exist) and optional [story_names]. + +Example: +======== + bin/rails generate storybook_rails:stories Button default primary + + creates a Button story file and view template: + Story File: test/components/button_stories.rb + Template: test/components/button_component.html.erb diff --git a/lib/generators/storybook_rails/stories_generator.rb b/lib/generators/storybook_rails/stories_generator.rb new file mode 100644 index 0000000..8634804 --- /dev/null +++ b/lib/generators/storybook_rails/stories_generator.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require "rails/generators/named_base" + +module StorybookRails + class StoriesGenerator < Rails::Generators::NamedBase + source_root File.expand_path("templates", __dir__) + argument :stories, type: :array, default: [], banner: "stories" + check_class_collision suffix: "Stories" + + def generate_stories_files + template "stories.rb", File.join(stories_path.to_s, "#{file_path}_stories.rb") + template "stories.html.erb", File.join(stories_path.to_s, "#{file_path}_stories.html.erb") + end + + private + + def stories_path + Rails.application.config.storybook_rails.stories_path + end + end +end diff --git a/lib/generators/storybook_rails/templates/stories.html.erb.tt b/lib/generators/storybook_rails/templates/stories.html.erb.tt new file mode 100644 index 0000000..d8eb56d --- /dev/null +++ b/lib/generators/storybook_rails/templates/stories.html.erb.tt @@ -0,0 +1 @@ +
Render the <%= class_name %> partial here.
diff --git a/lib/generators/storybook_rails/templates/stories.rb.tt b/lib/generators/storybook_rails/templates/stories.rb.tt new file mode 100644 index 0000000..0ef6e8a --- /dev/null +++ b/lib/generators/storybook_rails/templates/stories.rb.tt @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class <%= class_name %>Stories < ActionView::Storybook::Stories +<%- stories.each do |story_name| -%> + story(:<%= story_name %>) do + controls do + end + end + +<%- end -%> +end diff --git a/spec/action_view/generators/storybook_rails/stories_generator_spec.rb b/spec/action_view/generators/storybook_rails/stories_generator_spec.rb new file mode 100644 index 0000000..e90e7b2 --- /dev/null +++ b/spec/action_view/generators/storybook_rails/stories_generator_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'fileutils' +require "rails/generators/test_case" +require "generators/storybook_rails/stories_generator" + +Rails.application.load_generators + +class StoriesGeneratorTest < Rails::Generators::TestCase + tests StorybookRails::StoriesGenerator + destination File.expand_path("../tmp", __dir__) + setup :prepare_destination + + arguments %w[Button primary] + + setup do + Rails.application.config.storybook_rails.stories_path = "./" + end + + teardown do + FileUtils.rm_rf(File.expand_path("../tmp", __dir__)) + end + + def test_stories_generator + run_generator + + assert_file "button_stories.rb" do |file| + assert_match(/class ButtonStories < /, file) + assert_match(/story\(:primary\)/, file) + end + + assert_file "button_stories.html.erb" do |file| + assert_match("
Render the Button partial here.
", file) + end + end + + def test_stories_generator_with_namespace + run_generator %w[buttons/button primary] + + assert_file "buttons/button_stories.rb" do |file| + assert_match(/class Buttons::ButtonStories < /, file) + assert_match(/story\(:primary\)/, file) + end + + assert_file "buttons/button_stories.html.erb" do |file| + assert_match("
Render the Buttons::Button partial here.
", file) + end + end + + def test_stories_generator_with_namespaced_classname + run_generator %w[Buttons::Button primary] + + assert_file "buttons/button_stories.rb" do |file| + assert_match(/class Buttons::ButtonStories < /, file) + assert_match(/story\(:primary\)/, file) + end + + assert_file "buttons/button_stories.html.erb" do |file| + assert_match("
Render the Buttons::Button partial here.
", file) + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2c1da51..b0e6cde 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,9 +1,14 @@ # frozen_string_literal: true +require 'simplecov' +SimpleCov.start do + command_name "rails#{ENV['RAILS_VERSION']}-ruby#{ENV['RUBY_VERSION']}" if ENV["RUBY_VERSION"] + add_filter 'spec' + add_group 'generators', 'lib/generators' + add_group 'action_view', 'lib/action_view' +end + require "bundler/setup" -require "action_view" -require "action_view/storybook" -require "action_controller" # Configure Rails Envinronment # we need to do this before including capybara @@ -12,12 +17,9 @@ require "rspec/expectations" require "rspec/rails" -require 'simplecov' +require 'minitest/autorun' +require 'minitest/spec' require 'pry' -SimpleCov.start do - command_name "rails#{ENV['RAILS_VERSION']}-ruby#{ENV['RUBY_VERSION']}" if ENV["RUBY_VERSION"] - add_filter 'spec' -end Dir[File.expand_path(File.join(File.dirname(__FILE__), "support", "**", "*.rb"))].sort.each { |f| require f }