Back to Repositories

Testing Sequence Reset Implementation in Factory Bot

This test suite validates the sequence resetting functionality in FactoryBot, focusing on the rewind_sequences method. It ensures proper handling of both global and local sequences for generating test data, particularly for email addresses and names across different factory definitions.

Test Coverage Overview

The test suite comprehensively covers sequence resetting functionality in FactoryBot.

Key areas tested include:
  • Basic sequence resetting for global sequences
  • Inline sequence handling within factories
  • Collision prevention between global and local sequences
  • Factory-prefixed sequence behavior
  • Sequence handling within identical traits across different factories

Implementation Analysis

The testing approach uses RSpec’s describe/it blocks to organize test scenarios systematically. The implementation leverages FactoryBot’s sequence definition syntax and combines it with dynamic class creation for thorough testing.

Notable patterns include:
  • Dynamic test class definition using define_class
  • Factory definition with both global and local sequences
  • Usage of build_list for multiple object creation
  • Trait-based sequence definition testing

Technical Details

Testing tools and configuration:
  • RSpec as the testing framework
  • FactoryBot’s Syntax::Methods inclusion
  • Dynamic class creation helpers
  • Sequence definition with both simple and enumerable values
  • Factory trait definitions
  • Multiple assertion patterns for sequence verification

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through organized and comprehensive test coverage.

Notable practices include:
  • Isolated test cases for different sequence scenarios
  • Clear test case naming and organization
  • Comprehensive edge case coverage
  • Proper setup and teardown of test data
  • Effective use of factory patterns and traits

thoughtbot/factory_bot

spec/acceptance/sequence_resetting_spec.rb

            
describe "FactoryBot.rewind_sequences" do
  include FactoryBot::Syntax::Methods

  it "resets all sequences back to their starting values" do
    FactoryBot.define do
      sequence(:email) { |n| "somebody#{n}@example.com" }
      sequence(:name, %w[Joe Josh].to_enum)
    end

    2.times do
      generate(:email)
      generate(:name)
    end

    FactoryBot.rewind_sequences

    email = generate(:email)
    name = generate(:name)

    expect(email).to eq "[email protected]"
    expect(name).to eq "Joe"
  end

  it "resets inline sequences back to their starting value" do
    define_class("User") { attr_accessor :email }

    FactoryBot.define do
      factory :user do
        sequence(:email) { |n| "somebody#{n}@example.com" }
      end
    end

    build_list(:user, 2)

    FactoryBot.rewind_sequences

    user = build(:user)

    expect(user.email).to eq "[email protected]"
  end

  it "does not collide with globally registered factories" do
    define_class("User") { attr_accessor :email }

    FactoryBot.define do
      sequence(:email) { |n| "global-somebody#{n}@example.com" }

      factory :user do
        sequence(:email) { |n| "local-somebody#{n}@example.com" }
      end
    end

    2.times do
      generate(:email)
    end

    build_list(:user, 2)

    FactoryBot.rewind_sequences

    user = build(:user)
    email = generate(:email)

    expect(user.email).to eq "[email protected]"
    expect(email).to eq "[email protected]"
  end

  it "still allows global sequences prefixed with a factory name" do
    define_class("User") { attr_accessor :email }

    FactoryBot.define do
      sequence(:user_email) { |n| "global-somebody#{n}@example.com" }

      factory :user do
        sequence(:email) { |n| "local-somebody#{n}@example.com" }
      end
    end

    2.times do
      generate(:user_email)
    end

    build_list(:user, 2)

    FactoryBot.rewind_sequences

    user = build(:user)
    email = generate(:user_email)

    expect(user.email).to eq "[email protected]"
    expect(email).to eq "[email protected]"
  end

  it "allows setting sequences within identically named traits" do
    define_class("User") { attr_accessor :email }
    define_class("Person") { attr_accessor :email }

    FactoryBot.define do
      factory :user do
        trait :with_email do
          sequence(:email) { |n| "user#{n}@example.com" }
        end
      end

      factory :person do
        trait :with_email do
          sequence(:email) { |n| "person#{n}@example.com" }
        end
      end
    end

    build_list(:user, 2, :with_email)
    build_list(:person, 2, :with_email)

    FactoryBot.rewind_sequences

    user = build(:user, :with_email)
    person = build(:person, :with_email)

    expect(user.email).to eq "[email protected]"
    expect(person.email).to eq "[email protected]"
  end
end