123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- require 'rails_helper'
- require 'models/application_model_examples'
- require 'models/concerns/can_be_imported_examples'
- require 'models/concerns/has_collection_update_examples'
- require 'models/concerns/has_xss_sanitized_note_examples'
- RSpec.describe Ticket::State, type: :model do
- it_behaves_like 'ApplicationModel'
- it_behaves_like 'CanBeImported'
- it_behaves_like 'HasCollectionUpdate', collection_factory: :ticket_state
- it_behaves_like 'HasXssSanitizedNote', model_factory: :ticket_state
- describe 'Default state' do
- describe 'of whole table:' do
- it 'has default records' do
- expect(described_class.pluck(:name))
- .to contain_exactly('closed', 'merged', 'new', 'open', 'pending close', 'pending reminder')
- end
- end
- describe 'of "new" state:' do
- it 'is the sole #default_create state' do
- expect(described_class.where(default_create: true))
- .to contain_exactly(described_class.find_by(name: 'new'))
- end
- end
- describe 'of "open" state:' do
- it 'is the sole #default_follow_up state' do
- expect(described_class.where(default_follow_up: true))
- .to contain_exactly(described_class.find_by(name: 'open'))
- end
- end
- end
- describe 'Class methods:' do
- describe '.by_category' do
- it 'looks up states by category' do
- expect(described_class.by_category(:open))
- .to be_an(ActiveRecord::Relation)
- .and include(instance_of(described_class))
- end
- context 'with invalid category name' do
- it 'raises ArgumentError' do
- expect { described_class.by_category(:invalidcategoryname) }
- .to raise_error(ArgumentError)
- end
- end
- end
- end
- describe 'Attributes:' do
- describe '#default_create' do
- let!(:original_default) { described_class.find_by(default_create: true) }
- context 'for newly created record' do
- subject!(:state) { build(:ticket_state, default_create: default_create) }
- context 'when true' do
- let(:default_create) { true }
- it 'unsets previous default' do
- expect { state.save }
- .to change { original_default.reload.default_create }.to(false)
- .and not_change { described_class.where(default_create: true).count }
- end
- end
- context 'when false' do
- let(:default_create) { false }
- it 'does not alter existing default' do
- expect { state.save }
- .to not_change { described_class.find_by(default_create: true) }
- .and not_change { described_class.where(default_create: true).count }
- end
- end
- end
- context 'for existing record' do
- subject!(:state) { create(:ticket_state, default_create: default_create) }
- context 'when true' do
- let(:default_create) { true }
- context 'and updated to false' do
- it 'assigns Ticket::State.first as default' do
- expect { state.update(default_create: false) }
- .to change { described_class.first.default_create }.to(true)
- .and not_change { described_class.where(default_create: true).count }
- end
- end
- context 'and destroyed' do
- it 'assigns Ticket::State.first as default' do
- expect { state.destroy }
- .to change { described_class.first.default_create }.to(true)
- .and not_change { described_class.where(default_create: true).count }
- end
- end
- end
- context 'when false' do
- let(:default_create) { false }
- context 'and updated to true' do
- it 'unsets previous default' do
- expect { state.update(default_create: true) }
- .to change { original_default.reload.default_create }.to(false)
- .and not_change { described_class.where(default_create: true).count }
- end
- end
- context 'and destroyed' do
- it 'does not alter existing default' do
- expect { state.destroy }
- .to not_change { described_class.find_by(default_create: true) }
- .and not_change { described_class.where(default_create: true).count }
- end
- end
- end
- end
- end
- describe '#default_follow_up' do
- let!(:original_default) { described_class.find_by(default_follow_up: true) }
- context 'for newly created record' do
- subject!(:state) { build(:ticket_state, default_follow_up: default_follow_up) }
- context 'when true' do
- let(:default_follow_up) { true }
- it 'unsets previous default' do
- expect { state.save }
- .to change { original_default.reload.default_follow_up }.to(false)
- .and not_change { described_class.where(default_follow_up: true).count }
- end
- end
- context 'when false' do
- let(:default_follow_up) { false }
- it 'does not alter existing default' do
- expect { state.save }
- .to not_change { described_class.find_by(default_follow_up: true) }
- .and not_change { described_class.where(default_follow_up: true).count }
- end
- end
- end
- context 'for existing record' do
- subject!(:state) { create(:ticket_state, default_follow_up: default_follow_up) }
- context 'when true' do
- let(:default_follow_up) { true }
- context 'and updated to false' do
- it 'assigns Ticket::State.first as default' do
- expect { state.update(default_follow_up: false) }
- .to change { described_class.first.default_follow_up }.to(true)
- .and not_change { described_class.where(default_follow_up: true).count }
- end
- end
- context 'and destroyed' do
- it 'assigns Ticket::State.first as default' do
- expect { state.destroy }
- .to change { described_class.first.default_follow_up }.to(true)
- .and not_change { described_class.where(default_follow_up: true).count }
- end
- end
- end
- context 'when false' do
- let(:default_follow_up) { false }
- context 'and updated to true' do
- it 'unsets previous default' do
- expect { state.update(default_follow_up: true) }
- .to change { original_default.reload.default_follow_up }.to(false)
- .and not_change { described_class.where(default_follow_up: true).count }
- end
- end
- context 'and destroyed' do
- it 'does not alter existing default' do
- expect { state.destroy }
- .to not_change { described_class.find_by(default_follow_up: true) }
- .and not_change { described_class.where(default_follow_up: true).count }
- end
- end
- end
- end
- end
- end
- describe 'Callbacks' do
- let(:attr) { ObjectManager::Attribute.get(object: 'Ticket', name: 'state_id') }
- before { Setting.set('system_init_done', true) }
- it 'updates state_id attribute when a new state is added' do
- new_state = create(:ticket_state, state_type: Ticket::StateType.lookup(name: 'open'))
- expect(attr.screens)
- .to include(
- 'create_middle' => include(
- 'ticket.agent' => include('filter' => include(new_state.id)),
- 'ticket.customer' => include('filter' => not_include(new_state.id))
- ),
- 'edit' => include(
- 'ticket.agent' => include('filter' => include(new_state.id)),
- 'ticket.customer' => include('filter' => include(new_state.id))
- )
- )
- end
- context 'with an existing state' do
- let(:state) { create(:ticket_state, state_type: Ticket::StateType.lookup(name: 'new')) }
- it 'updates state_id attribute when a state is modified' do
- state.update! state_type: Ticket::StateType.lookup(name: 'open')
- expect(attr.screens)
- .to include(
- 'create_middle' => include(
- 'ticket.agent' => include('filter' => include(state.id)),
- 'ticket.customer' => include('filter' => not_include(state.id))
- ),
- 'edit' => include(
- 'ticket.agent' => include('filter' => include(state.id)),
- 'ticket.customer' => include('filter' => include(state.id))
- )
- )
- end
- it 'updates state_id attribute when a state is destroyed' do
- state.destroy!
- expect(attr.screens)
- .to include(
- 'create_middle' => include(
- 'ticket.agent' => include('filter' => not_include(state.id)),
- 'ticket.customer' => include('filter' => not_include(state.id))
- ),
- 'edit' => include(
- 'ticket.agent' => include('filter' => not_include(state.id)),
- 'ticket.customer' => include('filter' => not_include(state.id))
- )
- )
- end
- end
- end
- end
|