item_spec.rb 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe Checklist::Item, :aggregate_failures, current_user_id: 1, type: :model do
  4. let(:ticket) { create(:ticket) }
  5. let(:checklist) { create(:checklist, item_count: 0, ticket:) }
  6. describe '#validate_item_count' do
  7. let(:checklist_full) { create(:checklist, item_count: 100) }
  8. it 'does not allow more than 100 items' do
  9. next_item = build(:checklist_item, checklist: checklist_full)
  10. next_item.valid?
  11. expect(next_item.errors.full_messages)
  12. .to include('Checklist items are limited to 100 items per checklist.')
  13. end
  14. it 'does not run a check when cloning' do
  15. next_item = build(:checklist_item, checklist: checklist_full, initial_clone: true)
  16. next_item.valid?
  17. expect(next_item.errors).to be_blank
  18. end
  19. end
  20. describe '#detect_ticket_loop_reference' do
  21. it 'passes when another ticket is referenced' do
  22. item = create(:checklist_item, checklist:, ticket: create(:ticket))
  23. expect(item).to be_persisted
  24. end
  25. it 'fails when parent ticket is referenced' do
  26. item = build(:checklist_item, checklist:, ticket:).tap(&:save)
  27. expect(item.errors.messages_for(:ticket)).to include('reference must not be the checklist ticket.')
  28. end
  29. end
  30. describe '#detect_ticket_reference' do
  31. let(:target_ticket) { create(:ticket) }
  32. let(:number) do
  33. ticket_hook = Setting.get('ticket_hook')
  34. ticket_hook_divider = Setting.get('ticket_hook_divider')
  35. "#{ticket_hook}#{ticket_hook_divider}#{target_ticket.number}"
  36. end
  37. it 'detects given ticket' do
  38. item = create(:checklist_item, checklist:, text: number)
  39. expect(item.ticket).to eq target_ticket
  40. end
  41. it 'skips detecting when using a template' do
  42. item = create(:checklist_item, checklist:, text: number, initial_clone: true)
  43. expect(item.ticket).to be_nil
  44. end
  45. it 'fails gracefully when non-existant number-like text is given' do
  46. item = create(:checklist_item, checklist:, text: "#{number}1")
  47. expect(item.ticket).to be_nil
  48. end
  49. end
  50. describe '#detect_ticket_reference_state' do
  51. let(:target_ticket) { create(:ticket) }
  52. it 'does not set ticket state if no ticket given' do
  53. target_ticket
  54. checklist
  55. allow(Checklist).to receive(:ticket_closed?)
  56. create(:checklist_item, checklist:)
  57. expect(Checklist).not_to have_received(:ticket_closed?)
  58. end
  59. it 'sets ticket state when setting a ticket' do
  60. allow(Checklist).to receive(:ticket_closed?)
  61. allow(Checklist).to receive(:ticket_closed?).with(target_ticket).and_return(true)
  62. item = create(:checklist_item, checklist:, ticket: target_ticket)
  63. expect(item).to be_checked
  64. end
  65. it 'does not set ticket state when setting another attribute' do
  66. item = create(:checklist_item, checklist:, ticket: target_ticket)
  67. allow(Checklist).to receive(:ticket_closed?)
  68. item.update!(text: 'another')
  69. expect(Checklist).not_to have_received(:ticket_closed?)
  70. end
  71. end
  72. describe '#update_checklist_on_destroy' do
  73. let(:item) { create(:checklist_item, checklist:) }
  74. before { item }
  75. it 'removes item from checklist sorted_item_ids when destroying' do
  76. expect { item.destroy! }
  77. .to change { checklist.reload.sorted_item_ids }
  78. .to be_blank
  79. end
  80. it 'works fine when parent checklist is destroyed' do
  81. expect { item.checklist.destroy! }.not_to raise_error
  82. end
  83. end
  84. describe '#update_checklist_on_save' do
  85. it 'adds the item to checklist sorted_item_ids' do
  86. item = create(:checklist_item, checklist:)
  87. expect(checklist.sorted_item_ids).to include(item.id.to_s)
  88. end
  89. it 'touches checklist when updating the item' do
  90. item = create(:checklist_item, checklist:)
  91. travel 10.minutes
  92. expect { item.update! checked: true }
  93. .to change { item.checklist.updated_at }
  94. end
  95. end
  96. describe '#update_referenced_ticket' do
  97. it 'touches referenced ticket' do
  98. target_ticket = create(:ticket)
  99. travel 10.minutes
  100. expect { create(:checklist_item, checklist:, ticket: target_ticket) }
  101. .to change { target_ticket.reload.updated_at }
  102. end
  103. it 'touches referenced ticket on destroying' do
  104. target_ticket = create(:ticket)
  105. item = create(:checklist_item, checklist:, ticket: target_ticket)
  106. travel 10.minutes
  107. expect { item.destroy! }
  108. .to change { target_ticket.reload.updated_at }
  109. end
  110. end
  111. describe '.incomplete' do
  112. it 'returns unchecked items' do
  113. unchecked = create(:checklist_item, checked: false, checklist:)
  114. create(:checklist_item, checked: true, checklist:)
  115. expect(described_class.incomplete).to contain_exactly(unchecked)
  116. end
  117. end
  118. describe 'history entries for checked' do
  119. let(:checklist) do
  120. create(:checklist, item_count: 1)
  121. end
  122. it 'creates history entries for checked' do
  123. checklist.items.first.update!(checked: true)
  124. history_type_id = History::Type.find_by(name: 'checklist_item_checked').id
  125. expect(History.last).to have_attributes(
  126. history_type_id: history_type_id,
  127. value_from: checklist.items.first.text,
  128. value_to: 'true',
  129. )
  130. checklist.items.first.update!(checked: false)
  131. expect(History.last).to have_attributes(
  132. history_type_id: history_type_id,
  133. value_from: checklist.items.first.text,
  134. value_to: 'false',
  135. )
  136. end
  137. end
  138. end