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/models/query/results_spec.rb

830 lines
24 KiB

#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2020 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-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 ::Query::Results, type: :model, with_mail: false do
let(:query) do
FactoryBot.build :query,
show_hierarchies: false
end
let(:query_results) do
::Query::Results.new query
end
let(:project_1) { FactoryBot.create :project }
let(:role_pm) do
FactoryBot.create(:role,
permissions: %i(
view_work_packages
edit_work_packages
create_work_packages
delete_work_packages
))
end
let(:role_dev) do
FactoryBot.create(:role,
permissions: [:view_work_packages])
end
let(:user_1) do
FactoryBot.create(:user,
firstname: 'user',
lastname: '1',
member_in_project: project_1,
member_through_role: [role_dev, role_pm])
end
let(:wp_p1) do
(1..3).map do
FactoryBot.create(:work_package,
project: project_1,
assigned_to_id: user_1.id)
end
end
describe '#work_package_count_by_group' do
let(:query) do
FactoryBot.build :query,
show_hierarchies: false,
group_by: group_by,
project: project_1
end
let(:type_1) do
FactoryBot.create(:type)
end
let(:type_2) do
FactoryBot.create(:type)
end
let(:work_package1) do
FactoryBot.create(:work_package,
type: type_1,
project: project_1)
end
let(:work_package2) do
FactoryBot.create(:work_package,
type: type_2,
project: project_1)
end
context 'grouping by responsible' do
let(:group_by) { 'responsible' }
it 'should produce a valid SQL statement' do
expect { query_results.work_package_count_by_group }.not_to raise_error
end
end
context 'grouping and filtering by text' do
let(:group_by) { 'responsible' }
before do
query.add_filter('search', '**', ['asdf'])
end
it 'should produce a valid SQL statement (Regression #29598)' do
expect { query_results.work_package_count_by_group }.not_to raise_error
end
end
context 'grouping by assigned_to' do
let(:group_by) { 'assigned_to' }
before do
work_package1
work_package2.update_column(:assigned_to_id, user_1.id)
login_as(user_1)
end
it 'returns a hash of counts by value' do
expect(query_results.work_package_count_by_group).to eql(nil => 1, user_1 => 1)
end
end
context 'grouping by assigned_to with only a nil group' do
let(:group_by) { 'assigned_to' }
before do
work_package1
login_as(user_1)
end
it 'returns a hash of counts by value' do
expect(query_results.work_package_count_by_group).to eql(nil => 1)
end
end
context 'grouping by type' do
let(:group_by) { 'type' }
before do
work_package1
work_package2
login_as(user_1)
end
it 'returns the groups sorted by type`s position' do
type_1.update_column(:position, 1)
type_2.update_column(:position, 2)
result = query_results.work_package_count_by_group
expect(result.length)
.to eql 2
expect(result.keys.map(&:id))
.to eql [type_1.id, type_2.id]
type_1.update_column(:position, 2)
type_2.update_column(:position, 1)
new_results = ::Query::Results.new(query)
result = new_results.work_package_count_by_group
expect(result.length)
.to eql 2
expect(result.keys.map(&:id))
.to eql [type_2.id, type_1.id]
end
end
context 'grouping by list custom field and filtering for it at the same time' do
let!(:custom_field) do
FactoryBot.create(:list_wp_custom_field,
is_for_all: true,
is_filter: true,
multi_value: true).tap do |cf|
work_package1.type.custom_fields << cf
work_package2.type.custom_fields << cf
end
end
let(:first_value) do
custom_field.custom_options.first
end
let(:last_value) do
custom_field.custom_options.last
end
let(:group_by) { "cf_#{custom_field.id}" }
before do
login_as(user_1)
work_package1.send(:"custom_field_#{custom_field.id}=", first_value)
work_package1.save!
work_package2.send(:"custom_field_#{custom_field.id}=", [first_value,
last_value])
work_package2.save!
end
it 'yields no error but rather returns the result' do
expect { query_results.work_package_count_by_group }.not_to raise_error
group_count = query_results.work_package_count_by_group
expected_groups = [[first_value], [first_value, last_value]]
group_count.each do |key, count|
expect(count).to eql 1
expect(expected_groups.any? { |group| group & key == key & group }).to be_truthy
end
end
end
context 'grouping by int custom field' do
let!(:custom_field) do
FactoryBot.create(:int_wp_custom_field, is_for_all: true, is_filter: true)
end
let(:group_by) { "cf_#{custom_field.id}" }
before do
login_as(user_1)
wp_p1[0].type.custom_fields << custom_field
project_1.work_package_custom_fields << custom_field
wp_p1[0].update_attribute(:"custom_field_#{custom_field.id}", 42)
wp_p1[0].save
wp_p1[1].update_attribute(:"custom_field_#{custom_field.id}", 42)
wp_p1[1].save
end
it 'returns a hash of counts by value' do
expect(query_results.work_package_count_by_group).to eql(42 => 2, nil => 1)
end
end
context 'grouping by user custom field' do
let!(:custom_field) do
FactoryBot.create(:user_wp_custom_field, is_for_all: true, is_filter: true)
end
let(:group_by) { "cf_#{custom_field.id}" }
before do
login_as(user_1)
wp_p1[0].type.custom_fields << custom_field
project_1.work_package_custom_fields << custom_field
end
it 'returns nil as user custom fields are not groupable' do
expect(query_results.work_package_count_by_group).to be_nil
end
end
context 'grouping by bool custom field' do
let!(:custom_field) do
FactoryBot.create(:bool_wp_custom_field, is_for_all: true, is_filter: true)
end
let(:group_by) { "cf_#{custom_field.id}" }
before do
login_as(user_1)
wp_p1[0].type.custom_fields << custom_field
project_1.work_package_custom_fields << custom_field
wp_p1[0].update_attribute(:"custom_field_#{custom_field.id}", true)
wp_p1[0].save
wp_p1[1].update_attribute(:"custom_field_#{custom_field.id}", true)
wp_p1[1].save
end
it 'returns a hash of counts by value' do
expect(query_results.work_package_count_by_group).to eql(true => 2, nil => 1)
end
end
context 'grouping by date custom field' do
let!(:custom_field) do
FactoryBot.create(:date_wp_custom_field, is_for_all: true, is_filter: true)
end
let(:group_by) { "cf_#{custom_field.id}" }
before do
login_as(user_1)
wp_p1[0].type.custom_fields << custom_field
project_1.work_package_custom_fields << custom_field
wp_p1[0].update_attribute(:"custom_field_#{custom_field.id}", Date.today)
wp_p1[0].save
wp_p1[1].update_attribute(:"custom_field_#{custom_field.id}", Date.today)
wp_p1[1].save
end
it 'returns a hash of counts by value' do
expect(query_results.work_package_count_by_group).to eql(Date.today => 2, nil => 1)
end
end
end
describe '#work_packages' do
let!(:project_1) { FactoryBot.create :project }
let!(:project_2) { FactoryBot.create :project }
let!(:member) do
FactoryBot.create(:member,
project: project_2,
principal: user_1,
roles: [role_pm])
end
let!(:user_2) do
FactoryBot.create(:user,
firstname: 'user',
lastname: '2',
member_in_project: project_2,
member_through_role: role_dev)
end
let!(:wp_p2) do
FactoryBot.create(:work_package,
project: project_2,
assigned_to_id: user_2.id)
end
let!(:wp2_p2) do
FactoryBot.create(:work_package,
project: project_2,
assigned_to_id: user_1.id)
end
before do
wp_p1
end
context 'when filtering for assigned_to_role' do
before do
allow(User).to receive(:current).and_return(user_2)
allow(project_2.descendants).to receive(:active).and_return([])
query.add_filter('assigned_to_role', '=', [role_dev.id.to_s])
end
context 'when a project is set' do
let(:query) { FactoryBot.build :query, project: project_2 }
it 'should display only wp for selected project and selected role' do
expect(query_results.work_packages).to match_array([wp_p2])
end
end
context 'when no project is set' do
let(:query) { FactoryBot.build :query, project: nil }
it 'should display all wp from projects where User.current has access' do
expect(query_results.work_packages).to match_array([wp_p2, wp2_p2])
end
end
end
# this tests some unfortunate combination of filters where wrong
# sql statements where produced.
context 'with a custom field being returned and paginating' do
let(:group_by) { nil }
let(:query) do
FactoryBot.build_stubbed :query,
show_hierarchies: false,
group_by: group_by,
project: project_2
end
let!(:custom_field) { FactoryBot.create(:work_package_custom_field, is_for_all: true) }
before do
allow(User).to receive(:current).and_return(user_2)
# reload in order to have the custom field as an available
# custom field
query.project = Project.find(query.project.id)
end
context 'when grouping by assignees' do
before do
query.column_names = [:assigned_to, :"cf_#{custom_field.id}"]
query.group_by = 'assigned_to'
end
it 'returns all work packages of project 2' do
work_packages = query
.results
.work_packages
.page(1)
.per_page(10)
expect(work_packages).to match_array([wp_p2, wp2_p2])
end
end
context 'when grouping by responsibles' do
let(:group_by) { 'responsible' }
before do
query.column_names = [:responsible, :"cf_#{custom_field.id}"]
end
it 'returns all work packages of project 2' do
work_packages = query
.results
.work_packages
.page(1)
.per_page(10)
expect(work_packages).to match_array([wp_p2, wp2_p2])
end
end
end
9 years ago
context 'when grouping by responsible' do
let(:query) do
FactoryBot.build :query,
show_hierarchies: false,
group_by: group_by,
project: project_1
end
let(:group_by) { 'responsible' }
9 years ago
before do
allow(User).to receive(:current).and_return(user_1)
wp_p1[0].update_attribute(:responsible, user_1)
wp_p1[1].update_attribute(:responsible, user_2)
end
it 'outputs the work package count in the schema { <User> => count }' do
expect(query_results.work_package_count_by_group)
.to eql(user_1 => 1, user_2 => 1, nil => 1)
9 years ago
end
end
Add relations tables to Types via form configuration (#6773) * WIP: PrecedesFilter and FollowsFilter for WorkPackages * Create Type Form Groups per Query Type * generalize filters on relations avoiding alias * fix flickering spec * Rename dependency represeners for Follower and Predecessor Filters * Allow configuring templated queries within query configuring modal * Use `{id}` as templated value, instead of a now deprecated `templated` string * Rewrite ParentFilter to follow same structure as other relation filters. * Set Follower and Predecessor filters as hidden in Frontend * Default query shall show closed WPs, too * Remove relation filter type selection from form configuration view as we extend query configuration modal instead. * Allow ExternalQueryConfiguration to be more specific and prepend relation filters in its modal. * Quick unrelated fix on the way: the instruction text should start below the columns input and not to the right of it * - Add all missing relation filters. - Use verbs for naming instead of nouns to stay consistent with UI. * fix typo * Add relation filters to hidden filters and fix a rebase bug * Typo in docs * Fix broken rebase conflict resolution * Add part of and includes filter * adding specs for relation filters * rename RelatesFilter to RelatesToFilter * Rename shared example as direction does not matter anymore. * Fix spec for IncludesFilter * Fix name conflict for `includes` by calling typed_dag's `direct` later. * Fix shared filter examples as the parent filter does not get added per default anymore. * Fix spec after renaming PredecessorFilter to PrecedesFilter * Fix integration spec for type configuration form * Add filter dependency specs * Differentiate between WorkPackageFormChildrenQueryGroup and WorkPackageRelationQueryGroup types * Create inline-create for relation tables * Rewrite filters to use actual relation_type as key * Reload relations on change, change symbols * Fix relation filter i18n strings * Test presence of all relation filters frontend. * Extend integration test for form configuration to not only cover hierarchy, but also undirectional and directional relation types. * Consistent naming of filter dependency representer files * Satisfy codeclimate * Add missing copyright notes * Fixing PartofFilter and its specs * Reverse relation direction when created inline * WIP integration test for Relation Query Component and Children Query Component. * Correctly reload children tables when refreshed * Fix FilterOnUndirectedMixin * Fix removing of relation from embedded table after reload * Adding intergration tests for removing and adding relation or children, initiated form either embedded table or relations tab. * Fix specs * Fix implementation of duplicates and duplicated They are reversed in typed_dag and causes confusion [ci skip]
6 years ago
context 'when filtering by precedes and ordering by id' do
Add relations tables to Types via form configuration (#6773) * WIP: PrecedesFilter and FollowsFilter for WorkPackages * Create Type Form Groups per Query Type * generalize filters on relations avoiding alias * fix flickering spec * Rename dependency represeners for Follower and Predecessor Filters * Allow configuring templated queries within query configuring modal * Use `{id}` as templated value, instead of a now deprecated `templated` string * Rewrite ParentFilter to follow same structure as other relation filters. * Set Follower and Predecessor filters as hidden in Frontend * Default query shall show closed WPs, too * Remove relation filter type selection from form configuration view as we extend query configuration modal instead. * Allow ExternalQueryConfiguration to be more specific and prepend relation filters in its modal. * Quick unrelated fix on the way: the instruction text should start below the columns input and not to the right of it * - Add all missing relation filters. - Use verbs for naming instead of nouns to stay consistent with UI. * fix typo * Add relation filters to hidden filters and fix a rebase bug * Typo in docs * Fix broken rebase conflict resolution * Add part of and includes filter * adding specs for relation filters * rename RelatesFilter to RelatesToFilter * Rename shared example as direction does not matter anymore. * Fix spec for IncludesFilter * Fix name conflict for `includes` by calling typed_dag's `direct` later. * Fix shared filter examples as the parent filter does not get added per default anymore. * Fix spec after renaming PredecessorFilter to PrecedesFilter * Fix integration spec for type configuration form * Add filter dependency specs * Differentiate between WorkPackageFormChildrenQueryGroup and WorkPackageRelationQueryGroup types * Create inline-create for relation tables * Rewrite filters to use actual relation_type as key * Reload relations on change, change symbols * Fix relation filter i18n strings * Test presence of all relation filters frontend. * Extend integration test for form configuration to not only cover hierarchy, but also undirectional and directional relation types. * Consistent naming of filter dependency representer files * Satisfy codeclimate * Add missing copyright notes * Fixing PartofFilter and its specs * Reverse relation direction when created inline * WIP integration test for Relation Query Component and Children Query Component. * Correctly reload children tables when refreshed * Fix FilterOnUndirectedMixin * Fix removing of relation from embedded table after reload * Adding intergration tests for removing and adding relation or children, initiated form either embedded table or relations tab. * Fix specs * Fix implementation of duplicates and duplicated They are reversed in typed_dag and causes confusion [ci skip]
6 years ago
let(:query) do
FactoryBot.build :query,
project: project_1
end
before do
login_as(user_1)
wp_p1[1].precedes << wp_p1[0]
query.add_filter('precedes', '=', [wp_p1[0].id.to_s])
query.sort_criteria = [['id', 'asc']]
Add relations tables to Types via form configuration (#6773) * WIP: PrecedesFilter and FollowsFilter for WorkPackages * Create Type Form Groups per Query Type * generalize filters on relations avoiding alias * fix flickering spec * Rename dependency represeners for Follower and Predecessor Filters * Allow configuring templated queries within query configuring modal * Use `{id}` as templated value, instead of a now deprecated `templated` string * Rewrite ParentFilter to follow same structure as other relation filters. * Set Follower and Predecessor filters as hidden in Frontend * Default query shall show closed WPs, too * Remove relation filter type selection from form configuration view as we extend query configuration modal instead. * Allow ExternalQueryConfiguration to be more specific and prepend relation filters in its modal. * Quick unrelated fix on the way: the instruction text should start below the columns input and not to the right of it * - Add all missing relation filters. - Use verbs for naming instead of nouns to stay consistent with UI. * fix typo * Add relation filters to hidden filters and fix a rebase bug * Typo in docs * Fix broken rebase conflict resolution * Add part of and includes filter * adding specs for relation filters * rename RelatesFilter to RelatesToFilter * Rename shared example as direction does not matter anymore. * Fix spec for IncludesFilter * Fix name conflict for `includes` by calling typed_dag's `direct` later. * Fix shared filter examples as the parent filter does not get added per default anymore. * Fix spec after renaming PredecessorFilter to PrecedesFilter * Fix integration spec for type configuration form * Add filter dependency specs * Differentiate between WorkPackageFormChildrenQueryGroup and WorkPackageRelationQueryGroup types * Create inline-create for relation tables * Rewrite filters to use actual relation_type as key * Reload relations on change, change symbols * Fix relation filter i18n strings * Test presence of all relation filters frontend. * Extend integration test for form configuration to not only cover hierarchy, but also undirectional and directional relation types. * Consistent naming of filter dependency representer files * Satisfy codeclimate * Add missing copyright notes * Fixing PartofFilter and its specs * Reverse relation direction when created inline * WIP integration test for Relation Query Component and Children Query Component. * Correctly reload children tables when refreshed * Fix FilterOnUndirectedMixin * Fix removing of relation from embedded table after reload * Adding intergration tests for removing and adding relation or children, initiated form either embedded table or relations tab. * Fix specs * Fix implementation of duplicates and duplicated They are reversed in typed_dag and causes confusion [ci skip]
6 years ago
end
it 'returns the work packages preceding the filtered for work package' do
expect(query.results.work_packages)
.to match_array(wp_p1[1])
end
end
end
describe '#sorted_work_packages' do
Add relations tables to Types via form configuration (#6773) * WIP: PrecedesFilter and FollowsFilter for WorkPackages * Create Type Form Groups per Query Type * generalize filters on relations avoiding alias * fix flickering spec * Rename dependency represeners for Follower and Predecessor Filters * Allow configuring templated queries within query configuring modal * Use `{id}` as templated value, instead of a now deprecated `templated` string * Rewrite ParentFilter to follow same structure as other relation filters. * Set Follower and Predecessor filters as hidden in Frontend * Default query shall show closed WPs, too * Remove relation filter type selection from form configuration view as we extend query configuration modal instead. * Allow ExternalQueryConfiguration to be more specific and prepend relation filters in its modal. * Quick unrelated fix on the way: the instruction text should start below the columns input and not to the right of it * - Add all missing relation filters. - Use verbs for naming instead of nouns to stay consistent with UI. * fix typo * Add relation filters to hidden filters and fix a rebase bug * Typo in docs * Fix broken rebase conflict resolution * Add part of and includes filter * adding specs for relation filters * rename RelatesFilter to RelatesToFilter * Rename shared example as direction does not matter anymore. * Fix spec for IncludesFilter * Fix name conflict for `includes` by calling typed_dag's `direct` later. * Fix shared filter examples as the parent filter does not get added per default anymore. * Fix spec after renaming PredecessorFilter to PrecedesFilter * Fix integration spec for type configuration form * Add filter dependency specs * Differentiate between WorkPackageFormChildrenQueryGroup and WorkPackageRelationQueryGroup types * Create inline-create for relation tables * Rewrite filters to use actual relation_type as key * Reload relations on change, change symbols * Fix relation filter i18n strings * Test presence of all relation filters frontend. * Extend integration test for form configuration to not only cover hierarchy, but also undirectional and directional relation types. * Consistent naming of filter dependency representer files * Satisfy codeclimate * Add missing copyright notes * Fixing PartofFilter and its specs * Reverse relation direction when created inline * WIP integration test for Relation Query Component and Children Query Component. * Correctly reload children tables when refreshed * Fix FilterOnUndirectedMixin * Fix removing of relation from embedded table after reload * Adding intergration tests for removing and adding relation or children, initiated form either embedded table or relations tab. * Fix specs * Fix implementation of duplicates and duplicated They are reversed in typed_dag and causes confusion [ci skip]
6 years ago
let(:work_package1) { FactoryBot.create(:work_package, project: project_1, id: 1) }
let(:work_package2) { FactoryBot.create(:work_package, project: project_1, id: 2) }
let(:work_package3) { FactoryBot.create(:work_package, project: project_1, id: 3) }
let(:sort_by) { [['id', 'asc']] }
let(:columns) { %i(id subject) }
let(:group_by) { '' }
let(:query) do
FactoryBot.build_stubbed :query,
show_hierarchies: false,
group_by: group_by,
sort_criteria: sort_by,
project: project_1,
column_names: columns
end
let(:query_results) do
::Query::Results.new query
end
let(:user_a) { FactoryBot.create(:user, firstname: 'AAA', lastname: 'AAA') }
let(:user_m) { FactoryBot.create(:user, firstname: 'MMM', lastname: 'MMM') }
let(:user_z) { FactoryBot.create(:user, firstname: 'ZZZ', lastname: 'ZZZ') }
context 'grouping by assigned_to, having the author column selected' do
let(:group_by) { 'assigned_to' }
let(:columns) { %i(id subject author) }
before do
allow(User).to receive(:current).and_return(user_1)
work_package1.assigned_to = user_m
work_package1.author = user_m
work_package1.save(validate: false)
work_package2.assigned_to = user_z
work_package2.author = user_a
work_package2.save(validate: false)
work_package3.assigned_to = user_m
work_package3.author = user_a
work_package3.save(validate: false)
end
it 'sorts first by assigned_to (group by), then by sort criteria' do
# Would look like this in the table
#
# user_m
# work_package 1
# work_package 3
# user_z
# work_package 2
expect(query_results.sorted_work_packages)
.to match [work_package1, work_package3, work_package2]
end
end
context 'sorting by author, grouping by assigned_to' do
let(:group_by) { 'assigned_to' }
let(:sort_by) { [['author', 'asc']] }
before do
allow(User).to receive(:current).and_return(user_1)
work_package1.assigned_to = user_m
work_package1.author = user_m
work_package1.save(validate: false)
work_package2.assigned_to = user_z
work_package2.author = user_a
work_package2.save(validate: false)
work_package3.assigned_to = user_m
work_package3.author = user_a
work_package3.save(validate: false)
end
it 'sorts first by group by, then by assigned_to' do
# Would look like this in the table
#
# user_m
# work_package 3
# work_package 1
# user_z
# work_package 2
expect(query_results.sorted_work_packages)
.to match [work_package3, work_package1, work_package2]
query.sort_criteria = [['author', 'desc']]
# Would look like this in the table
#
# user_m
# work_package 1
# work_package 3
# user_z
# work_package 2
expect(query_results.sorted_work_packages)
.to match [work_package1, work_package3, work_package2]
end
end
context 'sorting and grouping by priority' do
let(:prio_low) { FactoryBot.create :issue_priority, position: 1 }
let(:prio_high) { FactoryBot.create :issue_priority, position: 0 }
let(:group_by) { 'priority' }
before do
allow(User).to receive(:current).and_return(user_1)
work_package1.priority = prio_low
work_package2.priority = prio_high
work_package1.save(validate: false)
work_package2.save(validate: false)
end
it 'respects the sorting (Regression #29689)' do
query.sort_criteria = [['priority', 'asc']]
expect(query_results.sorted_work_packages)
.to match [work_package1, work_package2]
query.sort_criteria = [['priority', 'desc']]
expect(query_results.sorted_work_packages)
.to match [work_package2, work_package1]
end
end
context 'sorting by priority, grouping by project' do
let(:prio_low) { FactoryBot.create :issue_priority, position: 1 }
let(:prio_high) { FactoryBot.create :issue_priority, position: 0 }
let(:group_by) { 'project' }
before do
allow(User).to receive(:current).and_return(user_1)
work_package1.priority = prio_low
work_package2.priority = prio_high
work_package1.save(validate: false)
work_package2.save(validate: false)
end
it 'properly selects project_id (Regression #31667)' do
query.sort_criteria = [['priority', 'asc']]
expect(query_results.sorted_work_packages)
.to match [work_package1, work_package2]
query.sort_criteria = [['priority', 'desc']]
expect(query_results.sorted_work_packages)
.to match [work_package2, work_package1]
group_count = query_results.work_package_count_by_group
expect(group_count).to eq({ project_1 => 2 })
end
end
context 'sorting by author and responsible, grouping by assigned_to' do
let(:group_by) { 'assigned_to' }
let(:sort_by) { [['author', 'asc'], ['responsible', 'desc']] }
before do
allow(User).to receive(:current).and_return(user_1)
work_package1.assigned_to = user_m
work_package1.author = user_m
work_package1.responsible = user_a
work_package1.save(validate: false)
work_package2.assigned_to = user_z
work_package2.author = user_m
work_package3.responsible = user_m
work_package2.save(validate: false)
work_package3.assigned_to = user_m
work_package3.author = user_m
work_package3.responsible = user_z
work_package3.save(validate: false)
end
it 'sorts first by group by, then by assigned_to (neutral as equal), then by responsible' do
# Would look like this in the table
#
# user_m
# work_package 3
# work_package 1
# user_z
# work_package 2
expect(query_results.sorted_work_packages)
.to match [work_package3, work_package1, work_package2]
query.sort_criteria = [['author', 'desc'], ['responsible', 'asc']]
# Would look like this in the table
#
# user_m
# work_package 1
# work_package 3
# user_z
# work_package 2
expect(query_results.sorted_work_packages)
.to match [work_package1, work_package3, work_package2]
end
end
context 'filtering by bool cf' do
let(:bool_cf) { FactoryBot.create(:bool_wp_custom_field, is_filter: true) }
let(:custom_value) do
FactoryBot.create(:custom_value,
custom_field: bool_cf,
customized: work_package1,
value: value)
end
let(:value) { 't' }
let(:filter_value) { 't' }
let(:activate_cf) do
work_package1.project.work_package_custom_fields << bool_cf
work_package1.type.custom_fields << bool_cf
work_package1.reload
project_1.reload
end
before do
allow(User).to receive(:current).and_return(user_1)
custom_value
activate_cf
query.add_filter(:"cf_#{bool_cf.id}", '=', [filter_value])
end
shared_examples_for 'is empty' do
it 'is empty' do
expect(query.results.work_packages)
.to be_empty
end
end
shared_examples_for 'returns the wp' do
it 'returns the wp' do
expect(query.results.work_packages)
.to match_array(work_package1)
end
end
context 'with the wp having true for the cf
and filtering for true' do
it_behaves_like 'returns the wp'
end
context 'with the wp having true for the cf
and filtering for false' do
let(:filter_value) { 'f' }
it_behaves_like 'is empty'
end
context 'with the wp having false for the cf
and filtering for false' do
let(:value) { 'f' }
let(:filter_value) { 'f' }
it_behaves_like 'returns the wp'
end
context 'with the wp having false for the cf
and filtering for true' do
let(:value) { 'f' }
it_behaves_like 'is empty'
end
context 'with the wp having no value for the cf
and filtering for true' do
let(:custom_value) { nil }
it_behaves_like 'is empty'
end
context 'with the wp having no value for the cf
and filtering for false' do
let(:custom_value) { nil }
let(:filter_value) { 'f' }
it_behaves_like 'returns the wp'
end
context 'with the wp having no value for the cf
and filtering for false
and the cf not being active in the project' do
let(:custom_value) { nil }
let(:filter_value) { 'f' }
let(:activate_cf) do
work_package1.type.custom_fields << bool_cf
work_package1.reload
project_1.reload
end
it_behaves_like 'is empty'
end
context 'with the wp having no value for the cf
and filtering for false
and the cf not being active for the type' do
let(:custom_value) { nil }
let(:filter_value) { 'f' }
let(:activate_cf) do
work_package1.type.custom_fields << bool_cf
work_package1.reload
project_1.reload
end
it_behaves_like 'is empty'
end
context 'with the wp having no value for the cf
and filtering for false
and the cf not being active in the project
and the cf being for all' do
let(:custom_value) { nil }
let(:filter_value) { 'f' }
let(:bool_cf) do
FactoryBot.create(:bool_wp_custom_field,
is_filter: true,
is_for_all: true)
end
let(:activate_cf) do
work_package1.project.work_package_custom_fields << bool_cf
work_package1.reload
project_1.reload
end
it_behaves_like 'is empty'
end
end
end
end