1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
# frozen_string_literal: true
RSpec.shared_examples 'issues move service' do |group|
shared_examples 'updating timestamps' do
it 'updates updated_at' do
expect {described_class.new(parent, user, params).execute(issue)}
.to change {issue.reload.updated_at}
end
end
context 'when moving an issue between lists' do
let(:issue) { create(:labeled_issue, project: project, labels: [bug, development]) }
let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list2.id } }
it_behaves_like 'updating timestamps'
it 'delegates the label changes to Issues::UpdateService' do
service = double(:service)
expect(Issues::UpdateService).to receive(:new).and_return(service)
expect(service).to receive(:execute).with(issue).once
described_class.new(parent, user, params).execute(issue)
end
it 'removes the label from the list it came from and adds the label of the list it goes to' do
described_class.new(parent, user, params).execute(issue)
expect(issue.reload.labels).to contain_exactly(bug, testing)
end
end
context 'when moving to closed' do
let!(:list3) { create(:list, board: board2, label: regression, position: 1) }
let(:issue) { create(:labeled_issue, project: project, labels: [bug, development, testing, regression]) }
let(:params) { { board_id: board1.id, from_list_id: list2.id, to_list_id: closed.id } }
it_behaves_like 'updating timestamps'
it 'delegates the close proceedings to Issues::CloseService' do
expect_any_instance_of(Issues::CloseService).to receive(:execute).with(issue).once
described_class.new(parent, user, params).execute(issue)
end
it 'removes all list-labels from boards and close the issue' do
described_class.new(parent, user, params).execute(issue)
issue.reload
expect(issue.labels).to contain_exactly(bug, regression)
expect(issue).to be_closed
end
end
context 'when moving to backlog' do
let(:milestone) { create(:milestone, project: project) }
let!(:backlog) { create(:backlog_list, board: board1) }
let(:issue) { create(:labeled_issue, project: project, labels: [bug, development, testing, regression], milestone: milestone) }
let(:params) { { board_id: board1.id, from_list_id: list2.id, to_list_id: backlog.id } }
it_behaves_like 'updating timestamps'
it 'keeps labels and milestone' do
described_class.new(parent, user, params).execute(issue)
issue.reload
expect(issue.labels).to contain_exactly(bug, regression)
expect(issue.milestone).to eq(milestone)
end
end
context 'when moving from closed' do
let(:issue) { create(:labeled_issue, :closed, project: project, labels: [bug]) }
let(:params) { { board_id: board1.id, from_list_id: closed.id, to_list_id: list2.id } }
it_behaves_like 'updating timestamps'
it 'delegates the re-open proceedings to Issues::ReopenService' do
expect_any_instance_of(Issues::ReopenService).to receive(:execute).with(issue).once
described_class.new(parent, user, params).execute(issue)
end
it 'adds the label of the list it goes to and reopen the issue' do
described_class.new(parent, user, params).execute(issue)
issue.reload
expect(issue.labels).to contain_exactly(bug, testing)
expect(issue).to be_opened
end
end
context 'when moving to same list' do
let(:assignee) { create(:user) }
let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list1.id } }
let(:issue1) { create(:labeled_issue, project: project, labels: [bug, development]) }
let(:issue2) { create(:labeled_issue, project: project, labels: [bug, development]) }
let(:issue) do
create(:labeled_issue, project: project, labels: [bug, development], assignees: [assignee])
end
it 'returns nil' do
expect(described_class.new(parent, user, params).execute(issue)).to be_nil
end
it 'keeps issues labels' do
described_class.new(parent, user, params).execute(issue)
expect(issue.reload.labels).to contain_exactly(bug, development)
end
it 'keeps issues assignees' do
described_class.new(parent, user, params).execute(issue)
expect(issue.reload.assignees).to contain_exactly(assignee)
end
it 'sorts issues' do
reorder_issues(params, issues: [issue, issue1, issue2])
described_class.new(parent, user, params).execute(issue)
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
end
it 'does not update updated_at' do
reorder_issues(params, issues: [issue, issue1, issue2])
updated_at = issue.updated_at
updated_at1 = issue1.updated_at
updated_at2 = issue2.updated_at
travel_to(1.minute.from_now) do
described_class.new(parent, user, params).execute(issue)
end
expect(issue.reload.updated_at.change(usec: 0)).to eq updated_at.change(usec: 0)
expect(issue1.reload.updated_at.change(usec: 0)).to eq updated_at1.change(usec: 0)
expect(issue2.reload.updated_at.change(usec: 0)).to eq updated_at2.change(usec: 0)
end
if group
context 'when on a group board' do
it 'sends the board_group_id parameter' do
params.merge!(move_after_id: issue1.id, move_before_id: issue2.id)
match_params = { move_between_ids: [issue1.id, issue2.id], board_group_id: parent.id }
expect(Issues::UpdateService).to receive(:new).with(project: issue.project, current_user: user, params: match_params).and_return(double(execute: build(:issue)))
described_class.new(parent, user, params).execute(issue)
end
end
end
def reorder_issues(params, issues: [])
issues.each do |issue|
issue.move_to_end && issue.save!
end
params.merge!(move_after_id: issues[1].id, move_before_id: issues[2].id)
end
end
end
|