# frozen_string_literal: true require 'spec_helper' RSpec.describe Spree::Zone do describe "validations" do it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_uniqueness_of(:name) } it { is_expected.to validate_presence_of(:zone_members) } end describe "#match" do let(:country_zone) { create(:zone, name: 'CountryZone') } let(:country) do country = create(:country) # Create at least one state for this country state = create(:state, country:) country end before { country_zone.members.create(zoneable: country) } context "when there is only one qualifying zone" do let(:address) { create(:address, country:, state: country.states.first) } it "should return the qualifying zone" do expect(Spree::Zone.match(address)).to eq country_zone end end context "when there are two qualified zones with same member type" do let(:address) { create(:address, country:, state: country.states.first) } let(:second_zone) { create(:zone, name: 'SecondZone') } before { second_zone.members.create(zoneable: country) } context "when both zones have the same number of members" do it "should return the zone that was created first" do expect(Spree::Zone.match(address)).to eq country_zone end end context "when one of the zones has fewer members" do let(:country2) { create(:country) } before { country_zone.members.create(zoneable: country2) } it "should return the zone with fewer members" do expect(Spree::Zone.match(address)).to eq second_zone end end end context "when there are two qualified zones with different member types" do let(:state_zone) { create(:zone, name: 'StateZone') } let(:address) { create(:address, country:, state: country.states.first) } before { state_zone.members.create(zoneable: country.states.first) } it "should return the zone with the more specific member type" do expect(Spree::Zone.match(address)).to eq state_zone end end context "when there are no qualifying zones" do it "should return nil" do expect(Spree::Zone.match(Spree::Address.new)).to be_nil end end end describe "#countries" do let(:state) { create(:state) } let(:country) { state.country } context "when zone consists of countries" do let(:country_zone) { create(:zone, name: 'CountryZone', member: country) } it 'should return a list of countries' do expect(country_zone.countries).to eq [country] end end context "when zone consists of states" do let(:state_zone) { create(:zone, name: 'StateZone', member: state) } it 'should return a list of countries' do expect(state_zone.countries).to eq [country] end end end describe "#contains_address?" do let(:state) { create(:state) } let(:country) { state.country } let(:address) { create(:address, country:, state:) } context "when zone is country type" do let(:country_zone) { create(:zone, name: 'CountryZone') } before { country_zone.members.create(zoneable: country) } it "should be true" do expect(country_zone.contains_address?(address)).to be_truthy end end context "when zone is state type" do let(:state_zone) { create(:zone, name: 'StateZone') } before { state_zone.members.create(zoneable: state) } it "should be true" do expect(state_zone.contains_address?(address)).to be_truthy end end end describe ".default_tax" do context "when there is a default tax zone specified" do let!(:default_zone) { create(:zone, name: 'whatever', default_tax: true) } it "should be the correct zone" do create(:zone, name: 'foo', default_tax: false) expect(Spree::Zone.default_tax).to eq default_zone end end context "when there is no default tax zone specified" do it "should be nil" do expect(Spree::Zone.default_tax).to be_nil end end end describe "#contains?" do let(:country_member1) { Spree::ZoneMember.create(zoneable: create(:country)) } let(:country_member2) { Spree::ZoneMember.create(zoneable: create(:country)) } let(:country_member3) { Spree::ZoneMember.create(zoneable: create(:country)) } let(:source) { create(:zone, name: 'source') } let(:target) { create(:zone, name: 'target') } context "when both zones are the same zone" do before do source.zone_members = [country_member1] end it "should be true" do target = source expect(source.contains?(target)).to be_truthy end end context "when both zones are of the same type" do before do source.zone_members = [country_member1, country_member2] end context "when all members are included in the zone we check against" do before do target.zone_members = [country_member1, country_member2] end it "should be true" do expect(source.contains?(target)).to be_truthy end end context "when some members are included in the zone we check against" do before do target.zone_members = [ country_member1, country_member2, Spree::ZoneMember.create(zoneable: create(:country)) ] end it "should be false" do expect(source.contains?(target)).to be_falsy end end context "when none of the members are included in the zone we check against" do before do target.zone_members = [ Spree::ZoneMember.create(zoneable: create(:country)), Spree::ZoneMember.create(zoneable: create(:country)) ] end it "should be false" do expect(source.contains?(target)).to be_falsy end end end context "when checking country against state" do before do source.zone_members = [Spree::ZoneMember.create(zoneable: create(:state))] target.zone_members = [country_member1] end it "should be false" do expect(source.contains?(target)).to be_falsy end end context "when checking state against country" do before { source.zone_members = [country_member1] } context "when all states contained in one of the countries we check against" do before do state1 = create(:state, country: country_member1.zoneable) target.zone_members = [Spree::ZoneMember.create(zoneable: state1)] end it "should be true" do expect(source.contains?(target)).to be_truthy end end context "when some states contained in one of the countries we check against" do before do state1 = create(:state, country: country_member1.zoneable) state2 = create(:state, country: country_member2.zoneable) target.zone_members = [ Spree::ZoneMember.create(zoneable: state1), Spree::ZoneMember.create(zoneable: state2) ] end it "should be false" do expect(source.contains?(target)).to be_falsy end end context "when none of the states contained in any of the countries we check against" do before do target.zone_members = [ Spree::ZoneMember.create(zoneable: create(:state, country: country_member2.zoneable)), Spree::ZoneMember.create(zoneable: create(:state, country: country_member2.zoneable)) ] end it "should be false" do expect(source.contains?(target)).to be_falsy end end end end describe "#save" do context "when default_tax is true" do it "should clear previous default tax zone" do zone1 = create(:zone, name: 'foo', default_tax: true) zone = create(:zone, name: 'bar', default_tax: true) expect(zone1.reload.default_tax).to be_falsy end end context "when a zone member country is added to an existing zone consisting of state members" do it "should remove existing state members" do state = create(:state) zone = create(:zone, name: 'foo', member: state) country = create(:country) country_member = zone.members.create(zoneable: country) zone.save expect(zone.reload.members).to eq [country_member] end end end describe "#kind" do context "when the zone consists of country zone members" do let!(:zone) { create(:zone, name: 'country', member: create(:country)) } it "should return the kind of zone member" do expect(zone.kind).to eq "country" end end context "when the zone consists of state zone members" do let!(:zone) { create(:zone, name: 'country', member: create(:state)) } it "should return the kind of zone member" do expect(zone.kind).to eq "state" end end end end