Merge pull request #19134 from opf/bug/64583-attribute-help-texts-missing-project-attributes-dialog

[#64583] Attribute help texts missing in Project Overview > Project attributes dialog
This commit is contained in:
Henriette Darge
2025-06-17 08:04:51 +02:00
committed by GitHub
19 changed files with 1323 additions and 5 deletions
@@ -41,6 +41,10 @@ class CustomFields::Inputs::Base::Input < ApplicationForm
@options = options
end
def model
@object
end
def input_attributes
base_input_attributes.merge(
{
+5 -2
View File
@@ -27,6 +27,8 @@
#++
module CustomFields::Inputs::Base::Utils
delegate :attribute_name, to: :@custom_field
def base_input_attributes
{
name:,
@@ -34,7 +36,8 @@ module CustomFields::Inputs::Base::Utils
value:,
required: required?,
invalid: invalid?,
validation_message:
validation_message:,
help_text_options: { attribute_name: }
}
end
@@ -55,7 +58,7 @@ module CustomFields::Inputs::Base::Utils
end
def qa_field_name
@custom_field.attribute_name(:kebab_case)
attribute_name(:kebab_case)
end
# used within autocompleter inputs
@@ -5,6 +5,22 @@ module Primer
module Forms
module Dsl
module InputMethods
def multi(**, &)
super(**decorate_options(**), &)
end
def check_box(**, &)
super(**decorate_options(**), &)
end
def radio_button_group(**, &)
super(**decorate_options(**), &)
end
def check_box_group(**, &)
super(**decorate_options(**), &)
end
def autocompleter(**, &)
add_input AutocompleterInput.new(builder:, form:, **decorate_options(**), &)
end
@@ -45,9 +61,10 @@ module Primer
add_input WorkPackageAutocompleterInput.new(builder:, form:, **decorate_options(**), &)
end
def decorate_options(include_help_text: true, **options)
if include_help_text && supports_help_texts?(builder.object)
options[:label] = form.wrap_attribute_label_with_help_text(options[:label], options[:name])
def decorate_options(include_help_text: true, help_text_options: {}, **options)
if include_help_text && supports_help_texts?(form.model)
attribute_name = help_text_options[:attribute_name] || options[:name]
options[:label] = form.wrap_attribute_label_with_help_text(options[:label], attribute_name)
end
options
end
@@ -0,0 +1,247 @@
# 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_relative "../shared_context"
RSpec.describe "Edit project custom fields on project overview page", "attribute help texts", :js, :selenium do
include_context "with seeded projects, members and project custom fields"
include API::V3::Utilities::PathHelper
let(:overview_page) { Pages::Projects::Show.new(project) }
let(:edit_dialog) { Components::Projects::ProjectCustomFields::EditDialog.new(project, section) }
before do
login_as member_with_project_attributes_edit_permissions
overview_page.visit_page
end
context "for input fields section" do
let(:section) { section_for_input_fields }
context "without attribute help texts defined" do
before do
overview_page.open_edit_dialog_for_section(section)
end
it "shows field labels without help text link" do
edit_dialog.expect_title section.name
edit_dialog.expect_field_label_without_help_text "Boolean field"
edit_dialog.expect_field_label_without_help_text "Date field"
edit_dialog.expect_field_label_without_help_text "Float field"
edit_dialog.expect_field_label_without_help_text "Integer field"
edit_dialog.expect_field_label_without_help_text "Link field"
edit_dialog.expect_field_label_without_help_text "String field"
edit_dialog.expect_field_label_without_help_text "Text field"
end
end
context "with attribute help texts defined" do
let!(:boolean_help_text) { create(:project_help_text, attribute_name: boolean_project_custom_field.attribute_name) }
let!(:date_help_text) { create(:project_help_text, attribute_name: date_project_custom_field.attribute_name) }
let!(:float_help_text) { create(:project_help_text, attribute_name: float_project_custom_field.attribute_name) }
let!(:integer_help_text) { create(:project_help_text, attribute_name: integer_project_custom_field.attribute_name) }
let!(:link_help_text) { create(:project_help_text, attribute_name: link_project_custom_field.attribute_name) }
let!(:string_help_text) { create(:project_help_text, attribute_name: string_project_custom_field.attribute_name) }
let!(:text_help_text) { create(:project_help_text, attribute_name: text_project_custom_field.attribute_name) }
before do
overview_page.open_edit_dialog_for_section(section)
end
it "shows field labels with help text link" do
edit_dialog.expect_title section.name
edit_dialog.expect_field_label_with_help_text "Boolean field"
edit_dialog.expect_field_label_with_help_text "Date field"
edit_dialog.expect_field_label_with_help_text "Float field"
edit_dialog.expect_field_label_with_help_text "Integer field"
edit_dialog.expect_field_label_with_help_text "Link field"
edit_dialog.expect_field_label_with_help_text "String field"
edit_dialog.expect_field_label_with_help_text "Text field"
end
context "without attachments" do
it "shows help text modal on clicking help text link" do
edit_dialog.expect_title section.name
edit_dialog.click_help_text_link_for_label "Date field"
expect(page).to have_modal "Date field"
within_modal "Date field" do
expect(page).to have_text "Attribute help text"
expect(page).to have_no_heading "Attachments"
click_on "Close"
end
expect(page).to have_no_modal "Date field"
end
end
context "with attachments" do
let!(:attachments) { create_list(:attachment, 2, container: integer_help_text) }
it "shows help text modal, including attachments, on clicking help text link" do
edit_dialog.expect_title section.name
edit_dialog.click_help_text_link_for_label "Integer field"
expect(page).to have_modal "Integer field"
within_modal "Integer field" do
expect(page).to have_text "Attribute help text"
expect(page).to have_heading "Attachments"
expect(page).to have_list_item count: 2
expect(page).to have_list_item text: "file-1.test"
expect(page).to have_list_item text: "file-2.test"
attachment_window = window_opened_by do
click_on "file-1.test"
end
within_window(attachment_window) do
expect(page).to have_current_path api_v3_paths.attachment_content(attachments.first.id)
expect(page).to have_text "test content"
end
attachment_window.close
click_on "Close"
end
expect(page).to have_no_modal "Integer field"
end
end
end
end
context "for select fields section" do
let(:section) { section_for_select_fields }
context "without attribute help texts defined" do
before do
overview_page.open_edit_dialog_for_section(section)
end
it "shows field labels without help text link" do
edit_dialog.expect_title section.name
edit_dialog.expect_field_label_without_help_text "List field"
edit_dialog.expect_field_label_without_help_text "Version field"
edit_dialog.expect_field_label_without_help_text "User field"
end
end
context "with attribute help texts defined" do
let!(:list_help_text) { create(:project_help_text, attribute_name: list_project_custom_field.attribute_name) }
let!(:version_help_text) { create(:project_help_text, attribute_name: version_project_custom_field.attribute_name) }
let!(:user_help_text) { create(:project_help_text, attribute_name: user_project_custom_field.attribute_name) }
before do
overview_page.open_edit_dialog_for_section(section)
end
it "shows field labels with help text link" do
edit_dialog.expect_title section.name
edit_dialog.expect_field_label_with_help_text "List field"
edit_dialog.expect_field_label_with_help_text "Version field"
edit_dialog.expect_field_label_with_help_text "User field"
end
it "shows help text modal on clicking help text link" do
edit_dialog.expect_title section.name
edit_dialog.click_help_text_link_for_label "User field"
expect(page).to have_modal "User field"
within_modal "User field" do
expect(page).to have_text "Attribute help text"
click_on "Close"
end
expect(page).to have_no_modal "User field"
end
end
end
context "for multi select fields section" do
let(:section) { section_for_multi_select_fields }
context "without attribute help texts defined" do
before do
overview_page.open_edit_dialog_for_section(section)
end
it "shows field labels without help text link" do
edit_dialog.expect_title section.name
edit_dialog.expect_field_label_without_help_text "Multi list field"
edit_dialog.expect_field_label_without_help_text "Multi version field"
edit_dialog.expect_field_label_without_help_text "Multi user field"
end
end
context "with attribute help texts defined" do
let!(:multi_list_help_text) do
create(:project_help_text, attribute_name: multi_list_project_custom_field.attribute_name)
end
let!(:multi_version_help_text) do
create(:project_help_text, attribute_name: multi_version_project_custom_field.attribute_name)
end
let!(:multi_user_help_text) do
create(:project_help_text, attribute_name: multi_user_project_custom_field.attribute_name)
end
before do
overview_page.open_edit_dialog_for_section(section)
end
it "shows field labels with help text link" do
edit_dialog.expect_title section.name
edit_dialog.expect_field_label_with_help_text "Multi list field"
edit_dialog.expect_field_label_with_help_text "Multi version field"
edit_dialog.expect_field_label_with_help_text "Multi user field"
end
it "shows help text modal on clicking help text link" do
edit_dialog.expect_title section.name
edit_dialog.click_help_text_link_for_label "Multi list field"
expect(page).to have_modal "Multi list field"
within_modal "Multi list field" do
expect(page).to have_text "Attribute help text"
click_on "Close"
end
expect(page).to have_no_modal "Multi list field"
end
end
end
end
@@ -0,0 +1,61 @@
# 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 CustomFields::Inputs::Bool, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) { create(:boolean_project_custom_field, name: "Boolean field") }
it_behaves_like "rendering label with help text", "Boolean field"
context "without a value" do
it "renders field" do
expect(rendered_form).to have_unchecked_field "Boolean field", with: "1"
end
end
context "when value is true" do
let(:value) { true }
it "renders field" do
expect(rendered_form).to have_checked_field "Boolean field", with: "1"
end
end
context "when value is false" do
let(:value) { false }
it "renders field" do
expect(rendered_form).to have_unchecked_field "Boolean field", with: "1"
end
end
end
@@ -0,0 +1,65 @@
# 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 CustomFields::Inputs::Date, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) { create(:date_project_custom_field, name: "Date field") }
it_behaves_like "rendering label with help text", "Date field"
context "without a value" do
it "renders field" do
expect(rendered_form).to have_field "Date field", type: :date, with: ""
end
end
context "when value is invalid" do
let(:value) { "NOT A DATE" }
it "renders invalid field" do
expect(rendered_form).to have_field "Date field", type: :date, with: "NOT A DATE", aria: { invalid: true }
end
it "renders error message" do
expect(rendered_form).to have_css ".FormControl-inlineValidation", text: "Value is not a valid date."
end
end
context "when value is valid" do
let(:value) { Date.civil(2024, 3, 20) }
it "renders field" do
expect(rendered_form).to have_field "Date field", type: :date, with: "2024-03-20"
end
end
end
@@ -0,0 +1,53 @@
# 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 CustomFields::Inputs::Float, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) { create(:float_project_custom_field, name: "Float field") }
it_behaves_like "rendering label with help text", "Float field"
context "without a value" do
it "renders field" do
expect(rendered_form).to have_field "Float field", type: :number, with: ""
end
end
context "with a value" do
let(:value) { 78.23 }
it "renders field" do
expect(rendered_form).to have_field "Float field", type: :number, with: "78.23"
end
end
end
@@ -0,0 +1,53 @@
# 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 CustomFields::Inputs::Int, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) { create(:integer_project_custom_field, name: "Integer field") }
it_behaves_like "rendering label with help text", "Integer field"
context "without a value" do
it "renders field" do
expect(rendered_form).to have_field "Integer field", type: :number, with: ""
end
end
context "with a value" do
let(:value) { 76 }
it "renders field" do
expect(rendered_form).to have_field "Integer field", type: :number, with: "76"
end
end
end
@@ -0,0 +1,54 @@
# 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 CustomFields::Inputs::MultiSelectList, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) do
create(
:list_project_custom_field,
name: "Multi-list field",
multi_value: true,
possible_values: ["uno", "due", "tre", "quattro"]
)
end
let(:value) { custom_field.possible_values.last(2).pluck(:id) }
it_behaves_like "rendering label with help text", "Multi-list field"
it_behaves_like "rendering autocompleter", "Multi-list field", multiple: true do
it "sets correct autocompleter inputs" do
expect(autocompleter["data-items"]).to have_json_size(4)
expect(autocompleter["data-model"]).to have_json_size(2)
expect(autocompleter["data-model"]).to be_json_eql(%{[{"name": "tre"}, {"name": "quattro"}]})
end
end
end
@@ -0,0 +1,48 @@
# 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 CustomFields::Inputs::MultiUserSelectList, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) { create(:user_project_custom_field, name: "Users field", multi_value: true) }
let(:value) { create_list(:user, 2) }
it_behaves_like "rendering label with help text", "Users field"
it_behaves_like "rendering autocompleter", "Users field", tag_name: "opce-user-autocompleter", multiple: true do
it "sets correct autocompleter inputs" do
expect(autocompleter["data-resource"]).to be_json_eql(%{"principals"})
expect(autocompleter["data-url"]).to be_json_eql(%{"/api/v3/principals"})
expect(autocompleter["data-input-value"]).to have_json_size(2)
expect(autocompleter["data-input-value"]).to be_json_eql(value.pluck(:id).map(&:to_s).to_json)
end
end
end
@@ -0,0 +1,48 @@
# 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 CustomFields::Inputs::MultiVersionSelectList, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) { create(:version_project_custom_field, name: "Versions field", multi_value: true) }
let(:value) { create_list(:version, 2, project: model) }
let!(:other_versions) { create_list(:version, 3, project: model) }
it_behaves_like "rendering label with help text", "Versions field"
it_behaves_like "rendering autocompleter", "Versions field", multiple: true do
it "sets correct autocompleter inputs" do
expect(autocompleter["data-items"]).to have_json_size(5)
expect(autocompleter["data-model"]).to have_json_size(2)
expect(autocompleter["data-model"]).to be_json_eql(value.map { it.slice(:name) }.to_json).excluding("group_by")
end
end
end
@@ -0,0 +1,46 @@
# 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 CustomFields::Inputs::SingleSelectList, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) { create(:list_project_custom_field, name: "List field", possible_values: ["eins", "zwei", "drei"]) }
let(:value) { custom_field.possible_values.first.id }
it_behaves_like "rendering label with help text", "List field"
it_behaves_like "rendering autocompleter", "List field" do
it "sets correct autocompleter inputs" do
expect(autocompleter["data-items"]).to have_json_size(3)
expect(autocompleter["data-model"]).to be_json_eql(%{{"name": "eins"}})
end
end
end
@@ -0,0 +1,47 @@
# 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 CustomFields::Inputs::SingleUserSelectList, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) { create(:user_project_custom_field, name: "User field") }
let(:value) { create(:user) }
it_behaves_like "rendering label with help text", "User field"
it_behaves_like "rendering autocompleter", "User field", tag_name: "opce-user-autocompleter" do
it "sets correct autocompleter inputs" do
expect(autocompleter["data-resource"]).to be_json_eql(%{"principals"})
expect(autocompleter["data-url"]).to be_json_eql(%{"/api/v3/principals"})
expect(autocompleter["data-input-value"]).to be_json_eql(%{"#{value.id}"})
end
end
end
@@ -0,0 +1,46 @@
# 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 CustomFields::Inputs::SingleVersionSelectList, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) { create(:version_project_custom_field, name: "Version field") }
let(:value) { create(:version, name: "Version 26", project: model) }
it_behaves_like "rendering label with help text", "Version field"
it_behaves_like "rendering autocompleter", "Version field" do
it "sets correct autocompleter inputs" do
expect(autocompleter["data-items"]).to have_json_size(1)
expect(autocompleter["data-model"]).to be_json_eql(%{{"name":"Version 26"}}).excluding("group_by")
end
end
end
@@ -0,0 +1,89 @@
# 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 CustomFields::Inputs::String, type: :forms do
include_context "with rendered custom field input form"
context "with a string custom field" do
let(:custom_field) { create(:string_project_custom_field, name: "String field") }
it_behaves_like "rendering label with help text", "String field"
context "without a value" do
it "renders field" do
expect(rendered_form).to have_field "String field", type: :text, with: ""
end
end
context "when value is empty" do
let(:value) { "" }
it "renders field" do
expect(rendered_form).to have_field "String field", type: :text, with: ""
end
end
context "when value is present" do
let(:value) { "weil wir es uns wert sind" }
it "renders field" do
expect(rendered_form).to have_field "String field", type: :text, with: "weil wir es uns wert sind"
end
end
end
context "with a link custom field" do
let(:custom_field) { create(:link_project_custom_field, name: "Link field") }
it_behaves_like "rendering label with help text", "Link field"
context "when value is invalid" do
let(:value) { "!@£$ NOT A LINK" }
it "renders invalid field" do
expect(rendered_form).to have_field "Link field", type: :text, with: "!@£$ NOT A LINK", aria: { invalid: true }
end
it "renders error message" do
expect(rendered_form).to have_css ".FormControl-inlineValidation", text: "Value is not a valid URL."
end
end
context "when value is present" do
let(:value) { "https://developer.mozilla.org/en-US/docs/" }
it "renders field" do
expect(rendered_form).to have_field "Link field", type: :text, with: "https://developer.mozilla.org/en-US/docs/"
end
end
end
end
@@ -0,0 +1,61 @@
# 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 CustomFields::Inputs::Text, type: :forms do
include_context "with rendered custom field input form"
let(:custom_field) { create(:text_project_custom_field, name: "Text field") }
it_behaves_like "rendering label with help text", "Text field"
context "without a value" do
it "renders field" do
expect(rendered_form).to have_field "Text field", type: :textarea, with: "", visible: :hidden
end
end
context "when value is empty" do
let(:value) { "" }
it "renders field" do
expect(rendered_form).to have_field "Text field", type: :textarea, with: "", visible: :hidden
end
end
context "when value is present" do
let(:value) { "parce que nous le valons bien" }
it "renders field" do
expect(rendered_form).to have_field "Text field", type: :textarea, with: "parce que nous le valons bien", visible: :hidden
end
end
end
@@ -0,0 +1,250 @@
# 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 Primer::OpenProject::Forms::Dsl::InputMethods, type: :forms do
let(:form_object) { Primer::Forms::Dsl::FormObject.extend(described_class) }
let(:builder) { instance_double(ActionView::Helpers::FormBuilder, object: model) }
let(:form) { instance_double(ApplicationForm, model:, caption_template?: false) }
let(:form_dsl) { form_object.new(builder:, form:) }
let(:name) { :subject }
let(:label) { "Subject" }
let(:options) { {} }
let(:model) { build_stubbed(:project) }
subject(:field) { field_group.first }
before do
allow(form).to receive(:wrap_attribute_label_with_help_text) do |label, name|
"#{label} <fake-attribute-help-text for='#{name}'/>"
end
end
shared_examples_for "input class" do |input_class|
it "instantiates correct input class" do
expect(field).to be_a(input_class)
end
end
shared_examples_for "supporting help texts" do
context "when include_help_text: option is true (default)" do
context "when no additional help_text_options: are passed" do
it "wraps the label with help text" do
expect(field.label).to start_with(label)
.and end_with("<fake-attribute-help-text for='#{name}'/>")
end
end
context "when additional help_text_options: are passed" do
let(:attribute_name) { :subject_attribute }
let(:options) { { help_text_options: { attribute_name: } } }
it "wraps the label with help text" do
expect(field.label).to start_with(label)
.and end_with("<fake-attribute-help-text for='#{attribute_name}'/>")
end
end
end
context "when include_help_text: option is false" do
let(:options) { { include_help_text: false } }
it "does not wrap the label" do
expect(field.label).to eq label
end
end
end
describe "multi input methods" do
describe "#multi" do
let(:field_group) { form_dsl.multi(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::MultiInput
it_behaves_like "supporting help texts"
end
describe "#check_box" do
let(:field_group) { form_dsl.check_box(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::CheckBoxInput
it_behaves_like "supporting help texts"
end
describe "#radio_button_group" do
let(:field_group) { form_dsl.radio_button_group(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::RadioButtonGroupInput
it_behaves_like "supporting help texts"
end
describe "#check_box_group" do
let(:field_group) { form_dsl.check_box_group(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::CheckBoxGroupInput
it_behaves_like "supporting help texts"
end
end
describe "#separator" do
let(:field_group) { form_dsl.separator }
include_examples "input class", Primer::Forms::Separator
end
describe "text input methods" do
describe "#text_field" do
let(:field_group) { form_dsl.text_field(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::TextFieldInput
it_behaves_like "supporting help texts"
end
describe "#auto_complete" do
let(:field_group) { form_dsl.auto_complete(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::AutoCompleteInput
it_behaves_like "supporting help texts"
end
describe "#text_area" do
let(:field_group) { form_dsl.text_area(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::TextAreaInput
it_behaves_like "supporting help texts"
end
end
describe "select input methods" do
describe "#select_list" do
let(:field_group) { form_dsl.select_list(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::SelectInput
it_behaves_like "supporting help texts"
end
describe "#action_menu" do
let(:field_group) { form_dsl.action_menu(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::ActionMenuInput
it_behaves_like "supporting help texts"
end
end
describe "button input methods" do
describe "#submit" do
let(:field_group) { form_dsl.submit(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::SubmitButtonInput
it_behaves_like "supporting help texts"
end
describe "#button" do
let(:field_group) { form_dsl.button(name:, label:, **options) }
include_examples "input class", Primer::Forms::Dsl::ButtonInput
it_behaves_like "supporting help texts"
end
end
describe "OpenProject input methods" do
describe "#autocompleter" do
let(:field_group) { form_dsl.autocompleter(name:, label:, autocomplete_options: {}, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::AutocompleterInput
it_behaves_like "supporting help texts"
end
describe "#pattern_input" do
let(:field_group) { form_dsl.pattern_input(name:, label:, value: "", suggestions: [], **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::PatternInput
it_behaves_like "supporting help texts"
end
describe "#color_select_list" do
let(:field_group) { form_dsl.color_select_list(name:, label:, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::ColorSelectInput
it_behaves_like "supporting help texts"
end
describe "#html_content" do
let(:field_group) { form_dsl.html_content(name:, label:, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::HtmlContentInput
end
describe "#project_autocompleter" do
let(:field_group) { form_dsl.project_autocompleter(name:, label:, autocomplete_options: {}, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::ProjectAutocompleterInput
it_behaves_like "supporting help texts"
end
describe "#single_date_picker" do
let(:field_group) { form_dsl.single_date_picker(name:, label:, datepicker_options: {}, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::SingleDatePickerInput
it_behaves_like "supporting help texts"
end
describe "#range_date_picker" do
let(:field_group) { form_dsl.range_date_picker(name:, label:, datepicker_options: {}, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::RangeDatePickerInput
it_behaves_like "supporting help texts"
end
describe "#rich_text_area" do
let(:field_group) { form_dsl.rich_text_area(name:, label:, rich_text_options: {}, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::RichTextAreaInput
it_behaves_like "supporting help texts"
end
describe "#storage_manual_project_folder_selection" do
let(:project_storage) { build_stubbed(:project_storage) }
let(:field_group) { form_dsl.storage_manual_project_folder_selection(name:, label:, project_storage:, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::StorageManualProjectFolderSelectionInput
it_behaves_like "supporting help texts"
end
describe "#work_package_autocompleter" do
let(:field_group) { form_dsl.work_package_autocompleter(name:, label:, autocomplete_options: {}, **options) }
include_examples "input class", Primer::OpenProject::Forms::Dsl::WorkPackageAutocompleterInput
it_behaves_like "supporting help texts"
end
end
end
@@ -95,6 +95,33 @@ module Components
expect(page).to have_css(async_content_container_css_selector)
end
def expect_field_label_with_help_text(label_text)
expect_field_label(label_text)
expect(find_field_label(label_text)).to have_link accessible_name: "Show help text"
end
def expect_field_label_without_help_text(label_text)
expect_field_label(label_text)
expect(find_field_label(label_text)).to have_no_link accessible_name: "Show help text"
end
def click_help_text_link_for_label(label_text)
link = find_field_label(label_text).find(:link, accessible_name: "Show help text")
link.click
end
def expect_field_label(label_text)
within_dialog do
expect(page).to have_element :label, text: label_text
end
end
def find_field_label(label_text)
within_dialog do
page.find(:element, :label, text: label_text)
end
end
###
def input_containers
@@ -0,0 +1,99 @@
# 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.
#++
RSpec.shared_context "with rendered custom field input form" do
include ViewComponent::TestHelpers
let(:model) { create(:project) }
let!(:custom_field_mapping) do
create(:project_custom_field_project_mapping, project: model, project_custom_field: custom_field)
end
let(:value) { nil }
current_user { build_stubbed(:admin) }
def build_form(builder)
described_class.new(builder, custom_field:, object: model)
end
def render_form
render_in_view_context(model, self) do |model, spec_context|
primer_form_with(url: "/foo", model:) do |f|
render(spec_context.build_form(f))
end
end
end
before do
model.custom_field_values = { "#{custom_field.id}": value } if value
model.custom_field_values.first.valid?
end
subject(:rendered_form) do
render_form
page
end
shared_examples "rendering label" do |label_text|
it "renders a label" do
expect(rendered_form).to have_element :label, text: label_text
end
end
shared_examples "rendering autocompleter" do |label_text, tag_name: "opce-autocompleter", multiple: false|
let(:label_id) { rendered_form.find(:element, :label, text: label_text)["for"] }
let(:autocompleter) { rendered_form.find(:element, tag_name, "data-label-for-id": "\"#{label_id}\"") }
it "renders autocompleter field" do
expect(rendered_form).to have_element tag_name, "data-label-for-id": "\"#{label_id}\"" do |autocompleter|
expect(autocompleter["data-multiple"]).to be_json_eql(multiple)
end
end
end
shared_examples "rendering label with help text" do |label_text|
let(:label) { rendered_form.find(:element, :label, text: label_text) }
include_examples "rendering label", label_text
context "without attribute help text" do
it "does not render help text link" do
expect(label).to have_no_link class: "op-attribute-help-text"
end
end
context "with attribute help text" do
let!(:attribute_help_text) { create(:project_help_text, attribute_name: custom_field.attribute_name) }
it "renders help text link" do
expect(label).to have_link class: "op-attribute-help-text"
end
end
end
end