gitlab-ce/spec/models/work_items/widgets/hierarchy_spec.rb

208 lines
7.5 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe WorkItems::Widgets::Hierarchy, feature_category: :team_planning do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:task) { create(:work_item, :task, project: project) }
let_it_be_with_reload(:work_item_parent) { create(:work_item, project: project) }
describe '.type' do
subject { described_class.type }
it { is_expected.to eq(:hierarchy) }
end
describe '#type' do
subject { described_class.new(task).type }
it { is_expected.to eq(:hierarchy) }
end
describe '#parent' do
let_it_be_with_reload(:parent_link) { create(:parent_link, work_item: task, work_item_parent: work_item_parent) }
subject { described_class.new(parent_link.work_item).parent }
it { is_expected.to eq(parent_link.work_item_parent) }
end
describe '#has_parent?' do
subject { described_class.new(task.reload).has_parent? }
context 'when parent is present' do
specify do
create(:parent_link, work_item: task, work_item_parent: work_item_parent)
is_expected.to eq(true)
end
end
context 'when parent is not present' do
it { is_expected.to eq(false) }
end
end
describe '#children' do
let_it_be_with_reload(:parent_link1) { create(:parent_link, work_item_parent: work_item_parent, work_item: task) }
let_it_be_with_reload(:parent_link2) { create(:parent_link, work_item_parent: work_item_parent) }
subject { described_class.new(work_item_parent).children }
it { is_expected.to contain_exactly(parent_link1.work_item, parent_link2.work_item) }
context 'when ordered by relative position and work_item_id' do
let_it_be(:oldest_child) { create(:work_item, :task, project: project) }
let_it_be(:newest_child) { create(:work_item, :task, project: project) }
let_it_be_with_reload(:link_to_oldest_child) do
create(:parent_link, work_item_parent: work_item_parent, work_item: oldest_child)
end
let_it_be_with_reload(:link_to_newest_child) do
create(:parent_link, work_item_parent: work_item_parent, work_item: newest_child)
end
let(:parent_links_ordered) { [parent_link1, parent_link2, link_to_oldest_child, link_to_newest_child] }
context 'when children relative positions are nil' do
it 'orders by work_item_id' do
is_expected.to eq(parent_links_ordered.map(&:work_item))
end
end
context 'when children relative positions are present' do
let(:first_position) { 10 }
let(:second_position) { 20 }
let(:parent_links_ordered) { [link_to_oldest_child, link_to_newest_child, parent_link1, parent_link2] }
before do
link_to_oldest_child.update!(relative_position: first_position)
link_to_newest_child.update!(relative_position: second_position)
end
it 'orders by relative_position and by created_at' do
is_expected.to eq(parent_links_ordered.map(&:work_item))
end
end
context 'when filtered by state' do
let_it_be(:open_child) { create(:work_item, :task, state: :opened, project: project) }
let_it_be(:closed_child) { create(:work_item, :task, state: :closed, project: project) }
let_it_be_with_reload(:link_to_open_child) do
create(:parent_link, work_item_parent: work_item_parent, work_item: open_child)
end
let_it_be_with_reload(:link_to_closed_child) do
create(:parent_link, work_item_parent: work_item_parent, work_item: closed_child)
end
it 'returns only opened items' do
result = described_class.new(work_item_parent).children(state: :opened)
expect(result).to include(open_child)
expect(result).not_to include(closed_child)
end
it 'returns only closed items' do
result = described_class.new(work_item_parent).children(state: :closed)
expect(result).to include(closed_child)
expect(result).not_to include(open_child)
end
it 'returns all items' do
result = described_class.new(work_item_parent).children
expect(result).to include(
open_child,
closed_child
)
end
end
end
end
describe '#rolled_up_counts_by_type' do
let_it_be(:work_item) { create(:work_item, :epic, namespace: group) }
let_it_be(:sub_epic) { create(:work_item, :epic, :closed, namespace: group) }
let_it_be(:sub_sub_epic) { create(:work_item, :epic, namespace: group) }
let_it_be(:sub_epic_2) { create(:work_item, :epic, namespace: group) }
let_it_be(:sub_issue) { create(:work_item, :issue, :closed, project: project) }
let_it_be(:sub_issue_2) { create(:work_item, :issue, project: project) }
let_it_be(:sub_task) { create(:work_item, :task, project: project) }
subject { described_class.new(work_item).rolled_up_counts_by_type }
before_all do
create(:parent_link, work_item_parent: work_item, work_item: sub_epic)
create(:parent_link, work_item_parent: sub_epic, work_item: sub_sub_epic)
create(:parent_link, work_item_parent: sub_epic, work_item: sub_issue)
create(:parent_link, work_item_parent: sub_issue, work_item: sub_task)
create(:parent_link, work_item_parent: work_item, work_item: sub_epic_2)
create(:parent_link, work_item_parent: sub_epic_2, work_item: sub_issue_2)
end
it 'returns rolled up dates by work item type and state' do
is_expected.to contain_exactly(
{
work_item_type: WorkItems::Type.default_by_type(:epic),
counts_by_state: { all: 3, opened: 2, closed: 1 }
},
{
work_item_type: WorkItems::Type.default_by_type(:issue),
counts_by_state: { all: 2, opened: 1, closed: 1 }
},
{
work_item_type: WorkItems::Type.default_by_type(:task),
counts_by_state: { all: 1, opened: 1, closed: 0 }
}
)
end
end
describe '#depth_limit_reached_by_type' do
let_it_be(:work_item) { create(:work_item, :epic) }
let_it_be(:hierarchy) { described_class.new(work_item) }
let_it_be(:descendant_type1) { create(:work_item_type, :epic) }
let_it_be(:descendant_type2) { create(:work_item_type, :issue) }
before do
allow(work_item.work_item_type).to receive(:descendant_types).and_return([descendant_type1, descendant_type2])
end
it 'returns an array of hashes with work_item_type and depth_limit_reached' do
allow(work_item).to receive(:max_depth_reached?).with(descendant_type1).and_return(true)
allow(work_item).to receive(:max_depth_reached?).with(descendant_type2).and_return(false)
result = hierarchy.depth_limit_reached_by_type
expect(result).to contain_exactly(
{ work_item_type: descendant_type1, depth_limit_reached: true },
{ work_item_type: descendant_type2, depth_limit_reached: false }
)
end
it 'calls max_depth_reached? for each descendant type' do
expect(work_item).to receive(:max_depth_reached?).with(descendant_type1).once
expect(work_item).to receive(:max_depth_reached?).with(descendant_type2).once
hierarchy.depth_limit_reached_by_type
end
context 'when there are no descendant types' do
before do
allow(work_item.work_item_type).to receive(:descendant_types).and_return([])
end
it 'returns an empty array' do
result = hierarchy.depth_limit_reached_by_type
expect(result).to eq([])
end
end
end
end