From a8a6d112da5bddb378894df98d63eb043cca36fb Mon Sep 17 00:00:00 2001 From: Eric Schubert Date: Fri, 18 Oct 2024 14:02:17 +0200 Subject: [PATCH 1/2] [#58426] add feature spec for custom fields of type hierarchy - https://community.openproject.org/work_packages/58426 - add a couple of test selectors - add page objects --- .../delete_item_dialog_component.html.erb | 4 +- .../hierarchy/delete_item_dialog_component.rb | 1 + .../hierarchy/item_component.html.erb | 2 +- .../hierarchy/items_component.html.erb | 5 +- .../new_item_form_component.html.erb | 1 + .../custom_fields/details_component.html.erb | 11 +- .../custom_fields/details_component.rb | 8 ++ app/views/custom_fields/_form.html.erb | 5 +- config/locales/en.yml | 2 +- docker-compose.yml | 2 + .../custom_fields/link_custom_field_spec.rb | 2 +- .../custom_fields/user_custom_field_spec.rb | 2 +- .../custom_fields/activate_in_project_spec.rb | 4 +- .../custom_fields/create_bool_spec.rb | 4 +- .../custom_fields/create_date_spec.rb | 4 +- .../custom_fields/create_float_spec.rb | 4 +- .../features/custom_fields/create_int_spec.rb | 4 +- .../custom_fields/create_long_text_spec.rb | 4 +- .../custom_fields/custom_fields_spec.rb | 4 +- .../hierarchy_custom_field_spec.rb | 131 ++++++++++++++++++ .../custom_fields/reorder_options_spec.rb | 4 +- .../types/activate_in_project_spec.rb | 2 +- .../pages/custom_fields/hierarchy_page.rb | 117 ++++++++++++++++ .../support/pages/custom_fields/index_page.rb | 66 +++++++++ .../new_page.rb} | 36 ++--- 25 files changed, 374 insertions(+), 55 deletions(-) create mode 100644 spec/features/custom_fields/hierarchy_custom_field_spec.rb create mode 100644 spec/support/pages/custom_fields/hierarchy_page.rb create mode 100644 spec/support/pages/custom_fields/index_page.rb rename spec/support/pages/{custom_fields.rb => custom_fields/new_page.rb} (66%) diff --git a/app/components/admin/custom_fields/hierarchy/delete_item_dialog_component.html.erb b/app/components/admin/custom_fields/hierarchy/delete_item_dialog_component.html.erb index 3ddbcb1ccb9b..1d4a054a67f4 100644 --- a/app/components/admin/custom_fields/hierarchy/delete_item_dialog_component.html.erb +++ b/app/components/admin/custom_fields/hierarchy/delete_item_dialog_component.html.erb @@ -28,7 +28,9 @@ See COPYRIGHT and LICENSE files for more details. ++#%> <%= - render(Primer::Alpha::Dialog.new(id: DIALOG_ID, title: "Delete item")) do |dialog| + render(Primer::Alpha::Dialog.new(id: DIALOG_ID, + title: "Delete item", + data: { test_selector: TEST_SELECTOR })) do |dialog| dialog.with_header(variant: :large) dialog.with_body do "Are you sure you want to delete this item from the current hierarchy level?" diff --git a/app/components/admin/custom_fields/hierarchy/delete_item_dialog_component.rb b/app/components/admin/custom_fields/hierarchy/delete_item_dialog_component.rb index e7b9307bcb4a..851116a4ee48 100644 --- a/app/components/admin/custom_fields/hierarchy/delete_item_dialog_component.rb +++ b/app/components/admin/custom_fields/hierarchy/delete_item_dialog_component.rb @@ -35,6 +35,7 @@ class DeleteItemDialogComponent < ApplicationComponent include OpTurbo::Streamable DIALOG_ID = "op-hierarchy-item--deletion-confirmation" + TEST_SELECTOR = "op-custom-fields--delete-item-dialog" def initialize(custom_field:, hierarchy_item:) super diff --git a/app/components/admin/custom_fields/hierarchy/item_component.html.erb b/app/components/admin/custom_fields/hierarchy/item_component.html.erb index a1f989219537..dec37dd18bd6 100644 --- a/app/components/admin/custom_fields/hierarchy/item_component.html.erb +++ b/app/components/admin/custom_fields/hierarchy/item_component.html.erb @@ -28,7 +28,7 @@ See COPYRIGHT and LICENSE files for more details. ++#%> <%= - component_wrapper do + component_wrapper(data: { test_selector: "op-custom-fields--hierarchy-item" }) do flex_layout(align_items: :center, justify_content: :space_between) do |item_container| item_container.with_column(flex_layout: true) do |item_information| item_information.with_column(mr: 2) do diff --git a/app/components/admin/custom_fields/hierarchy/items_component.html.erb b/app/components/admin/custom_fields/hierarchy/items_component.html.erb index f729fcbe7f81..c4f8937c6acb 100644 --- a/app/components/admin/custom_fields/hierarchy/items_component.html.erb +++ b/app/components/admin/custom_fields/hierarchy/items_component.html.erb @@ -32,7 +32,10 @@ See COPYRIGHT and LICENSE files for more details. flex_layout do |container| if items.empty? && !show_new_item_form? container.with_row(mb: 3) do - render Primer::Beta::Blankslate.new(border: true) do |component| + render Primer::Beta::Blankslate.new( + border: true, + test_selector: "op-custom-fields--hierarchy-items-blankslate" + ) do |component| component.with_visual_icon(icon: "list-ordered") component.with_heading(tag: :h3).with_content(I18n.t("custom_fields.admin.items.blankslate.title")) component.with_description { I18n.t("custom_fields.admin.items.blankslate.description") } diff --git a/app/components/admin/custom_fields/hierarchy/new_item_form_component.html.erb b/app/components/admin/custom_fields/hierarchy/new_item_form_component.html.erb index 289c9eafd63e..312bb9278ecd 100644 --- a/app/components/admin/custom_fields/hierarchy/new_item_form_component.html.erb +++ b/app/components/admin/custom_fields/hierarchy/new_item_form_component.html.erb @@ -31,6 +31,7 @@ See COPYRIGHT and LICENSE files for more details. primer_form_with( url: custom_field_items_path(@custom_field), method: :post, + data: { test_selector: "op-custom-fields--new-item-form" } ) do |f| render(CustomFields::Hierarchy::NewItemForm.new(f, custom_field: @custom_field, label: @label, short: @short)) end diff --git a/app/components/custom_fields/details_component.html.erb b/app/components/custom_fields/details_component.html.erb index 91e966f66f9f..c4e0409b4f2b 100644 --- a/app/components/custom_fields/details_component.html.erb +++ b/app/components/custom_fields/details_component.html.erb @@ -1,9 +1,14 @@ <%= component_wrapper do flex_layout do |content| - content.with_row(mb: 3) do - render Primer::Alpha::Banner.new(scheme: :default, icon: :info, dismiss_scheme: :hide) do - I18n.t("custom_fields.admin.notice.remember_items_and_projects") + if has_no_items_or_projects? + content.with_row(mb: 3) do + render Primer::Alpha::Banner.new(scheme: :default, + icon: :info, + dismiss_scheme: :hide, + test_selector: "op-custom-fields--new-hierarchy-banner") do + I18n.t("custom_fields.admin.notice.remember_items_and_projects") + end end end diff --git a/app/components/custom_fields/details_component.rb b/app/components/custom_fields/details_component.rb index ba38995317fe..5642117e1d28 100644 --- a/app/components/custom_fields/details_component.rb +++ b/app/components/custom_fields/details_component.rb @@ -32,5 +32,13 @@ module CustomFields class DetailsComponent < ApplicationComponent include OpPrimer::ComponentHelpers include OpTurbo::Streamable + + alias_method :custom_field, :model + + def has_no_items_or_projects? + custom_field.field_format_hierarchy? && + custom_field.hierarchy_root.children.empty? && + custom_field.projects.empty? + end end end diff --git a/app/views/custom_fields/_form.html.erb b/app/views/custom_fields/_form.html.erb index 6480748f59c5..b85a490efcdd 100644 --- a/app/views/custom_fields/_form.html.erb +++ b/app/views/custom_fields/_form.html.erb @@ -37,7 +37,10 @@ See COPYRIGHT and LICENSE files for more details. data-admin--custom-fields-format-config-value="<%= OpenProject::CustomFieldFormatDependent.stimulus_config %>" >
- <%= f.text_field :name, required: true, container_class: '-middle' %> + <%= f.text_field :name, + required: true, + container_class: "-middle", + "data-test-selector": "op-custom-fields--new-custom-field-name" %>
<% if @custom_field.type == 'ProjectCustomField' %>
diff --git a/config/locales/en.yml b/config/locales/en.yml index 8e6d1760a2cf..e9929d2ab022 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -245,10 +245,10 @@ en: heading: For all projects description: This custom field is enabled in all projects since the "For all projects" option is checked. It cannot be deactivated for individual projects. items: + actions: "Item actions" blankslate: title: "Your list of items is empty" description: "Start by adding items to the custom field of type hierarchy. Each item can be used to create a hierarchy bellow it. To navigate and create sub-items inside a hierarchy click on the created item." - actions: "Item actions" placeholder: label: "Item label" short: "Short name" diff --git a/docker-compose.yml b/docker-compose.yml index 5c3e420c8555..67af270b8c7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -131,6 +131,8 @@ services: environment: PROXY_HOSTNAME: backend-test CHROME_BIN: chromium + FE_PORT: 4200 + FE_HOST: frontend-test networks: - testing diff --git a/spec/features/admin/custom_fields/link_custom_field_spec.rb b/spec/features/admin/custom_fields/link_custom_field_spec.rb index f2cd19839e4a..a98b3ce64dae 100644 --- a/spec/features/admin/custom_fields/link_custom_field_spec.rb +++ b/spec/features/admin/custom_fields/link_custom_field_spec.rb @@ -30,7 +30,7 @@ RSpec.describe "Link custom fields edit", :js, :with_cuprite do shared_let(:admin) { create(:admin) } - let(:cf_page) { Pages::CustomFields.new } + let(:cf_page) { Pages::CustomFields::IndexPage.new } before do login_as(admin) diff --git a/spec/features/admin/custom_fields/user_custom_field_spec.rb b/spec/features/admin/custom_fields/user_custom_field_spec.rb index 7d45a5f6655b..58a76a7363cf 100644 --- a/spec/features/admin/custom_fields/user_custom_field_spec.rb +++ b/spec/features/admin/custom_fields/user_custom_field_spec.rb @@ -30,7 +30,7 @@ RSpec.describe "User custom fields edit", :js, :with_cuprite do shared_let(:admin) { create(:admin) } - let(:cf_page) { Pages::CustomFields.new } + let(:cf_page) { Pages::CustomFields::IndexPage.new } before do login_as(admin) diff --git a/spec/features/custom_fields/activate_in_project_spec.rb b/spec/features/custom_fields/activate_in_project_spec.rb index ef4c14a52b1c..796b0eef3b81 100644 --- a/spec/features/custom_fields/activate_in_project_spec.rb +++ b/spec/features/custom_fields/activate_in_project_spec.rb @@ -27,11 +27,11 @@ #++ require "spec_helper" -require "support/pages/custom_fields" +require "support/pages/custom_fields/index_page" RSpec.describe "custom fields", :js, :with_cuprite do let(:user) { create(:admin) } - let(:cf_page) { Pages::CustomFields.new } + let(:cf_page) { Pages::CustomFields::IndexPage.new } let(:for_all_cf) { create(:list_wp_custom_field, is_for_all: true) } let(:project_specific_cf) { create(:integer_wp_custom_field) } let(:work_package) do diff --git a/spec/features/custom_fields/create_bool_spec.rb b/spec/features/custom_fields/create_bool_spec.rb index 695123dbe73a..26a97def43fd 100644 --- a/spec/features/custom_fields/create_bool_spec.rb +++ b/spec/features/custom_fields/create_bool_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" -require "support/pages/custom_fields" +require "support/pages/custom_fields/index_page" RSpec.describe "custom fields", :js, :with_cuprite do let(:user) { create(:admin) } - let(:cf_page) { Pages::CustomFields.new } + let(:cf_page) { Pages::CustomFields::IndexPage.new } before do login_as user diff --git a/spec/features/custom_fields/create_date_spec.rb b/spec/features/custom_fields/create_date_spec.rb index c2f6eba5fbe0..957d5626ff89 100644 --- a/spec/features/custom_fields/create_date_spec.rb +++ b/spec/features/custom_fields/create_date_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" -require "support/pages/custom_fields" +require "support/pages/custom_fields/index_page" RSpec.describe "custom fields", :js, :with_cuprite do let(:user) { create(:admin) } - let(:cf_page) { Pages::CustomFields.new } + let(:cf_page) { Pages::CustomFields::IndexPage.new } before do login_as user diff --git a/spec/features/custom_fields/create_float_spec.rb b/spec/features/custom_fields/create_float_spec.rb index 71333b4ec28d..74a97b6e5a77 100644 --- a/spec/features/custom_fields/create_float_spec.rb +++ b/spec/features/custom_fields/create_float_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" -require "support/pages/custom_fields" +require "support/pages/custom_fields/index_page" RSpec.describe "custom fields", :js, :with_cuprite do let(:user) { create(:admin) } - let(:cf_page) { Pages::CustomFields.new } + let(:cf_page) { Pages::CustomFields::IndexPage.new } before do login_as user diff --git a/spec/features/custom_fields/create_int_spec.rb b/spec/features/custom_fields/create_int_spec.rb index 171825f178ef..951d5138a3b5 100644 --- a/spec/features/custom_fields/create_int_spec.rb +++ b/spec/features/custom_fields/create_int_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" -require "support/pages/custom_fields" +require "support/pages/custom_fields/index_page" RSpec.describe "custom fields", :js, :with_cuprite do let(:user) { create(:admin) } - let(:cf_page) { Pages::CustomFields.new } + let(:cf_page) { Pages::CustomFields::IndexPage.new } before do login_as user diff --git a/spec/features/custom_fields/create_long_text_spec.rb b/spec/features/custom_fields/create_long_text_spec.rb index 8aee873dcc70..6a207652feb4 100644 --- a/spec/features/custom_fields/create_long_text_spec.rb +++ b/spec/features/custom_fields/create_long_text_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" -require "support/pages/custom_fields" +require "support/pages/custom_fields/index_page" RSpec.describe "custom fields", :js do let(:user) { create(:admin) } - let(:cf_page) { Pages::CustomFields.new } + let(:cf_page) { Pages::CustomFields::IndexPage.new } let(:editor) { Components::WysiwygEditor.new "#custom_field_form" } let(:type) { create(:type_task) } let!(:project) { create(:project, enabled_module_names: %i[work_package_tracking], types: [type]) } diff --git a/spec/features/custom_fields/custom_fields_spec.rb b/spec/features/custom_fields/custom_fields_spec.rb index 32eafe20792b..8493345e9cc4 100644 --- a/spec/features/custom_fields/custom_fields_spec.rb +++ b/spec/features/custom_fields/custom_fields_spec.rb @@ -1,9 +1,9 @@ require "spec_helper" -require "support/pages/custom_fields" +require "support/pages/custom_fields/index_page" RSpec.describe "custom fields", :js, :with_cuprite do let(:user) { create(:admin) } - let(:cf_page) { Pages::CustomFields.new } + let(:cf_page) { Pages::CustomFields::IndexPage.new } before do login_as user diff --git a/spec/features/custom_fields/hierarchy_custom_field_spec.rb b/spec/features/custom_fields/hierarchy_custom_field_spec.rb new file mode 100644 index 000000000000..c524e8263c13 --- /dev/null +++ b/spec/features/custom_fields/hierarchy_custom_field_spec.rb @@ -0,0 +1,131 @@ +# 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" +require "support/pages/custom_fields/hierarchy_page" + +RSpec.describe "custom fields of type hierarchy", :js, :with_cuprite do + let(:user) { create(:admin) } + let(:custom_field_index_page) { Pages::CustomFields::IndexPage.new } + let(:new_custom_field_page) { Pages::CustomFields::NewPage.new } + let(:hierarchy_page) { Pages::CustomFields::HierarchyPage.new } + + it "lets you create, update and delete a custom field of type hierarchy", + with_flag: { custom_field_of_type_hierarchy: true } do + login_as user + + # First, we create a new custom field of type hierarchy + custom_field_index_page.visit! + + click_on "New custom field" + new_custom_field_page.expect_current_path + + hierarchy_name = "Stormtrooper Organisation" + fill_in "Name", with: hierarchy_name + select "Hierarchy", from: "Format" + click_on "Save" + + custom_field_index_page.expect_current_path("tab=WorkPackageCustomField") + expect(page).to have_list_item(hierarchy_name) + + # The next step is to enter the custom field and work on it + CustomField.find_by(name: hierarchy_name).tap do |custom_field| + hierarchy_page.add_custom_field_state(custom_field) + end + + click_on hierarchy_name + hierarchy_page.expect_current_path + + hierarchy_page.expect_empty_items_banner(visible: true) + hierarchy_page.expect_header_text(hierarchy_name) + + # Changing the name is possible + hierarchy_name = "Imperial Organisation" + fill_in "Name", with: "", fill_options: { clear: :backspace } + fill_in "Name", with: hierarchy_name + click_on "Save" + hierarchy_page.expect_header_text(hierarchy_name) + + # Now we want to create hierarchy items + hierarchy_page.switch_tab "Items" + hierarchy_page.expect_current_path + hierarchy_page.expect_blank_slate(visible: true) + + click_on "Item" + hierarchy_page.expect_blank_slate(visible: false) + fill_in "Label", with: "Stormtroopers" + fill_in "Short", with: "ST" + click_on "Save" + hierarchy_page.expect_blank_slate(visible: false) + hierarchy_page.expect_items_count(1) + hierarchy_page.expect_hierarchy_item(label: "Stormtroopers", short: "(ST)") + + # Is the form cancelable? + click_on "Item" + hierarchy_page.expect_inline_form(visible: true) + fill_in "Label", with: "Dark Troopers" + click_on "Cancel" + hierarchy_page.expect_inline_form(visible: false) + hierarchy_page.expect_items_count(1) + hierarchy_page.expect_hierarchy_item(label: "Dark Troopers", visible: false) + + # What happens if I add a wrong item? + click_on "Item" + fill_in "Label", with: "Phoenix Squad" + click_on "Save" + hierarchy_page.expect_items_count(2) + hierarchy_page.expect_hierarchy_item(label: "Phoenix Squad", visible: true) + hierarchy_page.open_action_menu_for("Phoenix Squad") + click_on "Delete" + hierarchy_page.expect_deletion_dialog(visible: true) + click_on "Delete" + hierarchy_page.expect_deletion_dialog(visible: false) + hierarchy_page.expect_items_count(1) + hierarchy_page.expect_hierarchy_item(label: "Phoenix Squad", visible: false) + + # Can I cancel the deletion? + hierarchy_page.open_action_menu_for("Stormtroopers") + click_on "Delete" + hierarchy_page.expect_deletion_dialog(visible: true) + click_on "Cancel" + hierarchy_page.expect_deletion_dialog(visible: false) + hierarchy_page.expect_hierarchy_item(label: "Stormtroopers", visible: true) + + # And is the blue banner gone, now that I have added some items? + hierarchy_page.switch_tab "Details" + hierarchy_page.expect_empty_items_banner(visible: false) + + # Finally, we delete the custom field ... I'm done with this ... + custom_field_index_page.visit! + expect(page).to have_list_item(hierarchy_name) + within("tr", text: hierarchy_name) { accept_prompt { click_on "Delete" } } + expect(page).to have_no_text(hierarchy_name) + end +end diff --git a/spec/features/custom_fields/reorder_options_spec.rb b/spec/features/custom_fields/reorder_options_spec.rb index 1ff0bc2e5416..796151433aaf 100644 --- a/spec/features/custom_fields/reorder_options_spec.rb +++ b/spec/features/custom_fields/reorder_options_spec.rb @@ -1,5 +1,5 @@ require "spec_helper" -require "support/pages/custom_fields" +require "support/pages/custom_fields/index_page" def get_possible_values(amount) (1..amount).to_a.map { |x| "PREFIX #{x}" } @@ -15,7 +15,7 @@ def get_possible_values_reordered(amount) RSpec.describe "Reordering custom options of a list custom field", :js do let(:user) { create(:admin) } - let(:cf_page) { Pages::CustomFields.new } + let(:cf_page) { Pages::CustomFields::IndexPage.new } let!(:custom_field) do create( diff --git a/spec/features/types/activate_in_project_spec.rb b/spec/features/types/activate_in_project_spec.rb index 258ffeb41904..a236e89a9f32 100644 --- a/spec/features/types/activate_in_project_spec.rb +++ b/spec/features/types/activate_in_project_spec.rb @@ -27,7 +27,7 @@ #++ require "spec_helper" -require "support/pages/custom_fields" +require "support/pages/custom_fields/index_page" RSpec.describe "types", :js, :with_cuprite do let(:user) do diff --git a/spec/support/pages/custom_fields/hierarchy_page.rb b/spec/support/pages/custom_fields/hierarchy_page.rb new file mode 100644 index 000000000000..fdef8bbd9da3 --- /dev/null +++ b/spec/support/pages/custom_fields/hierarchy_page.rb @@ -0,0 +1,117 @@ +# 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 "support/pages/page" + +module Pages + module CustomFields + class HierarchyPage < Page + def path + case @tab + when "items" + "/custom_fields/#{@custom_field.id}/items" + when "projects" + "/custom_fields/#{@custom_field.id}/projects" + else + "/custom_fields/#{@custom_field.id}/edit" + end + end + + def add_custom_field_state(custom_field) + @custom_field = custom_field + end + + def switch_tab(tab) + @tab = tab.downcase + + within_test_selector("custom_field_detail_header") do + click_on "Items" + end + end + + def expect_empty_items_banner(visible:) + if visible + expect(page).to have_test_selector("op-custom-fields--new-hierarchy-banner") + else + expect(page).not_to have_test_selector("op-custom-fields--new-hierarchy-banner") + end + end + + def expect_header_text(text) + expect(page).to have_css(".PageHeader-title", text: text) + end + + def expect_blank_slate(visible:) + if visible + expect(page).to have_test_selector("op-custom-fields--hierarchy-items-blankslate") + else + expect(page).not_to have_test_selector("op-custom-fields--hierarchy-items-blankslate") + end + end + + def expect_items_count(count) + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", count:) + end + + def expect_hierarchy_item(label:, short: nil, visible: true) + if visible + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", text: label) + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", text: short) unless short.nil? + else + expect(page).not_to have_test_selector("op-custom-fields--hierarchy-item", text: label) + end + end + + def expect_inline_form(visible:) + if visible + expect(page).to have_test_selector("op-custom-fields--new-item-form") + else + expect(page).not_to have_test_selector("op-custom-fields--new-item-form") + end + end + + def expect_deletion_dialog(visible:) + if visible + expect(page).to have_test_selector("op-custom-fields--delete-item-dialog") + else + expect(page).not_to have_test_selector("op-custom-fields--delete-item-dialog") + end + end + + def open_action_menu_for(label) + within_test_selector("op-custom-fields--hierarchy-item", text: label) do + within_test_selector("op-hierarchy-item--action-menu") do + click_on + end + end + end + end + end +end diff --git a/spec/support/pages/custom_fields/index_page.rb b/spec/support/pages/custom_fields/index_page.rb new file mode 100644 index 000000000000..d54fbc18f7f5 --- /dev/null +++ b/spec/support/pages/custom_fields/index_page.rb @@ -0,0 +1,66 @@ +#-- 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 "support/pages/page" + +module Pages + module CustomFields + class IndexPage < Page + def path + "/custom_fields" + end + + def visit_tab(name) + visit! + within_test_selector("custom-fields--tab-nav") do + click_on name.to_s + end + end + + def select_format(label) + select label, from: "custom_field_field_format" + end + + def set_name(name) + find_by_id("custom_field_name").set name + end + + def set_default_value(value) + fill_in "custom_field[default_value]", with: value + end + + def set_all_projects(value) + find_by_id("custom_field_is_for_all").set value + end + + def has_form_element?(name) + page.has_css? "label.form--label", text: name + end + end + end +end diff --git a/spec/support/pages/custom_fields.rb b/spec/support/pages/custom_fields/new_page.rb similarity index 66% rename from spec/support/pages/custom_fields.rb rename to spec/support/pages/custom_fields/new_page.rb index cb4501bf371a..0944231c530e 100644 --- a/spec/support/pages/custom_fields.rb +++ b/spec/support/pages/custom_fields/new_page.rb @@ -29,36 +29,16 @@ require "support/pages/page" module Pages - class CustomFields < Page - def path - "/custom_fields" - end - - def visit_tab(name) - visit! - within_test_selector("custom-fields--tab-nav") do - click_link name.to_s + module CustomFields + class NewPage < Page + def path + "/custom_fields/new?type=#{@type}" end - end - - def select_format(label) - select label, from: "custom_field_field_format" - end - - def set_name(name) - find_by_id("custom_field_name").set name - end - - def set_default_value(value) - fill_in "custom_field[default_value]", with: value - end - def set_all_projects(value) - find_by_id("custom_field_is_for_all").set value - end - - def has_form_element?(name) - page.has_css? "label.form--label", text: name + def initialize(type = "WorkPackageCustomField") + super() + @type = type + end end end end From 485ea7f6e9600ceb9a091d02348c2a41b17a6bcf Mon Sep 17 00:00:00 2001 From: Eric Schubert Date: Fri, 25 Oct 2024 12:53:32 +0200 Subject: [PATCH 2/2] [#58426] add more structure to feature spec - add regions to different steps of the feature spec - removed expectations from page object --- .../hierarchy_custom_field_spec.rb | 84 ++++++++++++------- .../pages/custom_fields/hierarchy_page.rb | 49 ----------- 2 files changed, 55 insertions(+), 78 deletions(-) diff --git a/spec/features/custom_fields/hierarchy_custom_field_spec.rb b/spec/features/custom_fields/hierarchy_custom_field_spec.rb index c524e8263c13..fe961ae75a2e 100644 --- a/spec/features/custom_fields/hierarchy_custom_field_spec.rb +++ b/spec/features/custom_fields/hierarchy_custom_field_spec.rb @@ -29,7 +29,6 @@ #++ require "spec_helper" -require "support/pages/custom_fields/hierarchy_page" RSpec.describe "custom fields of type hierarchy", :js, :with_cuprite do let(:user) { create(:admin) } @@ -41,7 +40,8 @@ with_flag: { custom_field_of_type_hierarchy: true } do login_as user - # First, we create a new custom field of type hierarchy + # region CustomField creation + custom_field_index_page.visit! click_on "New custom field" @@ -55,7 +55,10 @@ custom_field_index_page.expect_current_path("tab=WorkPackageCustomField") expect(page).to have_list_item(hierarchy_name) - # The next step is to enter the custom field and work on it + # endregion + + # region Edit the details of the custom field + CustomField.find_by(name: hierarchy_name).tap do |custom_field| hierarchy_page.add_custom_field_state(custom_field) end @@ -63,69 +66,92 @@ click_on hierarchy_name hierarchy_page.expect_current_path - hierarchy_page.expect_empty_items_banner(visible: true) - hierarchy_page.expect_header_text(hierarchy_name) + expect(page).to have_test_selector("op-custom-fields--new-hierarchy-banner") + expect(page).to have_css(".PageHeader-title", text: hierarchy_name) - # Changing the name is possible + # Now, that was the wrong name, so I can change it to the correct one hierarchy_name = "Imperial Organisation" fill_in "Name", with: "", fill_options: { clear: :backspace } fill_in "Name", with: hierarchy_name click_on "Save" - hierarchy_page.expect_header_text(hierarchy_name) + expect(page).to have_css(".PageHeader-title", text: hierarchy_name) + + # endregion - # Now we want to create hierarchy items + # region Adding items to the hierarchy + + # Now we want to create our first hierarchy items hierarchy_page.switch_tab "Items" hierarchy_page.expect_current_path - hierarchy_page.expect_blank_slate(visible: true) + expect(page).to have_test_selector("op-custom-fields--hierarchy-items-blankslate") click_on "Item" - hierarchy_page.expect_blank_slate(visible: false) + expect(page).not_to have_test_selector("op-custom-fields--hierarchy-items-blankslate") fill_in "Label", with: "Stormtroopers" fill_in "Short", with: "ST" click_on "Save" - hierarchy_page.expect_blank_slate(visible: false) - hierarchy_page.expect_items_count(1) - hierarchy_page.expect_hierarchy_item(label: "Stormtroopers", short: "(ST)") + expect(page).not_to have_test_selector("op-custom-fields--hierarchy-items-blankslate") + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", count: 1) + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", text: "Stormtroopers") + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", text: "(ST)") + + # And the inline form should still be there + expect(page).to have_test_selector("op-custom-fields--new-item-form") + + # Can I add the same item again? + fill_in "Label", with: "Stormtroopers" + click_on "Save" + within_test_selector("op-custom-fields--new-item-form") do + expect(page).to have_css(".FormControl-inlineValidation", text: "Label must be unique within the same hierarchy level") + end # Is the form cancelable? - click_on "Item" - hierarchy_page.expect_inline_form(visible: true) fill_in "Label", with: "Dark Troopers" click_on "Cancel" - hierarchy_page.expect_inline_form(visible: false) - hierarchy_page.expect_items_count(1) - hierarchy_page.expect_hierarchy_item(label: "Dark Troopers", visible: false) + expect(page).not_to have_test_selector("op-custom-fields--new-item-form") + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", count: 1) + expect(page).not_to have_test_selector("op-custom-fields--hierarchy-item", text: "Dark Troopers") + + # endregion - # What happens if I add a wrong item? + # region Deleting items from the hierarchy + + # What happens if I added a wrong item? click_on "Item" fill_in "Label", with: "Phoenix Squad" click_on "Save" - hierarchy_page.expect_items_count(2) - hierarchy_page.expect_hierarchy_item(label: "Phoenix Squad", visible: true) + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", count: 2) + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", text: "Phoenix Squad") hierarchy_page.open_action_menu_for("Phoenix Squad") click_on "Delete" - hierarchy_page.expect_deletion_dialog(visible: true) + expect(page).to have_test_selector("op-custom-fields--delete-item-dialog") click_on "Delete" - hierarchy_page.expect_deletion_dialog(visible: false) - hierarchy_page.expect_items_count(1) - hierarchy_page.expect_hierarchy_item(label: "Phoenix Squad", visible: false) + expect(page).not_to have_test_selector("op-custom-fields--delete-item-dialog") + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", count: 1) + expect(page).not_to have_test_selector("op-custom-fields--hierarchy-item", text: "Phoenix Squad") # Can I cancel the deletion? hierarchy_page.open_action_menu_for("Stormtroopers") click_on "Delete" - hierarchy_page.expect_deletion_dialog(visible: true) + expect(page).to have_test_selector("op-custom-fields--delete-item-dialog") click_on "Cancel" - hierarchy_page.expect_deletion_dialog(visible: false) - hierarchy_page.expect_hierarchy_item(label: "Stormtroopers", visible: true) + expect(page).not_to have_test_selector("op-custom-fields--delete-item-dialog") + expect(page).to have_test_selector("op-custom-fields--hierarchy-item", text: "Stormtroopers") + + # endregion + + # region Status check and cleanup # And is the blue banner gone, now that I have added some items? hierarchy_page.switch_tab "Details" - hierarchy_page.expect_empty_items_banner(visible: false) + expect(page).not_to have_test_selector("op-custom-fields--new-hierarchy-banner") # Finally, we delete the custom field ... I'm done with this ... custom_field_index_page.visit! expect(page).to have_list_item(hierarchy_name) within("tr", text: hierarchy_name) { accept_prompt { click_on "Delete" } } expect(page).to have_no_text(hierarchy_name) + + # endregion end end diff --git a/spec/support/pages/custom_fields/hierarchy_page.rb b/spec/support/pages/custom_fields/hierarchy_page.rb index fdef8bbd9da3..4b349b224c99 100644 --- a/spec/support/pages/custom_fields/hierarchy_page.rb +++ b/spec/support/pages/custom_fields/hierarchy_page.rb @@ -56,55 +56,6 @@ def switch_tab(tab) end end - def expect_empty_items_banner(visible:) - if visible - expect(page).to have_test_selector("op-custom-fields--new-hierarchy-banner") - else - expect(page).not_to have_test_selector("op-custom-fields--new-hierarchy-banner") - end - end - - def expect_header_text(text) - expect(page).to have_css(".PageHeader-title", text: text) - end - - def expect_blank_slate(visible:) - if visible - expect(page).to have_test_selector("op-custom-fields--hierarchy-items-blankslate") - else - expect(page).not_to have_test_selector("op-custom-fields--hierarchy-items-blankslate") - end - end - - def expect_items_count(count) - expect(page).to have_test_selector("op-custom-fields--hierarchy-item", count:) - end - - def expect_hierarchy_item(label:, short: nil, visible: true) - if visible - expect(page).to have_test_selector("op-custom-fields--hierarchy-item", text: label) - expect(page).to have_test_selector("op-custom-fields--hierarchy-item", text: short) unless short.nil? - else - expect(page).not_to have_test_selector("op-custom-fields--hierarchy-item", text: label) - end - end - - def expect_inline_form(visible:) - if visible - expect(page).to have_test_selector("op-custom-fields--new-item-form") - else - expect(page).not_to have_test_selector("op-custom-fields--new-item-form") - end - end - - def expect_deletion_dialog(visible:) - if visible - expect(page).to have_test_selector("op-custom-fields--delete-item-dialog") - else - expect(page).not_to have_test_selector("op-custom-fields--delete-item-dialog") - end - end - def open_action_menu_for(label) within_test_selector("op-custom-fields--hierarchy-item", text: label) do within_test_selector("op-hierarchy-item--action-menu") do