Back to Repositories

Testing ActiveRecord Generator Operations in Devise

This test suite validates the ActiveRecord generator functionality in Devise, focusing on model generation, migration handling, and namespace management. It ensures proper file creation, migration syntax, and database configuration across different scenarios.

Test Coverage Overview

The test suite comprehensively covers ActiveRecord generator operations in Devise.

Key areas tested include:
  • Migration file creation and syntax validation
  • Custom database migration path handling
  • Namespaced model generation
  • Model updates and migration management
  • File deletion and cleanup processes
  • Column type specifications for IP addresses
  • Primary key type handling

Implementation Analysis

The testing approach employs Rails::Generators::TestCase for systematic generator validation. It utilizes pattern-based testing to verify file creation, content validation, and proper database migration syntax. The implementation leverages Rails engine simulation for testing namespace isolation and generator behavior within engine contexts.

Technical Details

Testing tools and configuration:
  • Rails::Generators::TestCase framework
  • Custom destination path setup
  • Rails Engine simulation for namespace testing
  • Migration path configuration manipulation
  • File assertion helpers
  • Behavior switching between creation and revocation

Best Practices Demonstrated

The test suite exemplifies robust testing practices for Rails generators.

Notable practices include:
  • Isolated test environments
  • Comprehensive file existence verification
  • Configuration state preservation
  • Edge case handling for namespaced models
  • Proper cleanup and teardown
  • Migration content validation

heartcombo/devise

test/generators/active_record_generator_test.rb

            
# frozen_string_literal: true

require "test_helper"

if DEVISE_ORM == :active_record
  require "generators/active_record/devise_generator"

  class ActiveRecordGeneratorTest < Rails::Generators::TestCase
    tests ActiveRecord::Generators::DeviseGenerator
    destination File.expand_path("../../tmp", __FILE__)
    setup :prepare_destination

    test "all files are properly created with rails31 migration syntax" do
      run_generator %w(monster)
      assert_migration "db/migrate/devise_create_monsters.rb", /def change/
    end

    test "all files are properly created with changed db/migrate path in application configuration" do
      old_paths = Rails.application.config.paths["db/migrate"]
      Rails.application.config.paths.add "db/migrate", with: "db2/migrate"

      run_generator %w(monster)
      assert_migration "db2/migrate/devise_create_monsters.rb", /def change/

      Rails.application.config.paths["db/migrate"] = old_paths
    end

    test "all files for namespaced model are properly created" do
      run_generator %w(admin/monster)
      assert_migration "db/migrate/devise_create_admin_monsters.rb", /def change/
    end

    test "update model migration when model exists" do
      run_generator %w(monster)
      assert_file "app/models/monster.rb"
      run_generator %w(monster)
      assert_migration "db/migrate/add_devise_to_monsters.rb"
    end

    test "update model migration when model exists with changed db/migrate path in application configuration" do
      old_paths = Rails.application.config.paths["db/migrate"]
      Rails.application.config.paths.add "db/migrate", with: "db2/migrate"

      run_generator %w(monster)
      assert_file "app/models/monster.rb"
      run_generator %w(monster)

      assert_migration "db2/migrate/add_devise_to_monsters.rb"

      Rails.application.config.paths["db/migrate"] = old_paths
    end

    test "all files are properly deleted" do
      run_generator %w(monster)
      run_generator %w(monster)
      assert_migration "db/migrate/devise_create_monsters.rb"
      assert_migration "db/migrate/add_devise_to_monsters.rb"
      run_generator %w(monster), behavior: :revoke
      assert_no_migration "db/migrate/add_devise_to_monsters.rb"
      assert_migration "db/migrate/devise_create_monsters.rb"
      run_generator %w(monster), behavior: :revoke
      assert_no_file "app/models/monster.rb"
      assert_no_migration "db/migrate/devise_create_monsters.rb"
    end

    test "use string column type for ip addresses" do
      run_generator %w(monster)
      assert_migration "db/migrate/devise_create_monsters.rb", /t.string   :current_sign_in_ip/
      assert_migration "db/migrate/devise_create_monsters.rb", /t.string   :last_sign_in_ip/
    end

    test "do NOT add primary key type when NOT specified in rails generator" do
      run_generator %w(monster)
      assert_migration "db/migrate/devise_create_monsters.rb", /create_table :monsters do/
    end

    test "add primary key type with rails 5 when specified in rails generator" do
      run_generator ["monster", "--primary_key_type=uuid"]
      assert_migration "db/migrate/devise_create_monsters.rb", /create_table :monsters, id: :uuid do/
    end
  end

  module RailsEngine
    class Engine < Rails::Engine
      isolate_namespace RailsEngine
    end
  end

  def simulate_inside_engine(engine, namespace)
    if Rails::Generators.respond_to?(:namespace=)
      swap Rails::Generators, namespace: namespace do
        yield
      end
    else
      swap Rails, application: engine.instance do
        yield
      end
    end
  end

  class ActiveRecordEngineGeneratorTest < Rails::Generators::TestCase
    tests ActiveRecord::Generators::DeviseGenerator
    destination File.expand_path("../../tmp", __FILE__)
    setup :prepare_destination

    test "all files are properly created in rails 4.0" do
      simulate_inside_engine(RailsEngine::Engine, RailsEngine) do
        run_generator ["monster"]

        assert_file "app/models/rails_engine/monster.rb", /devise/
        assert_file "app/models/rails_engine/monster.rb" do |content|
          assert_no_match %r{attr_accessible :email}, content
        end
      end
    end

  end
end