mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
447e07b38d
failing spec: spec/features/work_packages/progress_modal_spec.rb:195 failing run: https://github.com/opf/openproject/actions/runs/21204407008/job/60997306384 In the spec, another page is visited during the test, meaning the internal ids of the capybara elements may not be the same as the ones before the page is reloaded. This is a problem because the `progress_popover` caches the container element, and it's not valid anymore (it's stale). One fix could be to create a new `progress_popover` instance after the other page is visited. I found it better to be able to pass a lambda for the container element to the `progress_popover` constructor, so that it always gets it afresh and will never be stale.
787 lines
31 KiB
Ruby
787 lines
31 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# -- copyright
|
|
# OpenProject is an open source project management software.
|
|
# Copyright (C) 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 COPYRIGHT and LICENSE files for more details.
|
|
# ++
|
|
|
|
require "spec_helper"
|
|
|
|
RSpec.describe "Progress modal", :js do
|
|
shared_let(:user) { create(:admin) }
|
|
shared_let(:role) { create(:project_role) }
|
|
|
|
shared_let(:type_task) { create(:type_task) }
|
|
shared_let(:project) { create(:project, types: [type_task]) }
|
|
shared_let(:priority) { create(:default_priority, name: "Normal") }
|
|
shared_let(:open_status_with_0p_done_ratio) do
|
|
create(:status, name: "open", default_done_ratio: 0)
|
|
end
|
|
shared_let(:in_progress_status_with_50p_done_ratio) do
|
|
create(:status, name: "in progress", default_done_ratio: 50)
|
|
end
|
|
shared_let(:complete_status_with_100p_done_ratio) do
|
|
create(:status, name: "complete", default_done_ratio: 100)
|
|
end
|
|
|
|
shared_let(:estimated_hours) { 10.0 }
|
|
shared_let(:remaining_hours) { 5.0 }
|
|
shared_let(:work_package) do
|
|
create(:work_package,
|
|
project:,
|
|
type: type_task,
|
|
status: open_status_with_0p_done_ratio) do |wp|
|
|
update_work_package_with(wp, estimated_hours:, remaining_hours:)
|
|
end
|
|
end
|
|
|
|
def update_work_package_with(work_package, attributes)
|
|
WorkPackages::UpdateService.new(model: work_package,
|
|
user:,
|
|
contract_class: WorkPackages::CreateContract)
|
|
.call(**attributes)
|
|
end
|
|
|
|
let(:progress_query) do
|
|
create(:query,
|
|
project:,
|
|
user:,
|
|
display_sums: false,
|
|
column_names: %i[id subject type status
|
|
estimated_hours remaining_hours done_ratio]) do |query|
|
|
create(:view_work_packages_table, query:)
|
|
end
|
|
end
|
|
|
|
let(:work_package_table) { Pages::WorkPackagesTable.new(project) }
|
|
let(:work_package_row) { work_package_table.work_package_container(work_package) }
|
|
let(:progress_popover) { work_package_table.progress_popover(work_package) }
|
|
let(:work_package_create_page) { Pages::FullWorkPackageCreate.new(project:) }
|
|
|
|
current_user { user }
|
|
|
|
def visit_progress_query_displaying_work_package
|
|
work_package_table.visit_query(progress_query)
|
|
work_package_table.expect_work_package_listed(work_package)
|
|
end
|
|
|
|
describe "clicking on a field on the work package table" do
|
|
it "sets the cursor after the last character on the selected input field" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open_by_clicking_on_field(:work)
|
|
progress_popover.expect_cursor_at_end_of_input(:work)
|
|
end
|
|
end
|
|
|
|
describe "work based mode" do
|
|
it "formats the values on input field blur" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
|
|
progress_popover.set_values(work: "5")
|
|
progress_popover.focus(:remaining_work)
|
|
progress_popover.expect_values(work: "5h")
|
|
|
|
progress_popover.set_values(remaining_work: "2")
|
|
progress_popover.focus(:percent_complete)
|
|
progress_popover.expect_values(remaining_work: "2h")
|
|
|
|
progress_popover.set_values(percent_complete: "30")
|
|
progress_popover.focus(:work)
|
|
progress_popover.expect_values(percent_complete: "30%")
|
|
end
|
|
|
|
shared_examples_for "opens the modal with the clicked field in focus" do
|
|
it "when clicking on a field opens the modal and focuses on the related modal input field", :aggregate_failures do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
%i[work remaining_work percent_complete].each do |field_name|
|
|
progress_popover.open_by_clicking_on_field(field_name)
|
|
progress_popover.expect_focused(field_name)
|
|
progress_popover.close
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with no fields set" do
|
|
before do
|
|
update_work_package_with(work_package, estimated_hours: nil, remaining_hours: nil, done_ratio: nil)
|
|
end
|
|
|
|
include_examples "opens the modal with the clicked field in focus"
|
|
end
|
|
|
|
context "with all fields set" do
|
|
before do
|
|
update_work_package_with(work_package, estimated_hours: 25.0, remaining_hours: 15.0)
|
|
end
|
|
|
|
include_examples "opens the modal with the clicked field in focus"
|
|
end
|
|
end
|
|
|
|
describe "status based mode", with_settings: { work_package_done_ratio: "status" } do
|
|
it "formats the values on input field blur" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
|
|
progress_popover.set_values(work: "5")
|
|
progress_popover.focus(:status)
|
|
progress_popover.expect_values(work: "5h")
|
|
end
|
|
|
|
describe "clicking on the work field in the work package table " \
|
|
"with no fields set" do
|
|
before { update_work_package_with(work_package, estimated_hours: nil, remaining_hours: nil) }
|
|
|
|
it "opens the modal with work in focus" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open_by_clicking_on_field(:work)
|
|
progress_popover.expect_focused(:work)
|
|
end
|
|
end
|
|
|
|
describe "clicking on the work field in the work package table " \
|
|
"with all fields set" do
|
|
before { update_work_package_with(work_package, estimated_hours: 20.0, remaining_hours: 15.0) }
|
|
|
|
it "opens the modal with work in focus" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open_by_clicking_on_field(:work)
|
|
progress_popover.expect_focused(:work)
|
|
end
|
|
end
|
|
|
|
describe "Remaining work field" do
|
|
it "is readonly" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_read_only(:remaining_work)
|
|
end
|
|
end
|
|
|
|
describe "Status field" do
|
|
before { open_status_with_0p_done_ratio.update!(is_default: true) }
|
|
|
|
it "renders only assignable statuses as options" do
|
|
# Create a single valid transition from "open" to "in progress"
|
|
create(:workflow,
|
|
type_id: type_task.id,
|
|
old_status: open_status_with_0p_done_ratio,
|
|
new_status: in_progress_status_with_50p_done_ratio,
|
|
role:)
|
|
|
|
visit_progress_query_displaying_work_package
|
|
progress_popover.open
|
|
|
|
# The only defined workflow is "open" to "in progress" so "complete" must
|
|
# not be listed as an available option
|
|
progress_popover.expect_select_with_options(:status, "open (0%)", "in progress (50%)")
|
|
progress_popover.expect_select_without_options(:status, "complete (100%)")
|
|
|
|
# Create another valid transition from "open" to "complete"
|
|
create(:workflow,
|
|
type_id: type_task.id,
|
|
old_status: open_status_with_0p_done_ratio,
|
|
new_status: complete_status_with_100p_done_ratio,
|
|
role:)
|
|
|
|
visit_progress_query_displaying_work_package
|
|
|
|
wait_for_reload
|
|
|
|
progress_popover.open
|
|
|
|
progress_popover.expect_select_with_options(:status, "open (0%)", "in progress (50%)", "complete (100%)")
|
|
end
|
|
end
|
|
|
|
context "when on a new work package form" do
|
|
let(:progress_popover) { Components::WorkPackages::ProgressPopover.new(create_form: true) }
|
|
|
|
specify "modal renders when no default status is set for new work packages" do
|
|
work_package_create_page.visit!
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_value(:status, :empty_without_any_options, disabled: true)
|
|
end
|
|
|
|
context "with a default status set for new work packages" do
|
|
before_all do
|
|
open_status_with_0p_done_ratio.update!(is_default: true)
|
|
|
|
create(:workflow,
|
|
type_id: type_task.id,
|
|
old_status: open_status_with_0p_done_ratio,
|
|
new_status: in_progress_status_with_50p_done_ratio,
|
|
role:)
|
|
create(:workflow,
|
|
type_id: type_task.id,
|
|
old_status: open_status_with_0p_done_ratio,
|
|
new_status: complete_status_with_100p_done_ratio,
|
|
role:)
|
|
end
|
|
|
|
it "can create work package after setting work" do
|
|
work_package_create_page.visit!
|
|
work_package_create_page.expect_fully_loaded
|
|
|
|
progress_popover.open
|
|
progress_popover.set_values(work: "invalid")
|
|
progress_popover.expect_values(remaining_work: "")
|
|
progress_popover.expect_errors(work: "Is not a valid duration.")
|
|
|
|
# The modal does not go away when clicking Save until all fields are valid
|
|
3.times do
|
|
progress_popover.save
|
|
sleep 0.2
|
|
progress_popover.expect_errors(work: "Is not a valid duration.")
|
|
end
|
|
progress_popover.set_values(work: "10h")
|
|
progress_popover.save
|
|
|
|
work_package_create_page.set_attributes({ subject: "hello" })
|
|
work_package_create_page.save!
|
|
work_package_table.expect_and_dismiss_toaster(message: "Successful creation.", wait: 5)
|
|
|
|
expect(WorkPackage.order(id: :asc).last).to have_attributes(
|
|
estimated_hours: 10.0,
|
|
remaining_hours: 10.0,
|
|
done_ratio: 0
|
|
)
|
|
end
|
|
|
|
it "renders the status selection field inside the modal as disabled " \
|
|
"and allows setting the status solely by the top-left field" do
|
|
work_package_create_page.visit!
|
|
work_package_create_page.expect_fully_loaded
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_disabled(:status)
|
|
progress_popover.expect_value(:status, "open (0%)", disabled: true)
|
|
|
|
progress_popover.close
|
|
|
|
work_package_create_page.set_status("in progress")
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_value(:status, "in progress (50%)", disabled: true)
|
|
end
|
|
|
|
it "can open the modal, then save without modifying anything" do
|
|
work_package_create_page.visit!
|
|
work_package_create_page.set_attributes({ subject: "hello" })
|
|
|
|
progress_popover.open
|
|
progress_popover.save
|
|
work_package_create_page.expect_no_toaster(type: "error")
|
|
|
|
work_package_create_page.save!
|
|
work_package_table.expect_and_dismiss_toaster(message: "Successful creation.")
|
|
end
|
|
|
|
it "updates remaining work when status is changed" do
|
|
work_package_create_page.visit!
|
|
work_package_create_page.set_attributes({ subject: "hello" })
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_hints(work: nil, remaining_work: nil)
|
|
progress_popover.set_values(work: "14h")
|
|
progress_popover.expect_values(remaining_work: "14h")
|
|
progress_popover.expect_hints(remaining_work: :derived)
|
|
progress_popover.save
|
|
|
|
work_package_create_page.set_status("in progress")
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_values(work: "14h", remaining_work: "7h")
|
|
progress_popover.expect_hints(remaining_work: :derived)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "opening the progress modal" do
|
|
before_all do
|
|
create(:workflow,
|
|
type_id: type_task.id,
|
|
old_status: open_status_with_0p_done_ratio,
|
|
new_status: in_progress_status_with_50p_done_ratio,
|
|
role:)
|
|
create(:workflow,
|
|
type_id: type_task.id,
|
|
old_status: open_status_with_0p_done_ratio,
|
|
new_status: complete_status_with_100p_done_ratio,
|
|
role:)
|
|
end
|
|
|
|
describe "field value format" do
|
|
context "with all values set" do
|
|
before { update_work_package_with(work_package, estimated_hours: 10.0, remaining_hours: 2.12345) }
|
|
|
|
it "populates fields with values correctly formatted" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_values(
|
|
work: "10h",
|
|
remaining_work: "2.12h", # 2h 7m
|
|
percent_complete: "79%"
|
|
)
|
|
end
|
|
end
|
|
|
|
context "on create page" do
|
|
it "can create work package after setting progress values multiple times" do
|
|
work_package_create_page.visit!
|
|
|
|
work_package_create_page.set_attributes({ subject: "hello" })
|
|
work_edit_field = ProgressEditField.new("#content", :estimatedTime)
|
|
remaining_work_edit_field = ProgressEditField.new("#content", :remainingTime)
|
|
percent_complete_edit_field = ProgressEditField.new("#content", :percentageDone)
|
|
expect(work_edit_field.trigger_element.value).to eq("-")
|
|
expect(remaining_work_edit_field.trigger_element.value).to eq("-")
|
|
expect(percent_complete_edit_field.trigger_element.value).to eq("-")
|
|
|
|
work_package_create_page.set_progress_attributes({ estimatedTime: "0h" })
|
|
expect(work_edit_field.trigger_element.value).to eq("0h")
|
|
expect(remaining_work_edit_field.trigger_element.value).to eq("0h")
|
|
expect(percent_complete_edit_field.trigger_element.value).to eq("-")
|
|
|
|
work_package_create_page.set_progress_attributes({ estimatedTime: "5h" })
|
|
expect(work_edit_field.trigger_element.value).to eq("5h")
|
|
expect(remaining_work_edit_field.trigger_element.value).to eq("5h")
|
|
expect(percent_complete_edit_field.trigger_element.value).to eq("0%")
|
|
|
|
work_package_create_page.set_progress_attributes({ percentageDone: "40%" })
|
|
expect(work_edit_field.trigger_element.value).to eq("5h")
|
|
expect(remaining_work_edit_field.trigger_element.value).to eq("3h")
|
|
expect(percent_complete_edit_field.trigger_element.value).to eq("40%")
|
|
|
|
work_package_create_page.save!
|
|
work_package_table.expect_and_dismiss_toaster(message: "Successful creation.", wait: 5)
|
|
|
|
expect(WorkPackage.order(id: :asc).last).to have_attributes(
|
|
estimated_hours: 5.0,
|
|
remaining_hours: 3.0,
|
|
done_ratio: 40
|
|
)
|
|
end
|
|
end
|
|
|
|
context "with % complete set and setting long decimal values in modal" do
|
|
before do
|
|
work_package.attributes = {
|
|
estimated_hours: nil, remaining_hours: nil, done_ratio: 89
|
|
}
|
|
work_package.save(validate: false)
|
|
end
|
|
|
|
it "does not lose precision due to conversion from ISO duration to hours (rounded to closest minute)" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
# set work to 2.5567
|
|
progress_popover.open
|
|
progress_popover.set_values(work: "2.5567")
|
|
progress_popover.save
|
|
work_package_table.expect_and_dismiss_toaster(message: "Successful update.")
|
|
|
|
# work should have been set to 2.56 and remaining work to 0.28
|
|
work_package.reload
|
|
expect(work_package.estimated_hours).to eq(2.56)
|
|
expect(work_package.remaining_hours).to eq(0.28)
|
|
|
|
# work should be displayed as "2h 34m" ("2h 33m 36s" rounded to minutes),
|
|
# and remaining work as "17m" ("16m 48s" rounded to minutes)
|
|
progress_popover.open
|
|
progress_popover.expect_values(
|
|
work: "2.56h", # 2h 34m
|
|
remaining_work: "0.28h" # 17m
|
|
)
|
|
end
|
|
end
|
|
|
|
context "with empty values" do
|
|
before do
|
|
update_work_package_with(work_package, estimated_hours: nil, remaining_hours: nil, done_ratio: nil)
|
|
end
|
|
|
|
it "populates all fields with blank values" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_values(
|
|
work: "",
|
|
remaining_work: "",
|
|
percent_complete: ""
|
|
)
|
|
end
|
|
end
|
|
|
|
context "with invalid values" do
|
|
before do
|
|
update_work_package_with(work_package, estimated_hours: nil, remaining_hours: nil, done_ratio: nil)
|
|
end
|
|
|
|
it "does not close the modal when clicking save multiple times (Bug #57423)" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.set_values(work: "invalid")
|
|
progress_popover.expect_values(remaining_work: "")
|
|
progress_popover.expect_errors(work: "Is not a valid duration.")
|
|
|
|
# The modal does not go away when clicking save
|
|
3.times do
|
|
progress_popover.save
|
|
sleep 0.2
|
|
progress_popover.expect_errors(work: "Is not a valid duration.")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "status field", with_settings: { work_package_done_ratio: "status" } do
|
|
it "renders the status options as the << status_name (percent_complete_value %) >>" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_select_with_options(:status,
|
|
"open (0%)",
|
|
"in progress (50%)",
|
|
"complete (100%)")
|
|
end
|
|
end
|
|
end
|
|
|
|
it "disables the field that triggered the modal" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
work_edit_field = ProgressEditField.new(work_package_row, :estimatedTime)
|
|
|
|
work_edit_field.activate!
|
|
|
|
work_edit_field.expect_trigger_field_disabled
|
|
end
|
|
|
|
it "allows clicking on a field other than the one that triggered the modal " \
|
|
"and opens the modal with said field selected" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
work_edit_field = ProgressEditField.new(work_package_row, :estimatedTime)
|
|
remaining_work_edit_field = ProgressEditField.new(work_package_row, :remainingTime)
|
|
|
|
remaining_work_edit_field.activate!
|
|
remaining_work_edit_field.expect_modal_field_in_focus
|
|
remaining_work_edit_field.expect_trigger_field_disabled
|
|
|
|
work_edit_field.reactivate!
|
|
work_edit_field.expect_modal_field_in_focus
|
|
work_edit_field.expect_trigger_field_disabled
|
|
end
|
|
end
|
|
|
|
describe "Live-update edge cases" do
|
|
context "given work = 10h, remaining work = 4h, % complete = 60%" do
|
|
before { update_work_package_with(work_package, estimated_hours: 10.0, remaining_hours: 4.0) }
|
|
|
|
specify "Case 1: When I clear work it clears remaining work" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.set_values(work: "")
|
|
progress_popover.expect_values(remaining_work: "")
|
|
progress_popover.expect_hints(remaining_work: :cleared_because_work_is_empty,
|
|
percent_complete: nil)
|
|
end
|
|
|
|
specify "Case 2: when work is set to 12h, " \
|
|
"remaining work is automatically set to 6h " \
|
|
"and subsequently work is set to 14h, " \
|
|
"remaining work updates to 8h" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.set_values(work: "12")
|
|
progress_popover.expect_values(remaining_work: "6h")
|
|
progress_popover.expect_hints(remaining_work: { increased_by_delta_like_work: { delta: 2 } },
|
|
percent_complete: :derived)
|
|
|
|
progress_popover.set_values(work: "14")
|
|
progress_popover.expect_values(remaining_work: "8h")
|
|
progress_popover.expect_hints(remaining_work: { increased_by_delta_like_work: { delta: 4 } },
|
|
percent_complete: :derived)
|
|
end
|
|
|
|
specify "Case 3: when work is set to 2h, " \
|
|
"remaining work is automatically set to 0h, " \
|
|
"and work is subsequently set to 12h, " \
|
|
"remaining work is updated to 6h" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.set_values(work: "2")
|
|
progress_popover.expect_values(remaining_work: "0h")
|
|
progress_popover.expect_hints(remaining_work: { decreased_by_delta_like_work: { delta: -8 } },
|
|
percent_complete: :derived)
|
|
|
|
progress_popover.set_values(work: "12")
|
|
progress_popover.expect_values(remaining_work: "6h")
|
|
progress_popover.expect_hints(remaining_work: { increased_by_delta_like_work: { delta: 2 } },
|
|
percent_complete: :derived)
|
|
end
|
|
|
|
specify "Case 23-7: when remaining work or % complete are set, work never " \
|
|
"changes, instead remaining work and % complete are derived" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.set_values(remaining_work: "2h")
|
|
progress_popover.expect_values(work: "10h", percent_complete: "80%")
|
|
progress_popover.expect_hints(work: nil,
|
|
remaining_work: nil,
|
|
percent_complete: :derived)
|
|
|
|
progress_popover.set_values(percent_complete: "50%")
|
|
progress_popover.expect_values(work: "10h", remaining_work: "5h")
|
|
progress_popover.expect_hints(work: nil,
|
|
remaining_work: :derived,
|
|
percent_complete: nil)
|
|
|
|
progress_popover.set_values(remaining_work: "9h")
|
|
progress_popover.expect_values(work: "10h", percent_complete: "10%")
|
|
progress_popover.expect_hints(work: nil,
|
|
remaining_work: nil,
|
|
percent_complete: :derived)
|
|
end
|
|
|
|
# scenario from https://community.openproject.org/wp/57370
|
|
specify "Case 23-11: when work is cleared, and remaining work is set, " \
|
|
"then work is derived again" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
# clear work
|
|
progress_popover.set_values(work: "")
|
|
progress_popover.expect_values(work: "", remaining_work: "", percent_complete: "60%")
|
|
progress_popover.expect_hints(work: nil,
|
|
remaining_work: :cleared_because_work_is_empty,
|
|
percent_complete: nil)
|
|
|
|
# set remaining work
|
|
progress_popover.set_values(remaining_work: "8h")
|
|
# work is derived
|
|
progress_popover.expect_values(work: "20h", remaining_work: "8h", percent_complete: "60%")
|
|
progress_popover.expect_hints(work: :derived,
|
|
remaining_work: nil,
|
|
percent_complete: nil)
|
|
end
|
|
|
|
# scenario from https://community.openproject.org/wp/57370
|
|
specify "Case 23-14: when remaining work is cleared, and work is set, " \
|
|
"then remaining work is derived again" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
# clear work
|
|
progress_popover.set_values(remaining_work: "")
|
|
progress_popover.expect_values(work: "", remaining_work: "", percent_complete: "60%")
|
|
progress_popover.expect_hints(work: :cleared_because_remaining_work_is_empty,
|
|
remaining_work: nil,
|
|
percent_complete: nil)
|
|
|
|
# set work
|
|
progress_popover.set_values(work: "20h")
|
|
# => remaining work is derived
|
|
progress_popover.expect_values(work: "20h", remaining_work: "8h", percent_complete: "60%")
|
|
progress_popover.expect_hints(work: nil,
|
|
remaining_work: :derived,
|
|
percent_complete: nil)
|
|
end
|
|
|
|
# scenario from https://community.openproject.org/wp/57370
|
|
specify "Case 33-1: when work and % complete are cleared, and then work " \
|
|
"is set again then % complete is derived again" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
# clear work and % complete
|
|
progress_popover.set_values(work: "", percent_complete: "")
|
|
progress_popover.expect_values(work: "", remaining_work: "4h", percent_complete: "")
|
|
progress_popover.expect_hints(work: nil,
|
|
remaining_work: nil,
|
|
percent_complete: nil)
|
|
|
|
# set work
|
|
progress_popover.set_values(work: "20h")
|
|
# => % complete is derived
|
|
progress_popover.expect_values(work: "20h", remaining_work: "4h", percent_complete: "80%")
|
|
progress_popover.expect_hints(work: nil,
|
|
remaining_work: nil,
|
|
percent_complete: :derived)
|
|
end
|
|
|
|
# scenario from https://community.openproject.org/wp/57370
|
|
specify "Case 33-2: when remaining work and % complete are cleared, " \
|
|
"changing or clearing work does not modify % complete at all" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.set_values(remaining_work: "")
|
|
progress_popover.expect_values(work: "", remaining_work: "", percent_complete: "60%")
|
|
progress_popover.expect_hints(work: :cleared_because_remaining_work_is_empty)
|
|
|
|
progress_popover.set_values(percent_complete: "")
|
|
progress_popover.expect_values(work: "10h", remaining_work: "", percent_complete: "")
|
|
progress_popover.expect_hints(work: nil, remaining_work: nil, percent_complete: nil)
|
|
|
|
# partially deleting work value like when pressing backspace
|
|
progress_popover.set_values(work: "1")
|
|
progress_popover.expect_values(work: "1", remaining_work: "", percent_complete: "")
|
|
progress_popover.expect_hints(work: nil, remaining_work: nil, percent_complete: nil)
|
|
|
|
# completly clearing work value
|
|
progress_popover.set_values(work: "")
|
|
progress_popover.expect_values(work: "", remaining_work: "", percent_complete: "")
|
|
progress_popover.expect_hints(work: nil, remaining_work: nil, percent_complete: nil)
|
|
end
|
|
end
|
|
|
|
context "given work, remaining work, and % complete are all empty" do
|
|
before do
|
|
update_work_package_with(work_package, estimated_hours: nil, remaining_hours: nil, done_ratio: nil)
|
|
end
|
|
|
|
# scenario from https://community.openproject.org/wp/57370
|
|
specify "Case 20-4: when remaining work and % complete are both set, work " \
|
|
"is derived because it's initially empty" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.set_values(remaining_work: "2h", percent_complete: "50%")
|
|
progress_popover.expect_values(work: "4h")
|
|
progress_popover.expect_hints(work: :derived,
|
|
remaining_work: nil,
|
|
percent_complete: nil)
|
|
|
|
progress_popover.set_values(remaining_work: "10h")
|
|
progress_popover.expect_values(work: "20h")
|
|
progress_popover.expect_hints(work: :derived,
|
|
remaining_work: nil,
|
|
percent_complete: nil)
|
|
end
|
|
|
|
# scenario from https://community.openproject.org/wp/57370
|
|
specify "Case 30-1: when % complete is set, remaining work is set, and " \
|
|
"% complete is changed, then work is always derived" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.set_values(percent_complete: "40%")
|
|
progress_popover.expect_values(work: "", remaining_work: "", percent_complete: "40%")
|
|
progress_popover.expect_hints(work: nil,
|
|
remaining_work: nil,
|
|
percent_complete: nil)
|
|
|
|
progress_popover.set_values(remaining_work: "60h")
|
|
progress_popover.expect_values(work: "100h", remaining_work: "60h", percent_complete: "40%")
|
|
progress_popover.expect_hints(work: :derived,
|
|
remaining_work: nil,
|
|
percent_complete: nil)
|
|
|
|
progress_popover.set_values(percent_complete: "80%")
|
|
progress_popover.expect_values(work: "300h", remaining_work: "60h", percent_complete: "80%")
|
|
progress_popover.expect_hints(work: :derived,
|
|
remaining_work: nil,
|
|
percent_complete: nil)
|
|
end
|
|
end
|
|
|
|
context "in status-based mode",
|
|
with_settings: { work_package_done_ratio: "status" } do
|
|
before_all do
|
|
open_status_with_0p_done_ratio.update!(is_default: true)
|
|
|
|
create(:workflow,
|
|
type_id: type_task.id,
|
|
old_status: open_status_with_0p_done_ratio,
|
|
new_status: in_progress_status_with_50p_done_ratio,
|
|
role:)
|
|
create(:workflow,
|
|
type_id: type_task.id,
|
|
old_status: open_status_with_0p_done_ratio,
|
|
new_status: complete_status_with_100p_done_ratio,
|
|
role:)
|
|
end
|
|
|
|
context "given status has % complete to 50% and work is unset" do
|
|
before do
|
|
update_work_package_with(work_package, status: in_progress_status_with_50p_done_ratio,
|
|
estimated_hours: nil)
|
|
end
|
|
|
|
specify "when setting work, it updates remaining work and % complete" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_values(work: "", remaining_work: "")
|
|
progress_popover.expect_hints(work: nil, remaining_work: nil)
|
|
|
|
progress_popover.set_values(work: "10h")
|
|
progress_popover.expect_values(work: "10h", remaining_work: "5h")
|
|
progress_popover.expect_hints(work: nil, remaining_work: :derived)
|
|
end
|
|
end
|
|
|
|
context "given work = 10h" do
|
|
before do
|
|
update_work_package_with(work_package, estimated_hours: 10)
|
|
end
|
|
|
|
specify "when changing the status or work, it updates remaining work" do
|
|
visit_progress_query_displaying_work_package
|
|
|
|
progress_popover.open
|
|
progress_popover.expect_hints(work: nil, remaining_work: nil)
|
|
|
|
progress_popover.set_values(status: in_progress_status_with_50p_done_ratio)
|
|
progress_popover.expect_values(work: "10h", remaining_work: "5h")
|
|
progress_popover.expect_hints(work: nil, remaining_work: :derived)
|
|
|
|
progress_popover.set_values(work: "")
|
|
progress_popover.expect_values(work: "", remaining_work: "")
|
|
progress_popover.expect_hints(work: nil, remaining_work: :cleared_because_work_is_empty)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|