diff --git a/lib/factory_bot.rb b/lib/factory_bot.rb index b17ab09..2e5545c 100644 --- a/lib/factory_bot.rb +++ b/lib/factory_bot.rb @@ -111,6 +111,10 @@ module FactoryBot sequences.find(name) end + def self.rewind_sequences + sequences.each(&:rewind) + end + def self.register_trait(trait) trait.names.each do |name| traits.register(name, trait) diff --git a/lib/factory_bot/sequence.rb b/lib/factory_bot/sequence.rb index 6b50f9b..26a39d9 100644 --- a/lib/factory_bot/sequence.rb +++ b/lib/factory_bot/sequence.rb @@ -35,6 +35,10 @@ module FactoryBot [@name] + @aliases end + def rewind + @value.rewind + end + private def value @@ -47,6 +51,7 @@ module FactoryBot class EnumeratorAdapter def initialize(value) + @first_value = value @value = value end @@ -57,6 +62,10 @@ module FactoryBot def next @value = @value.next end + + def rewind + @value = @first_value + end end end end diff --git a/spec/acceptance/sequence_resetting_spec.rb b/spec/acceptance/sequence_resetting_spec.rb new file mode 100644 index 0000000..6e01a32 --- /dev/null +++ b/spec/acceptance/sequence_resetting_spec.rb @@ -0,0 +1,25 @@ +require "spec_helper" + +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 "somebody1@example.com" + expect(name).to eq "Joe" + end +end diff --git a/spec/factory_bot/sequence_spec.rb b/spec/factory_bot/sequence_spec.rb index 9af34c3..c6d83d9 100644 --- a/spec/factory_bot/sequence_spec.rb +++ b/spec/factory_bot/sequence_spec.rb @@ -1,4 +1,25 @@ -require 'spec_helper' +require "spec_helper" + +shared_examples "a sequence" do |options| + first_value = options[:first_value] + second_value = options[:second_value] + + its(:next) { should eq first_value } + + context "when incrementing" do + before { subject.next } + its(:next) { should eq second_value } + end + + context "after rewinding" do + before do + subject.next + subject.rewind + end + + its(:next) { should eq first_value } + end +end describe FactoryBot::Sequence do describe "a basic sequence" do @@ -7,88 +28,90 @@ describe FactoryBot::Sequence do its(:name) { should eq name } its(:names) { should eq [name] } - its(:next) { should eq "=1" } - describe "when incrementing" do - before { subject.next } - its(:next) { should eq "=2" } - end + it_behaves_like "a sequence", first_value: "=1", second_value: "=2" end describe "a custom sequence" do - subject { FactoryBot::Sequence.new(:name, "A") { |n| "=#{n}" } } - its(:next) { should eq "=A" } + subject { FactoryBot::Sequence.new(:name, "A") { |n| "=#{n}" } } - describe "when incrementing" do - before { subject.next } - its(:next) { should eq "=B" } - end + it_behaves_like "a sequence", first_value: "=A", second_value: "=B" end describe "a sequence with aliases using default value" do - subject { FactoryBot::Sequence.new(:test, aliases: [:alias, :other]) { |n| "=#{n}" } } - its(:next) { should eq "=1" } + subject do + FactoryBot::Sequence.new(:test, aliases: [:alias, :other]) do |n| + "=#{n}" + end + end + its(:names) { should eq [:test, :alias, :other] } - describe "when incrementing" do - before { subject.next } - its(:next) { should eq "=2" } - end + it_behaves_like "a sequence", first_value: "=1", second_value: "=2" end describe "a sequence with custom value and aliases" do - subject { FactoryBot::Sequence.new(:test, 3, aliases: [:alias, :other]) { |n| "=#{n}" } } - its(:next) { should eq "=3" } - - describe "when incrementing" do - before { subject.next } - its(:next) { should eq "=4" } + subject do + FactoryBot::Sequence.new(:test, 3, aliases: [:alias, :other]) do |n| + "=#{n}" + end end + + its(:names) { should eq [:test, :alias, :other] } + + it_behaves_like "a sequence", first_value: "=3", second_value: "=4" end describe "a basic sequence without a block" do - subject { FactoryBot::Sequence.new(:name) } - its(:next) { should eq 1 } + subject { FactoryBot::Sequence.new(:name) } - describe "when incrementing" do - before { subject.next } - its(:next) { should eq 2 } - end + it_behaves_like "a sequence", first_value: 1, second_value: 2 end describe "a custom sequence without a block" do - subject { FactoryBot::Sequence.new(:name, "A") } - its(:next) { should eq "A" } + subject { FactoryBot::Sequence.new(:name, "A") } - describe "when incrementing" do - before { subject.next } - its(:next) { should eq "B" } - end + it_behaves_like "a sequence", first_value: "A", second_value: "B" end describe "iterating over items in an enumerator" do - subject { FactoryBot::Sequence.new(:name, %w[foo bar].to_enum) { |n| "=#{n}" } } + subject do + FactoryBot::Sequence.new(:name, %w[foo bar].to_enum) { |n| "=#{n}" } + end it "navigates to the next items until no items remain" do expect(subject.next).to eq "=foo" expect(subject.next).to eq "=bar" expect { subject.next }.to raise_error(StopIteration) end + + it_behaves_like "a sequence", first_value: "=foo", second_value: "=bar" end describe "a custom sequence and scope" do - subject { FactoryBot::Sequence.new(:name, 'A') { |n| "=#{n}#{foo}" } } + subject { FactoryBot::Sequence.new(:name, "A") { |n| "=#{n}#{foo}" } } let(:scope) { double("scope", foo: "attribute") } - it 'increments within the correct scope' do - expect(subject.next(scope)).to eq '=Aattribute' + it "increments within the correct scope" do + expect(subject.next(scope)).to eq "=Aattribute" end - describe 'when incrementing' do + context "when incrementing" do before { subject.next(scope) } - it 'increments within the correct scope' do - expect(subject.next(scope)).to eq '=Battribute' + it "increments within the correct scope" do + expect(subject.next(scope)).to eq "=Battribute" + end + end + + context "after rewinding" do + before do + subject.next(scope) + subject.rewind + end + + it "increments within the correct scope" do + expect(subject.next(scope)).to eq "=Aattribute" end end end