Skip to content

Instantly share code, notes, and snippets.

@stevepolitodesign
Last active September 23, 2023 15:30
Show Gist options
  • Save stevepolitodesign/77163ab24ee5889a10c08682593ff6bc to your computer and use it in GitHub Desktop.
Save stevepolitodesign/77163ab24ee5889a10c08682593ff6bc to your computer and use it in GitHub Desktop.
Testing a Generator in a Rails Engine

Testing a Generator in a Rails Engine

Testing a generator in a Rails engine can result in unwanted modifications of files in the test/dummy directory.

# lib/generators/my_engine/install_generator.rb
module MyEngine
  module Generators
    class InstallGenerator < Rails::Generators::Base
      source_root File.expand_path("templates", __dir__)
      
      def create_users_table
        generate "migration", "create_users_table email:string:index password_digest:string"
      end
      
      def add_routes
        route "root to: 'home#index'"
      end      
    end
  end
end

What's Going On Here?

  • This class creates a new rails g my_engine:install command. When it is called a migration will be added to db/migrate/ and config/routes.rb will be updated.
  • This will happen even when the test suite is run and will affect the test/dummy directory resulting in unwanted changes.
# test/lib/generators/my_engine/install_generator_test.rb
require "test_helper"
require "generators/my_engine/install_generator"

class MyEngine::InstallGeneratorTest < Rails::Generators::TestCase
  tests ::MyEngine::Generators::InstallGenerator
  destination Rails.root

  setup :prepare_destination
  teardown :restore_destination

  test "creates migration for users table" do
    run_generator

    assert_migration "db/migrate/create_users_table.rb"
  end
  
  test "should add routes" do
    run_generator

    assert_file "config/routes.rb" do |file|
      assert_match(/root to: 'home#index'/, file)
    end
  end  

  private

  def backup_file(path)
    copy_file Rails.root.join(path), Rails.root.join("#{path}.bak")
  end

  def prepare_destination
    backup_file("config/routes.rb")
  end

  def remove_if_exists(path)
    full_path = Rails.root.join(path)
    FileUtils.rm_rf(full_path)
  end

  def restore_destination
    remove_if_exists("db/migrate")
    restore_file("config/routes.rb")
  end

  def restore_file(path)
    File.delete(Rails.root.join(path))
    copy_file Rails.root.join("#{path}.bak"), Rails.root.join(path)
    File.delete(Rails.root.join("#{path}.bak"))
  end
end

What's Going On Here?

  • We set the destination to the Rails.root. That way when run_generator is called the changes happen in the dummy app located in test/dummy.
  • We override the existing prepare_destination instance method with our own. This will be called before each test block is run, and serves to keep the test/dummy directory in a clean state. We call restore_destination to be called after each test is run via the teardown callback. This will restore any modified files and remove any generated files.

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment