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_controller_sp...

413 lines
13 KiB

#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
#
# 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-2017 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 WorkPackagesController, type: :controller do
before do
allow(User).to receive(:current).and_return current_user
# disables sending mails
allow(UserMailer).to receive(:new).and_return(double('mailer').as_null_object)
end
let(:project) { FactoryBot.create(:project, identifier: 'test_project', is_public: false) }
let(:stub_project) { FactoryBot.build_stubbed(:project, identifier: 'test_project', is_public: false) }
let(:stub_work_package) { double('work_package', id: 1337, project: stub_project).as_null_object }
let(:current_user) { FactoryBot.create(:user) }
def self.requires_permission_in_project(&block)
describe 'w/o the permission to see the project/work_package' do
before do
allow(controller).to receive(:work_package).and_return(nil)
call_action
end
it 'should render a 404' do
expect(response.response_code).to be === 404
end
end
describe 'w/ the permission to see the project
w/ having the necessary permissions' do
before do
expect(WorkPackage).to receive_message_chain('visible.find_by').and_return(stub_work_package)
end
instance_eval(&block)
end
end
def self.requires_export_permission(&block)
describe 'w/ the export permission
w/o a project' do
let(:project) { nil }
before do
expect(User.current).to receive(:allowed_to?)
.with(:export_work_packages,
project,
global: true)
.and_return(true)
end
instance_eval(&block)
end
describe 'w/ the export permission
w/ a project' do
before do
params[:project_id] = project.id
expect(User.current).to receive(:allowed_to?)
.with(:export_work_packages,
project,
global: false)
.and_return(true)
end
instance_eval(&block)
end
describe 'w/o the export permission' do
let(:project) { nil }
before do
expect(User.current).to receive(:allowed_to?)
.with(:export_work_packages,
project,
global: true)
.and_return(false)
call_action
end
it 'should render a 403' do
expect(response.response_code).to eq(403)
end
end
end
describe 'index' do
let(:query) { FactoryBot.build_stubbed(:query).tap(&:add_default_filter) }
let(:work_packages) { double('work packages').as_null_object }
let(:results) { double('results').as_null_object }
before do
10 years ago
allow(User.current).to receive(:allowed_to?).and_return(false)
expect(User.current).to receive(:allowed_to?)
.with({ controller: 'work_packages',
action: 'index' },
project,
Boards module (#7008) * Hack spike to show D&D use case [ci skip] * Add ordered work packages * Save order on existing work packages * Boards WIP * CDK drag * Add dragula handler [ci skip] * Add filter to return all manual sorted work packages * Print icon on hover * Boards routing and list components * Better loading indicator on list with streaming result [ci skip] * Add new board and list buttons [ci skip] * Post new query [ci skip] * Added creation of new board lists with persisted queries [ci skip] * Render placeholder row in empty queries [ci skip] * Push boards on grid * Use base class in scope [ci skip] * Extend api for options * Hack spike to show D&D use case [ci skip] * Add ordered work packages * Save order on existing work packages * Boards WIP * CDK drag * Add dragula handler [ci skip] * Add filter to return all manual sorted work packages * Print icon on hover * Boards routing and list components * Better loading indicator on list with streaming result [ci skip] * Add new board and list buttons [ci skip] * Post new query [ci skip] * Added creation of new board lists with persisted queries [ci skip] * Render placeholder row in empty queries [ci skip] * Save queries in grids [ci skip] * Renaming queries [ci skip] * Add existing work packages to board [ci skip] * Introduce card view component for work packages * Extend grids to allow project scope for boards (#7025) Extends the grid backend to also be able to handle boards. In particular, it adds the ability of boards to be attached to projects and changes the page property of grids to a scope property that better describes that more than one board can belong to the same scope (e.g. /projects/:project_id/boards). For a fully featured board, though, widgets need to be able to store options, so that they can store queries. Those widgets might also need to have custom processing and validation. That part has not been implemented. * introduce project association for boards * have dedicated grid registration classes * update and create form for board grids * extract defaults into grid registration [ci skip] * Add drag and drop to card view [ci skip] * Add options to grid * Fix option migration name * Renaming boards [ci skip] * Frontend deletion of boards * Avoid map on NodeList which doesnt exist [ci skip] * Add inline create to boards [ci skip] * Smaller create button [ci skip] * Add navigation for boards * Make inner grid same height * Replace index page with table * Workaround for widget registration [ci skip] * Fixed height for cards and tables [ci skip] * Implement escape as cancel d&d action [ci skip] * Fix and extend grid specs for name and options * Extend board specs for required name * Fix migration for MySQL references https://stackoverflow.com/a/45825566/420614 * Make board list extend from widget Since we cannot configure widgets yet, it's not yet possible to use a board-list widget anywhere. * Fix specs * Fix escape listener removal [ci skip] * Fix renamed to_path in relation spec [ci skip] * Allow deletion of grids for boards * Avoid reloading resource multiple times with replays * Frontend synchronization on deletion [ci skip] * Delete through table * Use work packages board path * Use work packages board path * Fix augmented columns breaking re-rendering * Fix duplicated permission with forums * Strengthen tab switch in specs * Add hidden flag for project-context queries Allows the API to create a hidden query that will not be rendered to the user even if it is within a project context. * private queries * Add hidden flag for project-context queries Allows the API to create a hidden query that will not be rendered to the user even if it is within a project context. * Move boards below work packages * Add Board configuration modal * Fix reloading with onPush * Saving / Switching of display mode [ci skip] * Extract wp-query-selectable-title into common component * Fix renaming of board-list * Fix auto-hide notifications in boards * Add permissions to seeders * Reorder lists in board * Linting * Remove default gravatar from settings * Show assignees avatar in the card view of WPs * Fix specs * Add missing method * Fix timeline icon * Use URL as input to be able to show avatars for groups, too * Fix test * Add further specs * Use correct data attribute to avoid unnecessary data base calls * Add further specs * Deletion of board lists * Pass permission via gon to decide whether we can create boards * Fix rename spec * Cherry-pick of 7873d59 and 30abc7f
6 years ago
global: project.nil?)
.and_return(true)
end
describe 'with valid query' do
before do
Feature/angular calendar (#6766) * replace rails based calendar with angular * render empty calendar * update query on month switch * introduce specific interval filter * show colors * remove now unused filter partial * start on retaining the view in the url * hide datesInterval filter * I18n for calendars title * stengthen explicity of expected filters * spec moving to the next month * fix FilterSerializer reference * remove outdated feature spec * rework calendar controller specs * avoid undefined columns * bump ng-calendar to 1.7.0 * Revert "fix FilterSerializer reference" This reverts commit 2bb2e574cdd664a02a4eb9c3e94b5a170aec0a67. * Revert "avoid undefined columns" This reverts commit bcbb381b34b095526d3ee1aa15d6263a658c03c0. * load initial query only after calendar has been loaded * implement month remembering * implement history back and forth * cleanup code * remove unused methods * remove order value from filters * replace rails calendar widget completely * fix shrinkwrap * move module into correct namespace * linting * remove unused js * calculate full calendar height dynamically * setting calendar locale from service * retain week on reload * show notification in case of too many results * show tooltip on hover * go to work package on click * deactivate tooltip before wp show * narrow down style to tooltip * [28885] Improve html title consistency when navigating to queries Currently, query names are not reflected in the HTML title. This results in 'wrong' titles being shown when entering a split or full view and then returning back to the list. https://community.openproject.com/wp/28885 [ci skip]
6 years ago
allow(controller).to receive(:retrieve_query).and_return(query)
# Note: Stubs for methods used to build up the json query results.
# TODO RS: Clearly this isn't testing anything, but it all needs to be moved to an API controller anyway.
allow(query).to receive(:results).and_return(results)
allow(results).to receive_message_chain(:sorted_work_packages, :page, :per_page).and_return(work_packages)
end
describe 'html' do
8 years ago
let(:call_action) { get('index', params: { project_id: project.id }) }
before do
call_action
end
describe 'w/o a project' do
let(:project) { nil }
let(:call_action) { get('index') }
it 'should render the index template' do
expect(response).to render_template('work_packages/index')
end
end
context 'w/ a project' do
it 'should render the index template' do
expect(response).to render_template('work_packages/index')
end
end
end
describe 'csv' do
let(:params) { {} }
let(:call_action) { get('index', params: params.merge(format: 'csv')) }
requires_export_permission do
before do
mock_result = double('mock csv result',
error?: false,
content: 'blubs',
mime_type: 'text/csv',
title: 'blubs.csv')
expect(WorkPackage::Exporter::CSV)
.to receive(:list)
.with(query, anything)
.and_yield(mock_result)
expect(controller)
.to receive(:send_data)
.with(mock_result.content,
type: mock_result.mime_type,
filename: mock_result.title) do |_|
# We need to render something because otherwise
# the controller will and he will not find a suitable template
controller.render plain: 'success'
end
end
it 'should fulfill the defined should_receives' do
call_action
end
end
end
describe 'pdf' do
let(:params) { {} }
let(:call_action) { get('index', params: params.merge(format: 'pdf')) }
requires_export_permission do
context 'w/ a valid query' do
before do
mock_result = double('mock pdf result',
error?: false,
content: 'blubs',
mime_type: 'application/pdf',
title: 'blubs.pdf')
expect(controller)
.to receive(:send_data)
.with(mock_result.content,
type: mock_result.mime_type,
filename: mock_result.title) do |_|
# We need to render something because otherwise
# the controller will and he will not find a suitable template
controller.render plain: 'success'
end
expect(WorkPackage::Exporter::PDF)
.to receive(:list)
.with(query, anything)
.and_yield(mock_result)
end
it 'should fulfill the defined should_receives' do
call_action
end
end
context 'with invalid query' do
let(:params) { { query_id: 'hokusbogus' } }
context 'when a non-existant query has been previously selected' do
before do
allow(controller)
Feature/angular calendar (#6766) * replace rails based calendar with angular * render empty calendar * update query on month switch * introduce specific interval filter * show colors * remove now unused filter partial * start on retaining the view in the url * hide datesInterval filter * I18n for calendars title * stengthen explicity of expected filters * spec moving to the next month * fix FilterSerializer reference * remove outdated feature spec * rework calendar controller specs * avoid undefined columns * bump ng-calendar to 1.7.0 * Revert "fix FilterSerializer reference" This reverts commit 2bb2e574cdd664a02a4eb9c3e94b5a170aec0a67. * Revert "avoid undefined columns" This reverts commit bcbb381b34b095526d3ee1aa15d6263a658c03c0. * load initial query only after calendar has been loaded * implement month remembering * implement history back and forth * cleanup code * remove unused methods * remove order value from filters * replace rails calendar widget completely * fix shrinkwrap * move module into correct namespace * linting * remove unused js * calculate full calendar height dynamically * setting calendar locale from service * retain week on reload * show notification in case of too many results * show tooltip on hover * go to work package on click * deactivate tooltip before wp show * narrow down style to tooltip * [28885] Improve html title consistency when navigating to queries Currently, query names are not reflected in the HTML title. This results in 'wrong' titles being shown when entering a split or full view and then returning back to the list. https://community.openproject.com/wp/28885 [ci skip]
6 years ago
.to receive(:retrieve_query)
.and_raise(ActiveRecord::RecordNotFound)
call_action
end
it 'renders a 404' do
expect(response.response_code).to be === 404
end
end
end
context 'with an export error' do
before do
mock_result = double('mock pdf result',
error?: true,
message: 'because')
expect(WorkPackage::Exporter::PDF)
.to receive(:list)
.with(query, anything)
.and_yield(mock_result)
call_action
end
it "shows the error message" do
expect(flash[:error].downcase).to include("because")
end
it "redirects to the html index" do
if project
expect(response).to redirect_to project_work_packages_path(project)
else
expect(response).to redirect_to work_packages_path
end
end
end
end
end
describe 'atom' do
let(:params) { {} }
let(:call_action) { get('index', params: params.merge(format: 'atom')) }
requires_export_permission do
before do
expect(controller).to receive(:render_feed).with(work_packages, anything) do |*_args|
# We need to render something because otherwise
# the controller will and he will not find a suitable template
controller.render plain: 'success'
end
end
it 'should fulfill the defined should_receives' do
call_action
end
end
end
end
end
describe 'index with actual data' do
require 'csv'
render_views
##
# When Ruby tries to join the following work package's subject encoded in ISO-8859-1
# and its description encoded in UTF-8 it will result in a CompatibilityError.
# This would not happen if the description contained only letters covered by
# ISO-8859-1. Since this can happen, though, it is more sensible to encode everything
# in UTF-8 which gets rid of this problem altogether.
let(:work_package) do
FactoryBot.create(
:work_package,
subject: "Ruby encodes ß as '\\xDF' in ISO-8859-1.",
description: "\u2022 requires unicode.",
assigned_to: current_user
)
end
let(:current_user) { FactoryBot.create(:admin) }
it 'performs a successful export' do
wp = work_package.reload
expect do
get :index, params: { format: 'csv', c: %i(subject assignee updatedAt) }
end.not_to raise_error
data = CSV.parse(response.body)
expect(data.size).to eq(2)
expect(data.last).to include(wp.subject)
expect(data.last).to include(wp.description)
expect(data.last).to include(current_user.name)
expect(data.last).to include(wp.updated_at.localtime.strftime("%m/%d/%Y %I:%M %p"))
end
end
describe 'index with a broken project reference' do
before do
get('index', params: { project_id: 'project_that_doesnt_exist' })
end
it { is_expected.to respond_with :not_found }
end
describe 'show.html' do
let(:call_action) { get('show', params: { id: '1337' }) }
requires_permission_in_project do
it 'renders the show builder template' do
call_action
expect(response).to render_template('work_packages/show')
end
end
end
describe 'show.pdf' do
let(:call_action) { get('show', params: { format: 'pdf', id: '1337' }) }
requires_permission_in_project do
it 'respond with a pdf' do
pdf_data = 'foobar'
expected_name = "#{stub_work_package.project.identifier}-#{stub_work_package.id}.pdf"
expected_type = 'application/pdf'
pdf_result = double('pdf_result',
error?: false,
content: pdf_data,
title: expected_name,
mime_type: expected_type)
expect(WorkPackage::Exporter::PDF).to receive(:single).and_yield(pdf_result)
expect(controller).to receive(:send_data).with(pdf_data,
type: expected_type,
filename: expected_name) do |*_args|
# We need to render something because otherwise
# the controller will and he will not find a suitable template
controller.render plain: 'success'
end
call_action
end
end
end
describe 'show.atom' do
let(:call_action) { get('show', params: { format: 'atom', id: '1337' }) }
requires_permission_in_project do
it 'render the journal/index template' do
call_action
expect(response).to render_template('journals/index')
end
end
end
describe 'redirect deep link', with_settings: { login_required?: true } do
let(:current_user) { User.anonymous }
let(:params) do
{ project_id: project.id }
end
it 'redirects to collection with query' do
get 'index', params: params.merge(query_id: 123, query_props: 'foo')
expect(response).to be_redirect
location = "/projects/#{project.id}/work_packages?query_id=123&query_props=foo"
expect(response.location).to end_with(CGI.escape(location))
end
end
end