OpenProject is the leading open source project management software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
openproject/spec/controllers/work_packages/moves_controller_spec.rb

552 lines
17 KiB

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2021 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See docs/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe WorkPackages::MovesController, type: :controller, with_settings: { journal_aggregation_time_minutes: 0 } do
let(:user) { FactoryBot.create(:user) }
let(:role) do
FactoryBot.create :role,
permissions: %i(move_work_packages
view_work_packages
add_work_packages
edit_work_packages
assign_versions
manage_subtasks)
end
let(:type) { FactoryBot.create :type }
let(:type_2) { FactoryBot.create :type }
let!(:status) { FactoryBot.create :default_status }
let(:target_status) { FactoryBot.create :status }
let(:priority) { FactoryBot.create :priority }
let(:target_priority) { FactoryBot.create :priority }
let(:project) do
FactoryBot.create(:project,
public: false,
types: [type, type_2])
end
let(:work_package) do
FactoryBot.create(:work_package,
project_id: project.id,
type: type,
author: user,
priority: priority)
end
let(:current_user) { FactoryBot.create(:user) }
before do
allow(User).to receive(:current).and_return current_user
end
describe 'new.html' do
become_admin
describe 'w/o a valid planning element id' do
describe 'w/o being a member or administrator' do
become_non_member
it 'renders a 404 page' do
get 'new', params: { id: '1337' }
expect(response.response_code).to be === 404
end
end
describe 'w/ the current user being a member' do
become_member_with_view_planning_element_permissions
it 'raises ActiveRecord::RecordNotFound errors' do
get 'new', params: { id: '1337' }
expect(response.response_code).to be === 404
end
end
end
describe 'w/ a valid planning element id' do
become_admin
describe 'w/o being a member or administrator' do
become_non_member
it 'renders a 403 Forbidden page' do
get 'new', params: { work_package_id: work_package.id }
expect(response.response_code).to eq(403)
end
end
describe 'w/ the current user being a member' do
become_member_with_move_work_package_permissions
before do
get 'new', params: { work_package_id: work_package.id }
end
it 'renders the new builder template' do
expect(response).to render_template('work_packages/moves/new')
end
end
end
end
describe '#create' do
let!(:source_member) { FactoryBot.create(:member, user: current_user, project: project, roles: [role]) }
let!(:target_member) { FactoryBot.create(:member, user: current_user, project: target_project, roles: [role]) }
let(:target_project) { FactoryBot.create(:project, public: false) }
let(:work_package_2) do
FactoryBot.create(:work_package,
project_id: project.id,
type: type_2,
priority: priority)
end
describe 'an issue to another project' do
context 'w/o following' do
before do
status
end
subject do
post :create,
params: {
work_package_id: work_package.id,
new_project_id: target_project.id,
type_id: '',
author_id: user.id,
assigned_to_id: '',
responsible_id: '',
status_id: '',
start_date: '',
due_date: ''
}
end
it "redirects to the project's work packages page" do
is_expected.to be_redirect
is_expected.to redirect_to(project_work_packages_path(project))
end
end
context 'with following' do
subject do
post :create,
params: {
work_package_id: work_package.id,
new_project_id: target_project.id,
new_type_id: target_project.types.first.id,
assigned_to_id: '',
responsible_id: '',
status_id: '',
start_date: '',
due_date: '',
follow: '1'
}
end
it 'redirects to the work package page' do
is_expected.to be_redirect
is_expected.to redirect_to(work_package_path(work_package))
end
end
end
describe 'bulk move' do
context 'with two work packages' do
before do
# make sure, that the types of the work-packages are available on the target-project
# (and handle it/test it, when this is not the case see #1868)
target_project.types << [work_package.type, work_package_2.type]
target_project.save
post :create,
params: {
ids: [work_package.id, work_package_2.id],
new_project_id: target_project.id
}
work_package.reload
work_package_2.reload
end
it 'project id is changed for both work packages' do
expect(work_package.project_id).to eq(target_project.id)
expect(work_package_2.project_id).to eq(target_project.id)
end
it 'changed no types' do
expect(work_package.type_id).to eq(type.id)
expect(work_package_2.type_id).to eq(type_2.id)
end
end
context 'to another type' do
before do
post :create,
params: {
ids: [work_package.id, work_package_2.id],
new_type_id: type_2.id
}
work_package.reload
work_package_2.reload
end
it "changed work packages' types" do
expect(work_package.type_id).to eq(type_2.id)
expect(work_package_2.type_id).to eq(type_2.id)
end
end
context 'with another priority' do
before do
post :create,
params: {
ids: [work_package.id, work_package_2.id],
priority_id: target_priority.id
}
work_package.reload
work_package_2.reload
end
it "changed work packages' priority" do
expect(work_package.priority_id).to eq(target_priority.id)
expect(work_package_2.priority_id).to eq(target_priority.id)
end
end
shared_examples_for 'single note for moved work package' do
it { expect(moved_work_package.journals.count).to eq(2) }
it { expect(moved_work_package.journals.max_by(&:id).notes).to eq(note) }
end
describe 'move with given note' do
let(:note) { 'Moving a work package' }
context 'w/o work package changes' do
before do
post :create,
params: {
ids: [work_package.id],
notes: note
}
end
it_behaves_like 'single note for moved work package' do
let(:moved_work_package) { work_package.reload }
end
end
context 'w/o work package changes' do
before do
post :create,
params: {
ids: [work_package.id],
notes: note,
priority_id: target_priority.id
}
end
it_behaves_like 'single note for moved work package' do
let(:moved_work_package) { work_package.reload }
end
end
end
describe '&copy' do
context 'follows to another project' do
before do
post :create,
params: {
ids: [work_package.id],
copy: '',
new_project_id: target_project.id,
new_type_id: target_project.types.first.id, # FIXME see #1868
follow: ''
}
end
it 'redirects to the work package copy' do
copy = WorkPackage.order(Arel.sql('id desc')).first
is_expected.to redirect_to(work_package_path(copy))
end
end
context "w/o changing the work package's attribute" do
before do
post :create,
params: {
ids: [work_package.id],
copy: '',
new_project_id: target_project.id
}
end
subject { WorkPackage.order(Arel.sql('id desc')).where(project_id: project.id).first }
it 'did not change the type' do
expect(subject.type_id).to eq(work_package.type_id)
end
it 'did not change the status' do
expect(subject.status_id).to eq(work_package.status_id)
end
it 'did not change the status' do
expect(subject.version_id).to eq(work_package.version_id)
end
it 'did not change the assignee' do
expect(subject.assigned_to_id).to eq(work_package.assigned_to_id)
end
it 'did not change the responsible' do
expect(subject.responsible_id).to eq(work_package.responsible_id)
end
end
context "with changing the work package's attribute" do
let(:start_date) { Date.today }
let(:due_date) { Date.today + 1 }
let(:target_version) { FactoryBot.create(:version, project: target_project) }
let(:target_user) do
user = FactoryBot.create :user
FactoryBot.create(:member,
user: user,
project: target_project,
roles: [role])
user
end
before do
post :create,
params: {
ids: [work_package.id, work_package_2.id],
copy: '',
new_project_id: target_project.id,
new_type_id: target_project.types.first.id, # FIXME see #1868
assigned_to_id: target_user.id,
responsible_id: target_user.id,
status_id: target_status,
version_id: target_version.id,
start_date: start_date,
due_date: due_date
}
end
subject { WorkPackage.limit(2).order(Arel.sql('id desc')).where(project_id: target_project.id) }
it 'copied two work packages' do
expect(subject.count).to eq(2)
end
it 'did change the project' do
subject.map(&:project_id).each do |id|
expect(id).to eq(target_project.id)
end
end
it 'did change the assignee' do
subject.map(&:assigned_to_id).each do |id|
expect(id).to eq(target_user.id)
end
end
it 'did change the responsible' do
subject.map(&:responsible_id).each do |id|
expect(id).to eq(target_user.id)
end
end
it 'did change the status' do
subject.map(&:status_id).each do |id|
expect(id).to eq(target_status.id)
end
end
it 'did change the version' do
subject.map(&:version_id).each do |id|
expect(id).to eq(target_version.id)
end
end
it 'did change the start date' do
subject.map(&:start_date).each do |date|
expect(date).to eq(start_date)
end
end
it 'did change the end date' do
subject.map(&:due_date).each do |date|
expect(date).to eq(due_date)
end
end
end
context 'with given note' do
let(:note) { 'Copying a work package' }
before do
post :create,
params: {
ids: [work_package.id],
copy: '',
notes: note
}
end
subject { WorkPackage.limit(1).order(Arel.sql('id desc')).last.journals }
it { expect(subject.count).to eq(1) }
it { expect(subject.last.notes).to eq(note) }
end
context 'parent and child work package' do
let!(:child_wp) do
FactoryBot.create(:work_package,
type: type,
project: project,
parent: work_package)
end
before do
allow(User).to receive(:current).and_return(current_user)
end
context 'on new' do
before do
get :new,
params: {
ids: [work_package.id, child_wp.id],
copy: '',
new_project_id: to_project.id
}
it 'reports the one child work package' do
expect(response.body).to have_selector "a.issue", count: 1
expect(response.body).to have_selector "contextual-info", text: '(+ One child work package)'
end
end
end
context 'on create' do
it 'only copies the parent work package' do
expect(::WorkPackages::MoveService)
.to receive(:new)
.with(work_package, current_user)
.and_call_original
expect(::WorkPackages::MoveService)
.not_to receive(:new)
.with(child_wp, current_user)
expect do
post :create,
params: {
ids: [work_package.id, child_wp.id],
copy: ''
}
end.to change(WorkPackage, :count).by(2)
expect(flash[:notice]).to eq(I18n.t(:notice_successful_create))
end
end
end
context 'child work package from one project to other' do
let(:to_project) do
FactoryBot.create(:project,
types: [type])
end
let!(:member) do
FactoryBot.create(:member,
user: current_user,
roles: [role],
project: to_project)
end
let!(:child_wp) do
FactoryBot.create(:work_package,
type: type,
project: project,
parent: work_package)
end
shared_examples_for 'successful move' do
it { expect(flash[:notice]).to eq(I18n.t(:notice_successful_create)) }
end
before do
allow(User).to receive(:current).and_return(current_user)
def self.copy_child_work_package
post :create,
params: {
ids: [child_wp.id],
copy: '',
new_project_id: to_project.id,
work_package_id: child_wp.id,
new_type_id: to_project.types.first.id
}
end
end
context 'when cross_project_work_package_relations is disabled' do
before do
allow(Setting).to receive(:cross_project_work_package_relations?).and_return(false)
copy_child_work_package
end
it 'is unsuccessful' do
expect(flash[:error])
.to eq(I18n.t(:notice_failed_to_save_work_packages,
count: 1,
total: 1,
ids: "##{child_wp.id}"))
end
end
context 'when cross_project_work_package_relations is enabled' do
before do
allow(Setting).to receive(:cross_project_work_package_relations?).and_return(true)
copy_child_work_package
end
it_behaves_like 'successful move'
it { expect(to_project.work_packages.first.parent).to eq(child_wp.parent) }
end
end
end
end
end
end