# frozen_string_literal: true require 'spec_helper' RSpec.describe Spree::User do describe "associations" do it { is_expected.to have_many(:owned_enterprises) } it { is_expected.to have_many(:webhook_endpoints).dependent(:destroy) } describe "addresses" do let(:user) { create(:user, bill_address: create(:address)) } context "updating addresses via nested attributes" do it 'updates billing address with new address' do old_bill_address = user.bill_address new_bill_address = create(:address, firstname: 'abc') user.update( bill_address_attributes: new_bill_address.dup.attributes.merge( 'id' => old_bill_address.id ) .except!('created_at', 'updated_at') ) expect(user.bill_address.id).to eq old_bill_address.id expect(user.bill_address.firstname).to eq new_bill_address.firstname end it 'creates new shipping address' do new_ship_address = create(:address, firstname: 'abc') user.update(ship_address_attributes: new_ship_address.dup.attributes.except!( 'created_at', 'updated_at' )) expect(user.ship_address.id).not_to eq new_ship_address.id expect(user.ship_address.firstname).to eq new_ship_address.firstname end end end describe "enterprise ownership" do let(:u1) { create(:user, enterprise_limit: 2) } let(:u2) { create(:user, enterprise_limit: 1) } let!(:e1) { create(:enterprise, owner: u1) } let!(:e2) { create(:enterprise, owner: u1) } it "provides access to owned enterprises" do expect(u1.owned_enterprises.reload).to include e1, e2 end it "enforces the limit on the number of enterprise owned" do expect(u2.owned_enterprises.reload).to eq [] u2.owned_enterprises << e1 expect { u2.save! }.not_to raise_error expect do u2.owned_enterprises << e2 u2.save! end.to raise_error ActiveRecord::RecordInvalid, "Validation failed: #{u2.email} is not permitted " \ "to own any more enterprises (limit is 1)." end end describe "group ownership" do let(:u1) { create(:user) } let(:u2) { create(:user) } let!(:g1) { create(:enterprise_group, owner: u1) } let!(:g2) { create(:enterprise_group, owner: u1) } let!(:g3) { create(:enterprise_group, owner: u2) } it "provides access to owned groups" do expect(u1.owned_groups.reload).to match_array([g1, g2]) expect(u2.owned_groups.reload).to match_array([g3]) end end it "loads a user's customer representation at a particular enterprise" do u = create(:user) e = create(:enterprise) c = create(:customer, user: u, enterprise: e) expect(u.customer_of(e)).to eq(c) end end describe "validations" do subject(:user) { build(:user) } it { is_expected.to validate_presence_of(:email) } it { is_expected.to validate_uniqueness_of(:email).case_insensitive } it "detects emails without @" do user.email = "examplemail.com" expect(user).not_to be_valid expect(user.errors.messages[:email]).to include "is invalid" end it "detects backslashes at the end" do user.email = "example@gmail.com\\\\" expect(user).not_to be_valid end it "is okay with numbers before the @" do user.email = "example.42@posteo.de" expect(user).to be_valid end it "detects typos in the domain" do # We mock this validation in all other tests because our test data is not # valid, the network requests slow down tests and could make them flaky. expect_any_instance_of(ValidEmail2::Address).to receive(:valid_mx?).and_call_original user.email = "example@ho020tmail.com" expect(user).not_to be_valid end end context "#create" do it "should send a confirmation email" do expect do create(:user, email: 'new_user@example.com', confirmation_sent_at: nil, confirmed_at: nil) end.to enqueue_job ActionMailer::MailDeliveryJob expect(enqueued_jobs.last.to_s).to match "confirmation_instructions" end context "with the the same email as existing customers" do let(:email) { generate(:random_email) } let(:enterprise1) { create(:enterprise) } let(:enterprise2) { create(:enterprise) } let!(:customer1) { create(:customer, user: nil, email:, enterprise: enterprise1) } let!(:customer2) { create(:customer, user: nil, email:, enterprise: enterprise2) } let!(:order) { create(:order, customer: customer1) } let!(:user) { create(:user, email:) } it "should associate these customers with the created user" do expect(user.customers.reload).to include customer1, customer2 expect(user.customer_of(enterprise1)).to be_truthy expect(user.customer_of(enterprise2)).to be_truthy end it "should associate the orders passed by customer linked to the created user" do expect(user.orders.reload).to include order end end end context "confirming email" do it "should send a welcome email" do expect do create(:user, confirmed_at: nil).confirm end.to enqueue_job ActionMailer::MailDeliveryJob expect(enqueued_jobs.last.to_s).to match "signup_confirmation" end end describe "known_users" do let!(:u1) { create(:user) } let!(:u2) { create(:user) } let!(:u3) { create(:user) } let!(:e1) { create(:enterprise, owner: u1, users: [u1, u2]) } describe "as an enterprise user" do it "returns a list of users which manage shared enterprises" do expect(u1.known_users).to include u1, u2 expect(u1.known_users).not_to include u3 expect(u2.known_users).to include u1, u2 expect(u2.known_users).not_to include u3 expect(u3.known_users).not_to include u1, u2, u3 end end describe "as admin" do let(:admin) { create(:admin_user) } it "returns all users" do expect(admin.known_users).to include u1, u2, u3 end end end describe "default_card" do let(:user) { create(:user) } context "when the user has no credit cards" do it "returns nil" do expect(user.default_card).to be nil end end context "when the user has one credit card" do let!(:card) { create(:stored_credit_card, user:) } it "should be assigned as the default and be returned" do expect(card.reload.is_default).to be true expect(user.default_card.id).to be card.id end end context "when the user has more than one card" do let!(:non_default_card) { create(:stored_credit_card, user:) } let!(:default_card) { create(:stored_credit_card, user:, is_default: true) } it "returns the card which is specified as the default" do expect(user.default_card.id).to be default_card.id end end end describe '#admin?' do it 'returns true when the user has an admin role' do expect(create(:admin_user).admin?).to be_truthy end it 'returns false when the user does not have an admin role' do expect(create(:user).admin?).to eq(false) end end context '#destroy' do it 'can not delete if it has completed orders' do order = build(:order, completed_at: Time.zone.now) order.save user = order.user expect { user.destroy }.to raise_exception(Spree::User::DestroyWithOrdersError) end end describe "#flipper_id" do it "provides a unique id" do user = Spree::User.new(id: 42) expect(user.flipper_id).to eq "Spree::User;42" end end describe "#disabled=" do context 'when the value is truthy' do it "sets disabled datetime" do user = Spree::User.new expect(user.disabled_at).to be_nil user.disabled = '1' expect(user.disabled_at).not_to be_nil end end context 'when the value is falsey' do it "clears disabled datetime" do user = Spree::User.new(disabled_at: Time.zone.now) expect(user.disabled_at).not_to be_nil user.disabled = '0' expect(user.disabled_at).to be_nil end end end describe "#disabled" do it "returns true with a disabled datetime" do user = Spree::User.new user.disabled = '1' expect(user.disabled).to be_truthy end it "returns false without a disabled datetime" do user = Spree::User.new(disabled_at: Time.zone.now) user.disabled = '0' expect(user.disabled).to be_falsey end end describe "#affiliate_enterprises" do let(:user) { create(:user) } let(:affiliate_enterprise) { create(:enterprise) } let(:other_connected_enterprise) { create(:enterprise) } let(:other_enterprise) { create(:enterprise) } subject{ user.affiliate_enterprises } before do ConnectedApps::AffiliateSalesData.create(enterprise: affiliate_enterprise, data: true) ConnectedApp.create(enterprise: other_connected_enterprise, data: true) end context "user does not have feature" do it { is_expected.to be_empty } end context "user has feature affiliate_sales_data" do before do Flipper.enable_actor(:affiliate_sales_data, user) user.reload end it "includes only affiliate enterprises" do is_expected.to include affiliate_enterprise is_expected.not_to include other_connected_enterprise is_expected.not_to include other_enterprise end end end describe "#can_manage_line_items_in_orders_only?" do let(:producer) { create(:supplier_enterprise) } let(:order) { create(:order, distributor:) } subject { user.can_manage_line_items_in_orders_only? } context "when user has producer" do let(:user) { create(:user, enterprises: [producer]) } context "order containing their product" do before do order.line_items << create(:line_item, product: create(:product, supplier_id: producer.id)) end context "order distributor allow producer to edit orders" do let(:distributor) do create(:distributor_enterprise, enable_producers_to_edit_orders: true) end it { is_expected.to be_truthy } end context "order distributor doesn't allow producer to edit orders" do let(:distributor) { create(:distributor_enterprise) } it { is_expected.to be_falsey } end end end context "no order containing their product" do let(:user) { create(:user, enterprises: [create(:distributor_enterprise)]) } it { is_expected.to be_falsey } end end end