diff --git a/app/components/open_project/common/attribute_component.html.erb b/app/components/open_project/common/attribute_component.html.erb
index 3db882cd538c..5fa17c497919 100644
--- a/app/components/open_project/common/attribute_component.html.erb
+++ b/app/components/open_project/common/attribute_component.html.erb
@@ -1,24 +1,46 @@
<%= render(
Primer::Beta::Text.new(tag: :div,
classes: ['op-long-text-attribute--text', PARAGRAPH_CSS_CLASS],
color: text_color,
+ style: "max-height: #{max_height};",
data: {
'attribute-target': "descriptionText"
- })) { short_text } %>
+ })) { short_text }
+ %>
+
+ <%= render(
+ Primer::Beta::Text.new(tag: :div,
+ display: display_expand_button_value,
+ classes: 'op-long-text-attribute--text-hider',
+ data: { 'attribute-target': 'textHider' }))
+ %>
+
+ <%= render(
+ Primer::Alpha::HiddenTextExpander.new(inline: false,
+ "aria-label": I18n.t('label_attribute_expand_text', attribute: name),
+ display: display_expand_button_value,
+ data: {
+ 'attribute-target': 'expandButton',
+ 'test-selector': 'expand-button'
+ },
+ button_arguments: { 'data-show-dialog-id': id },
+ classes: 'op-long-text-attribute--text-expander'
+ ))
+ %>
<%= render(
Primer::Alpha::Dialog.new(id: id,
+ data: {
+ 'test-selector': 'attribute-dialog'
+ },
title: name,
size: :large)) do |component|
- component.with_show_button(scheme: :link,
- display: display_expand_button_value,
- ml: 1,
- data: { 'attribute-target': 'expandButton' }) { I18n.t('js.label_expand') }
component.with_body(mt: 2) { full_text }
component.with_header(variant: :large)
end
diff --git a/app/components/open_project/common/attribute_component.rb b/app/components/open_project/common/attribute_component.rb
index 1182707b70a7..993b893d5ed5 100644
--- a/app/components/open_project/common/attribute_component.rb
+++ b/app/components/open_project/common/attribute_component.rb
@@ -32,16 +32,20 @@ module Common
class AttributeComponent < Primer::Component
attr_reader :id,
:name,
- :description
+ :description,
+ :lines,
+ :background_reference_id
PARAGRAPH_CSS_CLASS = "op-uc-p".freeze
- def initialize(id, name, description, **args)
+ def initialize(id, name, description, lines: 1, background_reference_id: "content", **args)
super
@id = id
@name = name
@description = description
@system_arguments = args
+ @lines = lines
+ @background_reference_id = background_reference_id
end
def short_text
@@ -64,6 +68,10 @@ def text_color
:muted if multi_type?
end
+ def max_height
+ "#{lines * 1.6}em"
+ end
+
private
def first_paragraph
@@ -88,7 +96,7 @@ def body_children
end
def multi_type?
- first_paragraph.include?("figure") || first_paragraph.include?("macro")
+ first_paragraph.include?("figure") || first_paragraph.include?("macro") || (body_children.any? && first_paragraph.blank?)
end
end
end
diff --git a/app/components/open_project/common/attribute_component.sass b/app/components/open_project/common/attribute_component.sass
index ff6a4ab26583..126d434e06b9 100644
--- a/app/components/open_project/common/attribute_component.sass
+++ b/app/components/open_project/common/attribute_component.sass
@@ -1,7 +1,17 @@
.op-long-text-attribute
- display: flex
- align-items: center
+ position: relative
+
&--text
- @include text-shortener
+ overflow: hidden
margin: 0
- flex-grow: 1
+ &--text-hider
+ position: absolute
+ bottom: 0
+ right: 0
+ height: 1.5em
+ width: 2em
+ &--text-expander
+ position: absolute
+ bottom: 1px
+ right: 0
+ float: right
diff --git a/app/components/projects/settings/project_custom_field_sections/custom_field_row_component.html.erb b/app/components/projects/settings/project_custom_field_sections/custom_field_row_component.html.erb
index 8e538fb20a36..374bb4ed0642 100644
--- a/app/components/projects/settings/project_custom_field_sections/custom_field_row_component.html.erb
+++ b/app/components/projects/settings/project_custom_field_sections/custom_field_row_component.html.erb
@@ -1,15 +1,15 @@
<%=
component_wrapper do
flex_layout(align_items: :center, justify_content: :space_between, classes: 'op-project-custom-field', data: {
- qa_selector: "project-custom-field-#{@project_custom_field.id}"
+ test_selector: "project-custom-field-#{@project_custom_field.id}"
}) do |custom_field_container|
custom_field_container.with_column(flex_layout: true) do |title_container|
title_container.with_column(pt: 1, mr: 2) do
- render(Primer::Beta::Text.new) do
+ render(Primer::Beta::Text.new) do
@project_custom_field.name
end
end
- title_container.with_column(pt: 1, mr: 2, data: { qa_selector: "custom-field-type" } ) do
+ title_container.with_column(pt: 1, mr: 2, data: { test_selector: "custom-field-type" } ) do
render(Primer::Beta::Text.new(font_size: :small, color: :subtle)) do
@project_custom_field.field_format.capitalize
end
@@ -37,7 +37,7 @@
),
csrf_token: form_authenticity_token,
data: { 'turbo-method': :put, 'turbo-stream': true,
- qa_selector: "toggle-project-custom-field-mapping-#{@project_custom_field.id}" },
+ test_selector: "toggle-project-custom-field-mapping-#{@project_custom_field.id}" },
checked: active_in_project?,
enabled: !@project_custom_field.required?, # required fields cannot be disabled
size: :small,
diff --git a/app/components/projects/settings/project_custom_field_sections/show_component.html.erb b/app/components/projects/settings/project_custom_field_sections/show_component.html.erb
index 58f145a2f550..e80f89bca076 100644
--- a/app/components/projects/settings/project_custom_field_sections/show_component.html.erb
+++ b/app/components/projects/settings/project_custom_field_sections/show_component.html.erb
@@ -1,7 +1,7 @@
<%=
component_wrapper do
render(Primer::Beta::BorderBox.new(mt: 3, classes: 'op-project-custom-field-section', data: {
- qa_selector: "project-custom-field-section-#{@project_custom_field_section.id}"
+ test_selector: "project-custom-field-section-#{@project_custom_field_section.id}"
})) do |component|
component.with_header(font_weight: :bold, py: 2) do
flex_layout(justify_content: :space_between, align_items: :center) do |section_header_container|
@@ -26,7 +26,7 @@
font_weight: :bold,
color: :subtle,
'aria-label': t('projects.settings.project_custom_fields.actions.label_enable_all'),
- data: { 'turbo-method': :put, 'turbo-stream': true, qa_selector: "enable-all-project-custom-field-mappings-#{@project_custom_field_section.id}" }
+ data: { 'turbo-method': :put, 'turbo-stream': true, test_selector: "enable-all-project-custom-field-mappings-#{@project_custom_field_section.id}" }
)) do |button|
button.with_leading_visual_icon(icon: 'check-circle', color: :subtle)
t('projects.settings.project_custom_fields.actions.label_enable_all')
@@ -45,7 +45,7 @@
font_weight: :bold,
color: :subtle,
'aria-label': t('projects.settings.project_custom_fields.actions.label_disable_all'),
- data: { 'turbo-method': :put, 'turbo-stream': true, qa_selector: "disable-all-project-custom-field-mappings-#{@project_custom_field_section.id}" }
+ data: { 'turbo-method': :put, 'turbo-stream': true, test_selector: "disable-all-project-custom-field-mappings-#{@project_custom_field_section.id}" }
)) do |button|
button.with_leading_visual_icon(icon: 'x-circle', color: :subtle)
t('projects.settings.project_custom_fields.actions.label_disable_all')
diff --git a/app/components/settings/project_custom_field_sections/custom_field_row_component.html.erb b/app/components/settings/project_custom_field_sections/custom_field_row_component.html.erb
index bba637366eb8..7d87bb1dbc01 100644
--- a/app/components/settings/project_custom_field_sections/custom_field_row_component.html.erb
+++ b/app/components/settings/project_custom_field_sections/custom_field_row_component.html.erb
@@ -1,5 +1,5 @@
<%=
- component_wrapper(class: "op-project-custom-field-container", data: { qa_selector: "project-custom-field-container-#{@project_custom_field.id}" }) do
+ component_wrapper(class: "op-project-custom-field-container", data: { test_selector: "project-custom-field-container-#{@project_custom_field.id}" }) do
flex_layout(justify_content: :space_between, align_items: :center) do |main_container|
main_container.with_column(flex_layout: true, align_items: :center) do |content_container|
content_container.with_column(mr: 2) do
@@ -36,7 +36,7 @@
end
end
main_container.with_column do
- render(Primer::Alpha::ActionMenu.new(data: { qa_selector: "project-custom-field-action-menu" })) do |menu|
+ render(Primer::Alpha::ActionMenu.new(data: { test_selector: "project-custom-field-action-menu" })) do |menu|
menu.with_show_button(icon: "kebab-horizontal", 'aria-label': t("settings.project_attributes.label_project_custom_field_actions"), scheme: :invisible)
edit_action_item(menu)
move_actions(menu)
diff --git a/app/components/settings/project_custom_field_sections/custom_field_row_component.rb b/app/components/settings/project_custom_field_sections/custom_field_row_component.rb
index 765ec50dc0db..b57eb096fff1 100644
--- a/app/components/settings/project_custom_field_sections/custom_field_row_component.rb
+++ b/app/components/settings/project_custom_field_sections/custom_field_row_component.rb
@@ -45,7 +45,7 @@ def initialize(project_custom_field:, first_and_last:)
def edit_action_item(menu)
menu.with_item(label: t("label_edit"),
href: edit_admin_settings_project_custom_field_path(@project_custom_field),
- data: { turbo: "false", qa_selector: "project-custom-field-edit" }) do |item|
+ data: { turbo: "false", test_selector: "project-custom-field-edit" }) do |item|
item.with_leading_visual_icon(icon: :pencil)
end
end
@@ -68,7 +68,7 @@ def move_action_item(menu, move_to, label_text, icon)
menu.with_item(label: label_text,
href: move_admin_settings_project_custom_field_path(@project_custom_field, move_to:),
form_arguments: {
- method: :put, data: { 'turbo-stream': true, qa_selector: "project-custom-field-move-#{move_to}" }
+ method: :put, data: { "turbo-stream": true, test_selector: "project-custom-field-move-#{move_to}" }
}) do |item|
item.with_leading_visual_icon(icon:)
end
@@ -79,8 +79,8 @@ def delete_action_item(menu)
scheme: :danger,
href: admin_settings_project_custom_field_path(@project_custom_field),
form_arguments: {
- method: :delete, data: { confirm: t("text_are_you_sure"), 'turbo-stream': true,
- qa_selector: "project-custom-field-delete" }
+ method: :delete, data: { confirm: t("text_are_you_sure"), "turbo-stream": true,
+ test_selector: "project-custom-field-delete" }
}) do |item|
item.with_leading_visual_icon(icon: :trash)
end
diff --git a/app/components/settings/project_custom_field_sections/show_component.html.erb b/app/components/settings/project_custom_field_sections/show_component.html.erb
index ea991c887388..c8db95da20e0 100644
--- a/app/components/settings/project_custom_field_sections/show_component.html.erb
+++ b/app/components/settings/project_custom_field_sections/show_component.html.erb
@@ -1,5 +1,5 @@
<%=
- component_wrapper(class: "op-project-custom-field-section-container", data: { qa_selector: "project-custom-field-section-container-#{@project_custom_field_section.id}" }) do
+ component_wrapper(class: "op-project-custom-field-section-container", data: { test_selector: "project-custom-field-section-container-#{@project_custom_field_section.id}" }) do
render(Primer::Beta::BorderBox.new(mt: 3, data: drag_and_drop_target_config)) do |component|
component.with_header(font_weight: :bold) do
flex_layout(justify_content: :space_between, align_items: :center) do |section_header_container|
@@ -15,7 +15,7 @@
end
section_header_container.with_column(flex_layout: true, justify_content: :flex_end) do |actions_container|
actions_container.with_column do
- render(Primer::Alpha::ActionMenu.new(data: { qa_selector: "project-custom-field-section-action-menu" })) do |menu|
+ render(Primer::Alpha::ActionMenu.new(data: { test_selector: "project-custom-field-section-action-menu" })) do |menu|
menu.with_show_button(icon: "kebab-horizontal", 'aria-label': t("settings.project_attributes.label_section_actions"), scheme: :invisible)
edit_action_item(menu)
move_actions(menu)
@@ -50,7 +50,7 @@
type: "ProjectCustomField", custom_field_section_id: @project_custom_field_section.id
),
scheme: :secondary,
- data: { turbo: "false", qa_selector: "new-project-custom-field-button" }
+ data: { turbo: "false", test_selector: "new-project-custom-field-button" }
)) do |button|
button.with_leading_visual_icon(icon: :plus)
t('settings.project_attributes.label_new_attribute')
diff --git a/app/components/settings/project_custom_field_sections/show_component.rb b/app/components/settings/project_custom_field_sections/show_component.rb
index 76fa3c16a738..cc1af53fa9c5 100644
--- a/app/components/settings/project_custom_field_sections/show_component.rb
+++ b/app/components/settings/project_custom_field_sections/show_component.rb
@@ -49,18 +49,18 @@ def wrapper_uniq_by
def drag_and_drop_target_config
{
- 'is-drag-and-drop-target': true,
- 'target-container-accessor': '.Box > ul', # the accessor of the container that contains the drag and drop items
- 'target-id': @project_custom_field_section.id, # the id of the target
- 'target-allowed-drag-type': 'custom-field' # the type of dragged items which are allowed to be dropped in this target
+ "is-drag-and-drop-target": true,
+ "target-container-accessor": ".Box > ul", # the accessor of the container that contains the drag and drop items
+ "target-id": @project_custom_field_section.id, # the id of the target
+ "target-allowed-drag-type": "custom-field" # the type of dragged items which are allowed to be dropped in this target
}
end
def draggable_item_config(project_custom_field)
{
- 'draggable-id': project_custom_field.id,
- 'draggable-type': 'custom-field',
- 'drop-url': drop_admin_settings_project_custom_field_path(project_custom_field)
+ "draggable-id": project_custom_field.id,
+ "draggable-type": "custom-field",
+ "drop-url": drop_admin_settings_project_custom_field_path(project_custom_field)
}
end
@@ -82,7 +82,8 @@ def move_action_item(menu, move_to, label_text, icon)
menu.with_item(label: label_text,
href: move_admin_settings_project_custom_field_section_path(@project_custom_field_section, move_to:),
form_arguments: {
- method: :put, data: { 'turbo-stream': true, qa_selector: "project-custom-field-section-move-#{move_to}" }
+ method: :put, data: { "turbo-stream": true,
+ test_selector: "project-custom-field-section-move-#{move_to}" }
}) do |item|
item.with_leading_visual_icon(icon:)
end
@@ -99,8 +100,8 @@ def edit_action_item(menu)
menu.with_item(label: t("settings.project_attributes.label_edit_section"),
tag: :button,
content_arguments: {
- 'data-show-dialog-id': "project-custom-field-section-dialog#{@project_custom_field_section.id}",
- 'data-qa-selector': "project-custom-field-section-edit"
+ "data-show-dialog-id": "project-custom-field-section-dialog#{@project_custom_field_section.id}",
+ "data-test-selector": "project-custom-field-section-edit"
},
value: "") do |item|
item.with_leading_visual_icon(icon: :pencil)
@@ -112,8 +113,8 @@ def delete_action_item(menu)
scheme: :danger,
href: admin_settings_project_custom_field_section_path(@project_custom_field_section),
form_arguments: {
- method: :delete, data: { confirm: t("text_are_you_sure"), 'turbo-stream': true,
- qa_selector: "project-custom-field-section-delete" }
+ method: :delete, data: { confirm: t("text_are_you_sure"), "turbo-stream": true,
+ test_selector: "project-custom-field-section-delete" }
}) do |item|
item.with_leading_visual_icon(icon: :trash)
end
diff --git a/app/components/settings/project_custom_fields/header_component.html.erb b/app/components/settings/project_custom_fields/header_component.html.erb
index 0b1d0169aa7c..3045d6f46ed2 100644
--- a/app/components/settings/project_custom_fields/header_component.html.erb
+++ b/app/components/settings/project_custom_fields/header_component.html.erb
@@ -1,6 +1,6 @@
<%=
- component_wrapper do
+ component_wrapper do
render Primer::OpenProject::PageHeader.new do |header|
header.with_title(variant: :default) { t('settings.project_attributes.heading') }
header.with_description { t('settings.project_attributes.heading_description') }
@@ -11,7 +11,7 @@
tag: :a,
href: new_admin_settings_project_custom_field_path(type: "ProjectCustomField"),
scheme: :primary,
- data: { turbo: "false", qa_selector: "new-project-custom-field-button" }
+ data: { turbo: "false", test_selector: "new-project-custom-field-button" }
)) do |button|
button.with_leading_visual_icon(icon: :plus)
t('settings.project_attributes.label_new_attribute')
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 48074c49711a..40f0301584e6 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1821,6 +1821,7 @@ Project attributes and sections are defined in the
truncation_length
- render_truncated_preview_and_dialog_for_rich_text_value(truncation_length)
- else
- render(Primer::Beta::Text.new) do
- format_value(@project_custom_field_values.first&.value, @project_custom_field)
- end
- end
- end
-
- def render_truncated_preview_and_dialog_for_rich_text_value(truncation_length)
- flex_layout do |rich_text_preview_container|
- rich_text_preview_container.with_row do
- render(Primer::Beta::Text.new(classes: 'project-custom-fields-rich-text-preview')) do
- format_value(
- @project_custom_field_values.first&.value&.truncate(truncation_length),
- @project_custom_field
- )
- end + render_dialog
- end
- end
- end
-
- def render_dialog
- render(Primer::Alpha::Dialog.new(size: :medium_portrait, title: @project_custom_field.name)) do |dialog|
- dialog.with_show_button(scheme: :link) { t(:label_expand) }
- # TODO: remove inline style
- dialog.with_body(style: "max-height: 500px;") do
- format_value(@project_custom_field_values.first&.value, @project_custom_field)
- end
- end
+ def render_long_text
+ render OpenProject::Common::AttributeComponent.new("dialog-cf-#{@project_custom_field.id}",
+ @project_custom_field.name,
+ @project_custom_field_values&.first&.value,
+ lines: 3)
end
def render_user
diff --git a/modules/overviews/app/components/project_custom_fields/sections/show_component.html.erb b/modules/overviews/app/components/project_custom_fields/sections/show_component.html.erb
index b42340b6e217..2915d4781864 100644
--- a/modules/overviews/app/components/project_custom_fields/sections/show_component.html.erb
+++ b/modules/overviews/app/components/project_custom_fields/sections/show_component.html.erb
@@ -1,7 +1,7 @@
<%=
component_wrapper do
flex_layout(border: :bottom, pb: 2, classes: 'op-project-custom-field-section-container', data: {
- qa_selector: "project-custom-field-section-#{@project_custom_field_section.id}"
+ test_selector: "project-custom-field-section-#{@project_custom_field_section.id}"
}) do |details_container|
details_container.with_row(mb: 2) do
flex_layout(align_items: :center, justify_content: :space_between) do |heading|
@@ -18,7 +18,7 @@
button_icon: :pencil,
button_icon_label: t(:label_edit),
button_attributes: { scheme: :invisible, data: {
- qa_selector: "project-custom-field-section-edit-button"
+ test_selector: "project-custom-field-section-edit-button"
} }
))
end if allowed_to_edit?
diff --git a/modules/overviews/app/components/project_custom_fields/sidebar_component.html.erb b/modules/overviews/app/components/project_custom_fields/sidebar_component.html.erb
index 6f8f746c66ec..efdff6c6d02e 100644
--- a/modules/overviews/app/components/project_custom_fields/sidebar_component.html.erb
+++ b/modules/overviews/app/components/project_custom_fields/sidebar_component.html.erb
@@ -1,7 +1,7 @@
<%=
component_wrapper do
if available_project_custom_fields_grouped_by_section.any?
- flex_layout(data: { qa_selector: "project-custom-fields-sidebar-async-content" }) do |sections_container|
+ flex_layout(data: { test_selector: "project-custom-fields-sidebar-async-content" }) do |sections_container|
available_project_custom_fields_grouped_by_section.each do |project_custom_field_section, project_custom_fields|
sections_container.with_row(mb: 3) do
render(ProjectCustomFields::Sections::ShowComponent.new(
diff --git a/spec/features/admin/project_custom_fields/list_spec.rb b/spec/features/admin/project_custom_fields/list_spec.rb
index b01692b6606a..2c07ed5e272f 100644
--- a/spec/features/admin/project_custom_fields/list_spec.rb
+++ b/spec/features/admin/project_custom_fields/list_spec.rb
@@ -87,7 +87,8 @@
end
end
- expect(page).to have_no_css("[data-qa-selector='project-custom-field-section-container-#{section_for_multi_select_fields.id}']")
+ expect(page)
+ .to have_no_css("[data-test-selector='project-custom-field-section-container-#{section_for_multi_select_fields.id}']")
end
it 'allows to edit a section' do
@@ -188,7 +189,7 @@
end
end
- expect(page).to have_no_css("[data-qa-selector='project-custom-field-container-#{boolean_project_custom_field.id}']")
+ expect(page).to have_no_css("[data-test-selector='project-custom-field-container-#{boolean_project_custom_field.id}']")
end
it 'redirects to the custom field edit page via menu item' do
@@ -208,14 +209,14 @@
end
it 'redirects to the custom field new page via header menu button' do
- page.find("[data-qa-selector='new-project-custom-field-button']").click
+ page.find("[data-test-selector='new-project-custom-field-button']").click
expect(page).to have_current_path(new_admin_settings_project_custom_field_path(type: 'ProjectCustomField'))
end
it 'redirects to the custom field new page via button in empty sections' do
within_project_custom_field_section_container(section_for_multi_select_fields) do
- expect(page).to have_no_css("[data-qa-selector='new-project-custom-field-button']")
+ expect(page).to have_no_css("[data-test-selector='new-project-custom-field-button']")
end
multi_list_project_custom_field.destroy
@@ -225,7 +226,7 @@
visit admin_settings_project_custom_fields_path
within_project_custom_field_section_container(section_for_multi_select_fields) do
- page.find("[data-qa-selector='new-project-custom-field-button']").click
+ page.find("[data-test-selector='new-project-custom-field-button']").click
end
expect(page).to have_current_path(new_admin_settings_project_custom_field_path(
@@ -239,12 +240,12 @@
# helper methods:
def within_project_custom_field_section_container(section, &block)
- within("[data-qa-selector='project-custom-field-section-container-#{section.id}']", &block)
+ within("[data-test-selector='project-custom-field-section-container-#{section.id}']", &block)
end
def within_project_custom_field_section_menu(section, &block)
within_project_custom_field_section_container(section) do
- page.find("[data-qa-selector='project-custom-field-section-action-menu']").click
+ page.find("[data-test-selector='project-custom-field-section-action-menu']").click
within('anchored-position', &block)
end
end
@@ -257,12 +258,12 @@ def perform_action_for_project_custom_field_section(section, action)
end
def within_project_custom_field_container(custom_field, &block)
- within("[data-qa-selector='project-custom-field-container-#{custom_field.id}']", &block)
+ within("[data-test-selector='project-custom-field-container-#{custom_field.id}']", &block)
end
def within_project_custom_field_menu(section, &block)
within_project_custom_field_container(section) do
- page.find("[data-qa-selector='project-custom-field-action-menu']").click
+ page.find("[data-test-selector='project-custom-field-action-menu']").click
within('anchored-position', &block)
end
end
diff --git a/spec/features/projects/project_custom_fields/overview_page/dialog/permission_spec.rb b/spec/features/projects/project_custom_fields/overview_page/dialog/permission_spec.rb
index 60c7414eaf94..aec9e99269a7 100644
--- a/spec/features/projects/project_custom_fields/overview_page/dialog/permission_spec.rb
+++ b/spec/features/projects/project_custom_fields/overview_page/dialog/permission_spec.rb
@@ -45,7 +45,7 @@
it 'does not show the edit buttons' do
overview_page.within_async_loaded_sidebar do
- expect(page).to have_no_css("[data-qa-selector='project-custom-field-section-edit-button']")
+ expect(page).to have_no_css("[data-test-selector='project-custom-field-section-edit-button']")
end
end
end
@@ -58,7 +58,7 @@
it 'shows the edit buttons' do
overview_page.within_async_loaded_sidebar do
- expect(page).to have_css("[data-qa-selector='project-custom-field-section-edit-button']", count: 3)
+ expect(page).to have_css("[data-test-selector='project-custom-field-section-edit-button']", count: 3)
end
end
end
diff --git a/spec/features/projects/project_custom_fields/overview_page/dialog/update_spec.rb b/spec/features/projects/project_custom_fields/overview_page/dialog/update_spec.rb
index 15f61de8bbe9..1e7dbddd4dc3 100644
--- a/spec/features/projects/project_custom_fields/overview_page/dialog/update_spec.rb
+++ b/spec/features/projects/project_custom_fields/overview_page/dialog/update_spec.rb
@@ -269,9 +269,9 @@
describe "with text CF" do
let(:custom_field) { text_project_custom_field }
let(:field) { FormFields::Primerized::EditorFormField.new(custom_field) }
- let(:expected_initial_value) { "Lorem\nipsum" } # TBD: why is the second newline missing?
- let(:update_value) { "Dolor\n\nsit" }
- let(:expected_updated_value) { "Dolor\nsit" }
+ let(:expected_initial_value) { "Lorem" }
+ let(:update_value) { "Dolor sit" }
+ let(:expected_updated_value) { "Dolor sit" }
it_behaves_like "a rich text custom field input"
end
diff --git a/spec/features/projects/project_custom_fields/overview_page/sidebar_spec.rb b/spec/features/projects/project_custom_fields/overview_page/sidebar_spec.rb
index 4eae8b7909e2..446a9d9d38aa 100644
--- a/spec/features/projects/project_custom_fields/overview_page/sidebar_spec.rb
+++ b/spec/features/projects/project_custom_fields/overview_page/sidebar_spec.rb
@@ -146,10 +146,6 @@
describe "with correct values" do
describe "with boolean CF" do
- # it_behaves_like 'a project custom field' do
- # let(subject) { boolean_project_custom_field }
- # end
-
describe "with value set by user" do
it "shows the correct value for the project custom field if given" do
overview_page.visit_page
@@ -473,22 +469,30 @@
describe "with text CF" do
describe "with value set by user" do
- context "with a value that is shorter than 100 characters" do
+ context "with a value that does not have a line break and spans less than 3 lines" do
+ before do
+ text_project_custom_field.custom_values.where(customized: project).first.update!(value: "Lorem ipsum")
+ end
+
it "shows the correct value for the project custom field if given without truncation and dialog button" do
overview_page.visit_page
overview_page.within_async_loaded_sidebar do
overview_page.within_custom_field_container(text_project_custom_field) do
expect(page).to have_text "Text field"
- expect(page).to have_text "Lorem\nipsum"
+ expect(page).to have_text "Lorem ipsum"
end
+
+ overview_page.expect_text_not_truncated(text_project_custom_field)
end
end
end
- context "with a value that is longer than 100 characters" do
+ context "with a value that spans more than three lines" do
+ let(:cf_value) { ("lorem " * 100).strip }
+
before do
- text_project_custom_field.custom_values.where(customized: project).first.update!(value: "a" * 101)
+ text_project_custom_field.custom_values.where(customized: project).first.update!(value: cf_value)
end
it "shows the correct value for the project custom field if given with truncation and dialog button" do
@@ -497,16 +501,14 @@
overview_page.within_async_loaded_sidebar do
overview_page.within_custom_field_container(text_project_custom_field) do
expect(page).to have_text "Text field"
- expect(page).to have_text ("#{'a' * 97}...")
- expect(page).to have_text "Expand"
-
- click_on "Expand"
-
- within "dialog" do
- expect(page).to have_text "a" * 101
- end
+ expect(page).to have_text (("lorem " * 5).to_s)
end
+
+ overview_page.expect_text_truncated(text_project_custom_field)
+ overview_page.expand_text(text_project_custom_field)
end
+
+ overview_page.expect_full_text_in_dialog(cf_value)
end
end
end
@@ -524,6 +526,8 @@
expect(page).to have_text "Text field"
expect(page).to have_text I18n.t("placeholders.default")
end
+
+ overview_page.expect_text_not_truncated(text_project_custom_field)
end
end
end
@@ -541,6 +545,8 @@
expect(page).to have_text "Text field"
expect(page).to have_text I18n.t("placeholders.default")
end
+
+ overview_page.expect_text_not_truncated(text_project_custom_field)
end
end
@@ -554,6 +560,8 @@
expect(page).to have_text "Text field"
expect(page).to have_text I18n.t("placeholders.default")
end
+
+ overview_page.expect_text_not_truncated(text_project_custom_field)
end
end
end
@@ -718,14 +726,6 @@
end
end
end
-
- describe "with support for user groups" do
- # TODO
- end
-
- describe "with support for user placeholders" do
- # TODO
- end
end
describe "with multi list CF" do
diff --git a/spec/features/projects/project_custom_fields/settings/mapping_spec.rb b/spec/features/projects/project_custom_fields/settings/mapping_spec.rb
index 61db89df1e04..faf9ff175d9b 100644
--- a/spec/features/projects/project_custom_fields/settings/mapping_spec.rb
+++ b/spec/features/projects/project_custom_fields/settings/mapping_spec.rb
@@ -169,7 +169,9 @@
within_custom_field_container(boolean_project_custom_field) do
expect_unchecked_state
- page.find("[data-qa-selector='toggle-project-custom-field-mapping-#{boolean_project_custom_field.id}'] > button").click
+ page
+ .find("[data-test-selector='toggle-project-custom-field-mapping-#{boolean_project_custom_field.id}'] > button")
+ .click
expect_checked_state # without reloading the page
end
@@ -194,7 +196,7 @@
visit project_settings_project_custom_fields_path(project)
within_custom_field_section_container(section_for_input_fields) do
- page.find("[data-qa-selector='enable-all-project-custom-field-mappings-#{section_for_input_fields.id}']").click
+ page.find("[data-test-selector='enable-all-project-custom-field-mappings-#{section_for_input_fields.id}']").click
within_custom_field_container(boolean_project_custom_field) do
expect_checked_state
@@ -221,7 +223,7 @@
visit project_settings_project_custom_fields_path(project)
within_custom_field_section_container(section_for_input_fields) do
- page.find("[data-qa-selector='enable-all-project-custom-field-mappings-#{section_for_input_fields.id}']").click
+ page.find("[data-test-selector='enable-all-project-custom-field-mappings-#{section_for_input_fields.id}']").click
within_custom_field_container(boolean_project_custom_field) do
expect_checked_state
@@ -244,7 +246,7 @@
end
within_custom_field_section_container(section_for_input_fields) do
- page.find("[data-qa-selector='disable-all-project-custom-field-mappings-#{section_for_input_fields.id}']").click
+ page.find("[data-test-selector='disable-all-project-custom-field-mappings-#{section_for_input_fields.id}']").click
within_custom_field_container(boolean_project_custom_field) do
expect_unchecked_state
@@ -362,7 +364,9 @@
it 'includeds the invisible project custom fields in the bulk actions' do
within_custom_field_section_container(section_with_invisible_fields) do
- page.find("[data-qa-selector='disable-all-project-custom-field-mappings-#{section_with_invisible_fields.id}']").click
+ page
+ .find("[data-test-selector='disable-all-project-custom-field-mappings-#{section_with_invisible_fields.id}']")
+ .click
within_custom_field_container(visible_project_custom_field) do
expect_unchecked_state
@@ -371,7 +375,9 @@
expect_unchecked_state
end
- page.find("[data-qa-selector='enable-all-project-custom-field-mappings-#{section_with_invisible_fields.id}']").click
+ page
+ .find("[data-test-selector='enable-all-project-custom-field-mappings-#{section_with_invisible_fields.id}']")
+ .click
within_custom_field_container(visible_project_custom_field) do
expect_checked_state
@@ -398,7 +404,9 @@
it 'does not include the invisible project custom fields in the bulk actions' do
within_custom_field_section_container(section_with_invisible_fields) do
- page.find("[data-qa-selector='disable-all-project-custom-field-mappings-#{section_with_invisible_fields.id}']").click
+ page
+ .find("[data-test-selector='disable-all-project-custom-field-mappings-#{section_with_invisible_fields.id}']")
+ .click
within_custom_field_container(visible_project_custom_field) do
expect_unchecked_state
@@ -410,7 +418,7 @@
# disable manually
project.project_custom_field_project_mappings.find_by(custom_field_id: invisible_project_custom_field.id).destroy!
- page.find("[data-qa-selector='enable-all-project-custom-field-mappings-#{section_with_invisible_fields.id}']").click
+ page.find("[data-test-selector='enable-all-project-custom-field-mappings-#{section_with_invisible_fields.id}']").click
within_custom_field_container(visible_project_custom_field) do
expect_checked_state
@@ -425,7 +433,7 @@
end
def expect_type(type)
- within "[data-qa-selector='custom-field-type']" do
+ within "[data-test-selector='custom-field-type']" do
expect(page).to have_content(type)
end
end
@@ -439,10 +447,10 @@ def expect_unchecked_state
end
def within_custom_field_section_container(section, &)
- within("[data-qa-selector='project-custom-field-section-#{section.id}']", &)
+ within("[data-test-selector='project-custom-field-section-#{section.id}']", &)
end
def within_custom_field_container(custom_field, &)
- within("[data-qa-selector='project-custom-field-#{custom_field.id}']", &)
+ within("[data-test-selector='project-custom-field-#{custom_field.id}']", &)
end
end
diff --git a/spec/features/projects/projects_index_spec.rb b/spec/features/projects/projects_index_spec.rb
index ab09bd73b957..635c4844be92 100644
--- a/spec/features/projects/projects_index_spec.rb
+++ b/spec/features/projects/projects_index_spec.rb
@@ -26,38 +26,38 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-require 'spec_helper'
+require "spec_helper"
-RSpec.describe 'Projects index page',
+RSpec.describe "Projects index page",
:js,
:with_cuprite,
with_settings: { login_required?: false } do
shared_let(:admin) { create(:admin) }
- shared_let(:manager) { create(:project_role, name: 'Manager') }
- shared_let(:developer) { create(:project_role, name: 'Developer') }
+ shared_let(:manager) { create(:project_role, name: "Manager") }
+ shared_let(:developer) { create(:project_role, name: "Developer") }
shared_let(:custom_field) { create(:text_project_custom_field) }
shared_let(:invisible_custom_field) { create(:project_custom_field, visible: false) }
shared_let(:project) do
create(:project,
- name: 'Plain project',
- identifier: 'plain-project')
+ name: "Plain project",
+ identifier: "plain-project")
end
shared_let(:public_project) do
project = create(:project,
- name: 'Public project',
- identifier: 'public-project',
+ name: "Public project",
+ identifier: "public-project",
public: true)
- project.custom_field_values = { invisible_custom_field.id => 'Secret CF' }
+ project.custom_field_values = { invisible_custom_field.id => "Secret CF" }
project.save
project
end
shared_let(:development_project) do
create(:project,
- name: 'Development project',
- identifier: 'development-project')
+ name: "Development project",
+ identifier: "development-project")
end
let(:news) { create(:news, project:) }
@@ -87,9 +87,9 @@ def expect_projects_in_order(*projects)
end
end
- describe 'project visibility restriction' do
- context 'for an anonymous user' do
- specify 'only public projects shall be visible' do
+ describe "project visibility restriction" do
+ context "for an anonymous user" do
+ specify "only public projects shall be visible" do
ProjectRole.anonymous
visit projects_path
@@ -97,20 +97,20 @@ def expect_projects_in_order(*projects)
expect(page).to have_text(public_project.name)
# Test that the 'More' menu stays invisible on hover
- expect(page).to have_no_css('.icon-show-more-horizontal')
+ expect(page).to have_no_css(".icon-show-more-horizontal")
end
end
- context 'for project members', with_ee: %i[custom_fields_in_projects_list] do
+ context "for project members", with_ee: %i[custom_fields_in_projects_list] do
shared_let(:user) do
create(:user,
member_with_roles: { development_project => developer },
- login: 'nerd',
- firstname: 'Alan',
- lastname: 'Turing')
+ login: "nerd",
+ firstname: "Alan",
+ lastname: "Turing")
end
- specify 'only public projects or those the user is a member of shall be visible' do
+ specify "only public projects or those the user is a member of shall be visible" do
ProjectRole.non_member
login_as(user)
visit projects_path
@@ -121,28 +121,28 @@ def expect_projects_in_order(*projects)
# Non-admin users shall not see invisible CFs.
expect(page).to have_no_text(invisible_custom_field.name.upcase)
- expect(page).to have_no_select('add_filter_select', with_options: [invisible_custom_field.name])
+ expect(page).to have_no_select("add_filter_select", with_options: [invisible_custom_field.name])
end
end
- context 'for work package members', with_ee: %i[custom_fields_in_projects_list] do
+ context "for work package members", with_ee: %i[custom_fields_in_projects_list] do
shared_let(:work_package) { create(:work_package, project: development_project) }
shared_let(:user) do
create(:user,
member_with_permissions: { work_package => [:view_work_packages] },
- login: 'nerd',
- firstname: 'Alan',
- lastname: 'Turing')
+ login: "nerd",
+ firstname: "Alan",
+ lastname: "Turing")
end
- specify 'only public projects or those the user is member in a specific work package' do
+ specify "only public projects or those the user is member in a specific work package" do
Setting.enabled_projects_columns += [custom_field.column_name]
development_project.update(
- description: 'I am a nice project',
- status_explanation: 'We are on track',
- status_code: 'on_track',
- custom_field_values: { custom_field.id => 'This is a test value' }
+ description: "I am a nice project",
+ status_explanation: "We are on track",
+ status_code: "on_track",
+ custom_field_values: { custom_field.id => "This is a test value" }
)
login_as(user)
@@ -162,14 +162,14 @@ def expect_projects_in_order(*projects)
end
end
- context 'for admins' do
+ context "for admins" do
before do
- project.update(created_at: 7.days.ago, description: 'I am a nice project')
+ project.update(created_at: 7.days.ago, description: "I am a nice project")
news
end
- specify 'all projects are visible' do
+ specify "all projects are visible" do
login_as(admin)
visit projects_path
@@ -177,130 +177,133 @@ def expect_projects_in_order(*projects)
expect(page).to have_text(project.name)
# Test visibility of 'more' menu list items
- item = page.first('tbody tr .icon-show-more-horizontal', visible: :all)
+ item = page.first("tbody tr .icon-show-more-horizontal", visible: :all)
item.hover
item.click
- menu = page.first('tbody tr .project-actions')
- expect(menu).to have_text('Copy')
- expect(menu).to have_text('Project settings')
- expect(menu).to have_text('New subproject')
- expect(menu).to have_text('Delete')
- expect(menu).to have_text('Archive')
+ menu = page.first("tbody tr .project-actions")
+ expect(menu).to have_text("Copy")
+ expect(menu).to have_text("Project settings")
+ expect(menu).to have_text("New subproject")
+ expect(menu).to have_text("Delete")
+ expect(menu).to have_text("Archive")
# Test visibility of admin only properties
- within('#project-table') do
+ within("#project-table") do
expect(page)
- .to have_css('th', text: 'REQUIRED DISK STORAGE')
+ .to have_css("th", text: "REQUIRED DISK STORAGE")
expect(page)
- .to have_css('th', text: 'CREATED ON')
+ .to have_css("th", text: "CREATED ON")
expect(page)
- .to have_css('td', text: project.created_at.strftime('%m/%d/%Y'))
+ .to have_css("td", text: project.created_at.strftime("%m/%d/%Y"))
expect(page)
- .to have_css('th', text: 'LATEST ACTIVITY AT')
+ .to have_css("th", text: "LATEST ACTIVITY AT")
expect(page)
- .to have_css('td', text: news.created_at.strftime('%m/%d/%Y'))
+ .to have_css("td", text: news.created_at.strftime("%m/%d/%Y"))
end
end
- specify 'flash sortBy is being escaped' do
+ specify "flash sortBy is being escaped" do
login_as(admin)
visit projects_path(sortBy: "[[\">\",\"\"]]")
error_text = "Orders > is not set to one of the allowed values. and does not exist."
error_html = "Orders ><script src='/foobar js'></script> is not set to one of the allowed values. and does not exist."
- expect(page).to have_css('.op-toast.-error', text: error_text)
+ expect(page).to have_css(".op-toast.-error", text: error_text)
- error_container = page.find('.op-toast.-error')
- expect(error_container['innerHTML']).to include error_html
+ error_container = page.find(".op-toast.-error")
+ expect(error_container["innerHTML"]).to include error_html
end
end
end
- context 'without valid Enterprise token' do
- specify 'CF columns and filters are not visible' do
+ context "without valid Enterprise token" do
+ specify "CF columns and filters are not visible" do
load_and_open_filters admin
# CF's columns are not present:
expect(page).to have_no_text(custom_field.name.upcase)
# CF's filters are not present:
- expect(page).to have_no_select('add_filter_select', with_options: [custom_field.name])
+ expect(page).to have_no_select("add_filter_select", with_options: [custom_field.name])
end
end
- context 'with valid Enterprise token', with_ee: %i[custom_fields_in_projects_list] do
+ context "with valid Enterprise token", with_ee: %i[custom_fields_in_projects_list] do
shared_let(:long_text_custom_field) { create(:text_project_custom_field) }
- specify 'CF columns and filters are not visible by default' do
+ specify "CF columns and filters are not visible by default" do
load_and_open_filters admin
# CF's columns are not shown due to setting
expect(page).to have_no_text(custom_field.name.upcase)
end
- specify 'CF columns and filters are visible when added to settings' do
+ specify "CF columns and filters are visible when added to settings" do
Setting.enabled_projects_columns += [custom_field.column_name, invisible_custom_field.column_name]
load_and_open_filters admin
# CF's column is present:
expect(page).to have_text(custom_field.name.upcase)
# CF's filter is present:
- expect(page).to have_select('add_filter_select', with_options: [custom_field.name])
+ expect(page).to have_select("add_filter_select", with_options: [custom_field.name])
# Admins shall be the only ones to see invisible CFs
expect(page).to have_text(invisible_custom_field.name.upcase)
- expect(page).to have_select('add_filter_select', with_options: [invisible_custom_field.name])
+ expect(page).to have_select("add_filter_select", with_options: [invisible_custom_field.name])
end
- specify 'long-text fields are truncated' do
+ specify "long-text fields are truncated" do
development_project.update(
- description: 'I am a nice project with a very long long long long long long long long long description',
- status_explanation: '',
- custom_field_values: { custom_field.id => 'This is a short value',
- long_text_custom_field.id => 'This is a very long long long long long long long value' }
+ description: "I am a nice project with a very long long long long long long long long long description",
+ status_explanation: "",
+ custom_field_values: { custom_field.id => "This is a short value",
+ long_text_custom_field.id => "This is a very long long long long long long long value" }
)
development_project.save!
login_as(admin)
- Setting.enabled_projects_columns += [custom_field.column_name, long_text_custom_field.column_name, 'description',
- 'status_explanation']
+ Setting.enabled_projects_columns += [custom_field.column_name, long_text_custom_field.column_name, "description",
+ "status_explanation"]
projects_page.visit!
- tr_project_development = page.first('tr', text: 'Development project')
-
# Check if the description is truncated and shows the Expand button correctly
- td_project_development_description = tr_project_development.first('td.description')
- expect(td_project_development_description).to have_css('button', text: 'Expand')
- td_project_development_description.find('button', text: 'Expand').click
- expect(page).to have_css('.Overlay-body', text: development_project.description)
+ projects_page.within_row(development_project) do
+ expect(page).to have_css('td.description [data-test-selector="expand-button"]')
+ page.find('td.description [data-test-selector="expand-button"]').click
+ end
+
+ expect(page).to have_css(".Overlay-body", text: development_project.description)
# Check if the status explanation with an html tag is truncated and shows the cell text and Expand button correctly
- td_project_development_status_description = tr_project_development.first('td.status_explanation')
- expect(td_project_development_status_description).to have_css('button', text: 'Expand')
- expect(td_project_development_status_description).to have_text('Preview not available')
+ projects_page.within_row(development_project) do
+ expect(page).to have_css('td.status_explanation [data-test-selector="expand-button"]')
+ expect(page).to have_css("td.status_explanation", text: "Preview not available")
+ end
# Check if a long-text custom field which has a short text as value is not truncated and there is no Expand button there
- td_project_development_short_cf = tr_project_development.first('td', text: 'This is a short value')
- expect(td_project_development_short_cf).to have_no_css('button', text: 'Expand')
+ projects_page.within_row(development_project) do
+ expect(page).to have_no_css("td.cf_#{custom_field.id} [data-test-selector=\"expand-button\"]")
+ expect(page).to have_css("td.cf_#{custom_field.id}", text: "This is a short value")
+ end
# Check if a long-text custom field which has a long text as value is truncated and there is an Expand button there
- td_project_development_long_cf = tr_project_development.first(
- 'td',
- text: 'This is a very long long long long long long long value'
- )
- expect(td_project_development_long_cf).to have_css('button', text: 'Expand')
+ projects_page.within_row(development_project) do
+ expect(page).to have_css("td.cf_#{long_text_custom_field.id} [data-test-selector=\"expand-button\"]")
+ expect(page).to have_css("td.cf_#{long_text_custom_field.id}",
+ text: "This is a very long long long long long long long value")
+ end
end
end
- context 'with a filter set' do
- it 'only shows the matching projects and filters' do
+ context "with a filter set" do
+ it "only shows the matching projects and filters" do
load_and_open_filters admin
- projects_page.set_filter('name_and_identifier',
- 'Name or identifier',
- 'contains',
- ['Plain'])
+ projects_page.set_filter("name_and_identifier",
+ "Name or identifier",
+ "contains",
+ ["Plain"])
- click_on 'Apply'
+ click_on "Apply"
# Filter is applied: Only the project that contains the the word "Plain" gets listed
projects_page.expect_projects_listed(project)
projects_page.expect_projects_not_listed(public_project)
@@ -309,54 +312,54 @@ def expect_projects_in_order(*projects)
end
end
- context 'when paginating', with_settings: { enabled_projects_columns: %w[name project_status] } do
+ context "when paginating", with_settings: { enabled_projects_columns: %w[name project_status] } do
before do
allow(Setting).to receive(:per_page_options_array).and_return([1, 5])
end
- it 'keeps applied filters, orders and columns' do
+ it "keeps applied filters, orders and columns" do
load_and_open_filters admin
- projects_page.set_filter('name_and_identifier',
- 'Name or identifier',
- 'doesn\'t contain',
- ['Plain'])
+ projects_page.set_filter("name_and_identifier",
+ "Name or identifier",
+ "doesn't contain",
+ ["Plain"])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
- projects_page.set_columns('Name')
- projects_page.expect_columns('Name')
+ projects_page.set_columns("Name")
+ projects_page.expect_columns("Name")
# Sorts ASC by name
- projects_page.sort_by('Name')
+ projects_page.sort_by("Name")
wait_for_reload
# Results should be filtered and ordered ASC by name and only the selected columns should be present
projects_page.expect_projects_listed(development_project)
projects_page.expect_projects_not_listed(project, # as it is filtered out
public_project) # as it is on the second page
- projects_page.expect_columns('Name')
- projects_page.expect_no_columns('Status')
- expect(page).to have_text('Next') # as the result set is larger than 1
+ projects_page.expect_columns("Name")
+ projects_page.expect_no_columns("Status")
+ expect(page).to have_text("Next") # as the result set is larger than 1
# Changing the page size to 5 and back to 1 should not change the filters (which we test later on the second page)
projects_page.set_page_size(5)
wait_for_reload
projects_page.set_page_size(1)
wait_for_reload
- click_on '2' # Go to pagination page 2
+ click_on "2" # Go to pagination page 2
# On page 2 you should see the second page of the filtered set ordered ASC by name and only the selected columns exist
projects_page.expect_projects_listed(public_project)
projects_page.expect_projects_not_listed(project, # Filtered out
development_project) # Present on page 1
- projects_page.expect_columns('Name')
- projects_page.expect_no_columns('Status')
+ projects_page.expect_columns("Name")
+ projects_page.expect_no_columns("Status")
projects_page.expect_total_pages(2) # Filters kept active, so there is no third page.
# Sorts DESC by name
- projects_page.sort_by('Name')
+ projects_page.sort_by("Name")
wait_for_reload
# Clicking on sorting resets the page to the first one
@@ -368,12 +371,12 @@ def expect_projects_in_order(*projects)
development_project) # Present on page 2
projects_page.expect_total_pages(2) # Filters kept active, so there is no third page.
- expect(page).to have_css('.sort.desc', text: 'NAME')
- projects_page.expect_columns('Name')
- projects_page.expect_no_columns('Status')
+ expect(page).to have_css(".sort.desc", text: "NAME")
+ projects_page.expect_columns("Name")
+ projects_page.expect_no_columns("Status")
# Sending the filter form again what implies to compose the request freshly
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
# We should see page 1, resetting pagination, as it is a new filter, but keeping the DESC order on the project
@@ -382,53 +385,53 @@ def expect_projects_in_order(*projects)
projects_page.expect_projects_not_listed(development_project, # as it is on the second page
project) # as it filtered out
projects_page.expect_total_pages(2) # as the result set is larger than 1
- expect(page).to have_css('.sort.desc', text: 'NAME')
- projects_page.expect_columns('Name')
- projects_page.expect_no_columns('Status')
+ expect(page).to have_css(".sort.desc", text: "NAME")
+ projects_page.expect_columns("Name")
+ projects_page.expect_no_columns("Status")
end
end
- context 'when filter of type' do
- specify 'Name and identifier gives results in both, name and identifier' do
+ context "when filter of type" do
+ specify "Name and identifier gives results in both, name and identifier" do
load_and_open_filters admin
# Filter on model attribute 'name'
- projects_page.set_filter('name_and_identifier',
- 'Name or identifier',
- 'doesn\'t contain',
- ['Plain'])
+ projects_page.set_filter("name_and_identifier",
+ "Name or identifier",
+ "doesn't contain",
+ ["Plain"])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
projects_page.expect_projects_listed(development_project, public_project)
projects_page.expect_projects_not_listed(project)
# Filter on model attribute 'identifier'
- remove_filter('name_and_identifier')
+ remove_filter("name_and_identifier")
- projects_page.set_filter('name_and_identifier',
- 'Name or identifier',
- 'is',
- ['plain-project'])
+ projects_page.set_filter("name_and_identifier",
+ "Name or identifier",
+ "is",
+ ["plain-project"])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
projects_page.expect_projects_listed(project)
projects_page.expect_projects_not_listed(development_project, public_project)
end
- describe 'Active or archived' do
+ describe "Active or archived" do
shared_let(:parent_project) do
create(:project,
- name: 'Parent project',
- identifier: 'parent-project')
+ name: "Parent project",
+ identifier: "parent-project")
end
shared_let(:child_project) do
create(:project,
- name: 'Child project',
- identifier: 'child-project',
+ name: "Child project",
+ identifier: "child-project",
parent: parent_project)
end
@@ -445,7 +448,7 @@ def expect_projects_in_order(*projects)
public_project)
accept_alert do
- projects_page.click_menu_item_of('Archive', parent_project)
+ projects_page.click_menu_item_of("Archive", parent_project)
end
wait_for_reload
@@ -463,20 +466,20 @@ def expect_projects_in_order(*projects)
load_and_open_filters admin
- projects_page.filter_by_active('no')
+ projects_page.filter_by_active("no")
projects_page.expect_projects_listed(parent_project, child_project, archived: true)
# Test visibility of 'more' menu list items
projects_page.activate_menu_of(parent_project) do |menu|
- expect(menu).to have_text('Unarchive')
- expect(menu).to have_text('Delete')
- expect(menu).to have_no_text('Archive')
- expect(menu).to have_no_text('Copy')
- expect(menu).to have_no_text('Settings')
- expect(menu).to have_no_text('New subproject')
-
- click_link('Unarchive')
+ expect(menu).to have_text("Unarchive")
+ expect(menu).to have_text("Delete")
+ expect(menu).to have_no_text("Archive")
+ expect(menu).to have_no_text("Copy")
+ expect(menu).to have_no_text("Settings")
+ expect(menu).to have_no_text("New subproject")
+
+ click_link_or_button("Unarchive")
end
# The child project does not get unarchived automatically
@@ -488,7 +491,7 @@ def expect_projects_in_order(*projects)
load_and_open_filters admin
- projects_page.filter_by_active('yes')
+ projects_page.filter_by_active("yes")
projects_page.expect_projects_listed(parent_project,
project,
@@ -498,7 +501,7 @@ def expect_projects_in_order(*projects)
end
end
- describe 'I am member or not' do
+ describe "I am member or not" do
shared_let(:member) { create(:user, member_with_permissions: { project => %i[view_work_packages edit_work_packages] }) }
it "filters for projects I'm a member on and those where I'm not" do
@@ -507,13 +510,13 @@ def expect_projects_in_order(*projects)
projects_page.expect_projects_listed(project, public_project)
- projects_page.filter_by_membership('yes')
+ projects_page.filter_by_membership("yes")
wait_for_reload
projects_page.expect_projects_listed(project)
projects_page.expect_projects_not_listed(public_project, development_project)
- projects_page.filter_by_membership('no')
+ projects_page.filter_by_membership("no")
wait_for_reload
projects_page.expect_projects_listed(public_project)
@@ -521,75 +524,75 @@ def expect_projects_in_order(*projects)
end
end
- describe 'project status filter' do
+ describe "project status filter" do
shared_let(:no_status_project) do
# A project that doesn't have a status code set
create(:project,
- name: 'No status project')
+ name: "No status project")
end
shared_let(:green_project) do
# A project that has a status code set
create(:project,
- status_code: 'on_track',
- name: 'Green project')
+ status_code: "on_track",
+ name: "Green project")
end
- it 'sorts and filters on project status' do
+ it "sorts and filters on project status" do
login_as(admin)
projects_page.visit!
- click_link('Sort by "Status"')
+ click_link_or_button('Sort by "Status"')
expect_project_at_place(green_project, 1)
- expect(page).to have_text('(1 - 5/5)')
+ expect(page).to have_text("(1 - 5/5)")
- click_link('Ascending sorted by "Status"')
+ click_link_or_button('Ascending sorted by "Status"')
expect_project_at_place(green_project, 5)
- expect(page).to have_text('(1 - 5/5)')
+ expect(page).to have_text("(1 - 5/5)")
projects_page.open_filters
- projects_page.set_filter('project_status_code',
- 'Project status',
- 'is (OR)',
- ['On track'])
+ projects_page.set_filter("project_status_code",
+ "Project status",
+ "is (OR)",
+ ["On track"])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(green_project.name)
expect(page).to have_no_text(no_status_project.name)
- projects_page.set_filter('project_status_code',
- 'Project status',
- 'is not empty',
+ projects_page.set_filter("project_status_code",
+ "Project status",
+ "is not empty",
[])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(green_project.name)
expect(page).to have_no_text(no_status_project.name)
- projects_page.set_filter('project_status_code',
- 'Project status',
- 'is empty',
+ projects_page.set_filter("project_status_code",
+ "Project status",
+ "is empty",
[])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_no_text(green_project.name)
expect(page).to have_text(no_status_project.name)
- projects_page.set_filter('project_status_code',
- 'Project status',
- 'is not',
- ['On track'])
+ projects_page.set_filter("project_status_code",
+ "Project status",
+ "is not",
+ ["On track"])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_no_text(green_project.name)
@@ -597,7 +600,7 @@ def expect_projects_in_order(*projects)
end
end
- describe 'other filter types', with_ee: %i[custom_fields_in_projects_list] do
+ describe "other filter types", with_ee: %i[custom_fields_in_projects_list] do
include ActiveSupport::Testing::TimeHelpers
shared_let(:list_custom_field) { create(:list_project_custom_field) }
@@ -608,14 +611,14 @@ def expect_projects_in_order(*projects)
date_of_this_week = today + ((today.wday % 7) > 2 ? -1 : 1)
DateTime.parse("#{date_of_this_week}T11:11:11+00:00")
end
- shared_let(:fixed_datetime) { DateTime.parse('2017-11-11T11:11:11+00:00') }
+ shared_let(:fixed_datetime) { DateTime.parse("2017-11-11T11:11:11+00:00") }
shared_let(:project_created_on_today) do
freeze_time
project = create(:project,
- name: 'Created today project')
+ name: "Created today project")
project.custom_field_values = { list_custom_field.id => list_custom_field.possible_values[2],
- date_custom_field.id => '2011-11-11' }
+ date_custom_field.id => "2011-11-11" }
project.save!
project
ensure
@@ -624,21 +627,21 @@ def expect_projects_in_order(*projects)
shared_let(:project_created_on_this_week) do
travel_to(datetime_of_this_week)
create(:project,
- name: 'Created on this week project')
+ name: "Created on this week project")
ensure
travel_back
end
shared_let(:project_created_on_six_days_ago) do
travel_to(DateTime.now - 6.days)
create(:project,
- name: 'Created on six days ago project')
+ name: "Created on six days ago project")
ensure
travel_back
end
shared_let(:project_created_on_fixed_date) do
travel_to(fixed_datetime)
create(:project,
- name: 'Created on fixed date project')
+ name: "Created on fixed date project")
ensure
travel_back
end
@@ -654,13 +657,13 @@ def expect_projects_in_order(*projects)
load_and_open_filters admin
end
- specify 'selecting operator' do
+ specify "selecting operator" do
# created on 'today' shows projects that were created today
- projects_page.set_filter('created_at',
- 'Created on',
- 'today')
+ projects_page.set_filter("created_at",
+ "Created on",
+ "today")
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(project_created_on_today.name)
@@ -668,13 +671,13 @@ def expect_projects_in_order(*projects)
expect(page).to have_no_text(project_created_on_fixed_date.name)
# created on 'this week' shows projects that were created within the last seven days
- remove_filter('created_at')
+ remove_filter("created_at")
- projects_page.set_filter('created_at',
- 'Created on',
- 'this week')
+ projects_page.set_filter("created_at",
+ "Created on",
+ "this week")
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(project_created_on_today.name)
@@ -682,14 +685,14 @@ def expect_projects_in_order(*projects)
expect(page).to have_no_text(project_created_on_fixed_date.name)
# created on 'on' shows projects that were created within the last seven days
- remove_filter('created_at')
+ remove_filter("created_at")
- projects_page.set_filter('created_at',
- 'Created on',
- 'on',
- ['2017-11-11'])
+ projects_page.set_filter("created_at",
+ "Created on",
+ "on",
+ ["2017-11-11"])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(project_created_on_fixed_date.name)
@@ -697,69 +700,69 @@ def expect_projects_in_order(*projects)
expect(page).to have_no_text(project_created_on_this_week.name)
# created on 'less than days ago'
- remove_filter('created_at')
+ remove_filter("created_at")
- projects_page.set_filter('created_at',
- 'Created on',
- 'less than days ago',
- ['1'])
+ projects_page.set_filter("created_at",
+ "Created on",
+ "less than days ago",
+ ["1"])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(project_created_on_today.name)
expect(page).to have_no_text(project_created_on_fixed_date.name)
# created on 'more than days ago'
- remove_filter('created_at')
+ remove_filter("created_at")
- projects_page.set_filter('created_at',
- 'Created on',
- 'more than days ago',
- ['1'])
+ projects_page.set_filter("created_at",
+ "Created on",
+ "more than days ago",
+ ["1"])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(project_created_on_fixed_date.name)
expect(page).to have_no_text(project_created_on_today.name)
# created on 'between'
- remove_filter('created_at')
+ remove_filter("created_at")
- projects_page.set_filter('created_at',
- 'Created on',
- 'between',
- ['2017-11-10', '2017-11-12'])
+ projects_page.set_filter("created_at",
+ "Created on",
+ "between",
+ ["2017-11-10", "2017-11-12"])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(project_created_on_fixed_date.name)
expect(page).to have_no_text(project_created_on_today.name)
# Latest activity at 'today'. This spot check would fail if the data does not get collected from multiple tables
- remove_filter('created_at')
+ remove_filter("created_at")
- projects_page.set_filter('latest_activity_at',
- 'Latest activity at',
- 'today')
+ projects_page.set_filter("latest_activity_at",
+ "Latest activity at",
+ "today")
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(project_created_on_today.name)
expect(page).to have_no_text(project_created_on_fixed_date.name)
# CF List
- remove_filter('latest_activity_at')
+ remove_filter("latest_activity_at")
projects_page.set_filter(list_custom_field.column_name,
list_custom_field.name,
- 'is (OR)',
+ "is (OR)",
[list_custom_field.possible_values[2].value])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(project_created_on_today.name)
@@ -769,44 +772,44 @@ def expect_projects_in_order(*projects)
cf_filter = page.find("li[filter-name='#{list_custom_field.column_name}']")
within(cf_filter) do
# Initial filter is a 'single select'
- expect(cf_filter.find(:select, 'value')).not_to be_multiple
- click_on 'Toggle multiselect'
+ expect(cf_filter.find(:select, "value")).not_to be_multiple
+ click_on "Toggle multiselect"
# switching to multiselect keeps the current selection
- expect(cf_filter.find(:select, 'value')).to be_multiple
- expect(cf_filter).to have_select('value', selected: list_custom_field.possible_values[2].value)
+ expect(cf_filter.find(:select, "value")).to be_multiple
+ expect(cf_filter).to have_select("value", selected: list_custom_field.possible_values[2].value)
- select list_custom_field.possible_values[3].value, from: 'value'
+ select list_custom_field.possible_values[3].value, from: "value"
end
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
cf_filter = page.find("li[filter-name='#{list_custom_field.column_name}']")
within(cf_filter) do
# Query has two values for that filter, so it should show a 'multi select'.
- expect(cf_filter.find(:select, 'value')).to be_multiple
+ expect(cf_filter.find(:select, "value")).to be_multiple
expect(cf_filter)
- .to have_select('value',
+ .to have_select("value",
selected: [list_custom_field.possible_values[2].value,
list_custom_field.possible_values[3].value])
# switching to single select keeps the first selection
- select list_custom_field.possible_values[1].value, from: 'value'
- unselect list_custom_field.possible_values[2].value, from: 'value'
+ select list_custom_field.possible_values[1].value, from: "value"
+ unselect list_custom_field.possible_values[2].value, from: "value"
- click_on 'Toggle multiselect'
- expect(cf_filter.find(:select, 'value')).not_to be_multiple
- expect(cf_filter).to have_select('value', selected: list_custom_field.possible_values[1].value)
- expect(cf_filter).to have_no_select('value', selected: list_custom_field.possible_values[3].value)
+ click_on "Toggle multiselect"
+ expect(cf_filter.find(:select, "value")).not_to be_multiple
+ expect(cf_filter).to have_select("value", selected: list_custom_field.possible_values[1].value)
+ expect(cf_filter).to have_no_select("value", selected: list_custom_field.possible_values[3].value)
end
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
cf_filter = page.find("li[filter-name='#{list_custom_field.column_name}']")
within(cf_filter) do
# Query has one value for that filter, so it should show a 'single select'.
- expect(cf_filter.find(:select, 'value')).not_to be_multiple
+ expect(cf_filter.find(:select, "value")).not_to be_multiple
end
# CF date filter work (at least for one operator)
@@ -814,10 +817,10 @@ def expect_projects_in_order(*projects)
projects_page.set_filter(date_custom_field.column_name,
date_custom_field.name,
- 'on',
- ['2011-11-11'])
+ "on",
+ ["2011-11-11"])
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_text(project_created_on_today.name)
@@ -826,7 +829,7 @@ def expect_projects_in_order(*projects)
# Disabling a CF in the project should remove the project from results
project_created_on_today.project_custom_field_project_mappings.destroy_all
- click_on 'Apply'
+ click_on "Apply"
wait_for_reload
expect(page).to have_no_text(project_created_on_today.name, wait: 1)
@@ -836,13 +839,13 @@ def expect_projects_in_order(*projects)
pending "NOT WORKING YET: Date vs. DateTime issue: Selecting same date for from and to value shows projects of that date"
end
- describe 'public filter' do
+ describe "public filter" do
it 'filters on "public" status' do
load_and_open_filters admin
projects_page.expect_projects_listed(project, public_project)
- projects_page.filter_by_public('no')
+ projects_page.filter_by_public("no")
wait_for_reload
projects_page.expect_projects_listed(project)
@@ -850,7 +853,7 @@ def expect_projects_in_order(*projects)
load_and_open_filters admin
- projects_page.filter_by_public('yes')
+ projects_page.filter_by_public("yes")
wait_for_reload
projects_page.expect_projects_listed(public_project)
@@ -859,18 +862,18 @@ def expect_projects_in_order(*projects)
end
end
- context 'for non-admins with role with permission' do
+ context "for non-admins with role with permission" do
shared_let(:can_copy_projects_role) do
- create(:project_role, name: 'Can Copy Projects Role', permissions: [:copy_projects])
+ create(:project_role, name: "Can Copy Projects Role", permissions: [:copy_projects])
end
shared_let(:can_add_subprojects_role) do
- create(:project_role, name: 'Can Add Subprojects Role', permissions: [:add_subprojects])
+ create(:project_role, name: "Can Add Subprojects Role", permissions: [:add_subprojects])
end
shared_let(:parent_project) do
create(:project,
- name: 'Parent project',
- identifier: 'parent-project')
+ name: "Parent project",
+ identifier: "parent-project")
end
shared_let(:can_copy_projects_manager) do
@@ -907,8 +910,8 @@ def expect_projects_in_order(*projects)
expect(page).to have_text(parent_project.name)
# 'More' does not become visible on hover
- page.find('tbody tr').hover
- expect(page).to have_no_css('.icon-show-more-horizontal')
+ page.find("tbody tr").hover
+ expect(page).to have_no_css(".icon-show-more-horizontal")
# For a project member with :copy_projects privilege the 'More' menu is visible.
login_as(can_copy_projects_manager)
@@ -918,17 +921,17 @@ def expect_projects_in_order(*projects)
# 'More' becomes visible on hover
# because we use css opacity we can not test for the visibility changes
- page.find('tbody tr').hover
- expect(page).to have_css('.icon-show-more-horizontal')
+ page.find("tbody tr").hover
+ expect(page).to have_css(".icon-show-more-horizontal")
# Test visibility of 'more' menu list items
- page.find('tbody tr .icon-show-more-horizontal').click
- menu = page.find('tbody tr .project-actions')
- expect(menu).to have_text('Copy')
- expect(menu).to have_no_text('New subproject')
- expect(menu).to have_no_text('Delete')
- expect(menu).to have_no_text('Archive')
- expect(menu).to have_no_text('Unarchive')
+ page.find("tbody tr .icon-show-more-horizontal").click
+ menu = page.find("tbody tr .project-actions")
+ expect(menu).to have_text("Copy")
+ expect(menu).to have_no_text("New subproject")
+ expect(menu).to have_no_text("Delete")
+ expect(menu).to have_no_text("Archive")
+ expect(menu).to have_no_text("Unarchive")
# For a project member with :add_subprojects privilege the 'More' menu is visible.
login_as(can_add_subprojects_manager)
@@ -936,35 +939,35 @@ def expect_projects_in_order(*projects)
# 'More' becomes visible on hover
# because we use css opacity we can not test for the visibility changes
- page.find('tbody tr').hover
- expect(page).to have_css('.icon-show-more-horizontal')
+ page.find("tbody tr").hover
+ expect(page).to have_css(".icon-show-more-horizontal")
# Test visibility of 'more' menu list items
- page.find('tbody tr .icon-show-more-horizontal').click
- menu = page.find('tbody tr .project-actions')
- expect(menu).to have_text('New subproject')
- expect(menu).to have_no_text('Copy')
- expect(menu).to have_no_text('Delete')
- expect(menu).to have_no_text('Archive')
- expect(menu).to have_no_text('Unrchive')
+ page.find("tbody tr .icon-show-more-horizontal").click
+ menu = page.find("tbody tr .project-actions")
+ expect(menu).to have_text("New subproject")
+ expect(menu).to have_no_text("Copy")
+ expect(menu).to have_no_text("Delete")
+ expect(menu).to have_no_text("Archive")
+ expect(menu).to have_no_text("Unrchive")
# Test admin only properties are invisible
- within('#project-table') do
+ within("#project-table") do
expect(page)
- .to have_no_css('th', text: 'REQUIRED DISK STORAGE')
+ .to have_no_css("th", text: "REQUIRED DISK STORAGE")
expect(page)
- .to have_no_css('th', text: 'CREATED ON')
+ .to have_no_css("th", text: "CREATED ON")
expect(page)
- .to have_no_css('td', text: project.created_at.strftime('%m/%d/%Y'))
+ .to have_no_css("td", text: project.created_at.strftime("%m/%d/%Y"))
expect(page)
- .to have_no_css('th', text: 'LATEST ACTIVITY AT')
+ .to have_no_css("th", text: "LATEST ACTIVITY AT")
expect(page)
- .to have_no_css('td', text: news.created_at.strftime('%m/%d/%Y'))
+ .to have_no_css("td", text: news.created_at.strftime("%m/%d/%Y"))
end
end
end
- describe 'order', with_ee: %i[custom_fields_in_projects_list] do
+ describe "order", with_ee: %i[custom_fields_in_projects_list] do
shared_let(:integer_custom_field) { create(:integer_project_custom_field) }
# order is important here as the implementation uses lft
# first but then reorders in ruby
@@ -1002,7 +1005,7 @@ def expect_projects_in_order(*projects)
child_project_a.save!
end
- it 'allows to alter the order in which projects are displayed' do
+ it "allows to alter the order in which projects are displayed" do
Setting.enabled_projects_columns += [integer_custom_field.column_name]
# initially, ordered by name asc on each hierarchical level
@@ -1013,7 +1016,7 @@ def expect_projects_in_order(*projects)
child_project_z,
public_project)
- click_link('Name')
+ click_link_or_button("Name")
wait_for_reload
# Projects ordered by name asc
@@ -1024,7 +1027,7 @@ def expect_projects_in_order(*projects)
public_project,
child_project_z)
- click_link('Name')
+ click_link_or_button("Name")
wait_for_reload
# Projects ordered by name desc
@@ -1035,7 +1038,7 @@ def expect_projects_in_order(*projects)
development_project,
child_project_a)
- click_link(integer_custom_field.name)
+ click_link_or_button(integer_custom_field.name)
wait_for_reload
# Projects ordered by cf asc first then project name desc
@@ -1046,7 +1049,7 @@ def expect_projects_in_order(*projects)
child_project_m,
child_project_a)
- click_link('Sort by "Project hierarchy"')
+ click_link_or_button('Sort by "Project hierarchy"')
wait_for_reload
# again ordered by name asc on each hierarchical level
@@ -1059,17 +1062,17 @@ def expect_projects_in_order(*projects)
end
end
- describe 'blocked filter' do
- it 'is not visible' do
+ describe "blocked filter" do
+ it "is not visible" do
load_and_open_filters admin
- expect(page).to have_no_select('add_filter_select', with_options: ["Principal"])
- expect(page).to have_no_select('add_filter_select', with_options: ["ID"])
- expect(page).to have_no_select('add_filter_select', with_options: ["Subproject of"])
+ expect(page).to have_no_select("add_filter_select", with_options: ["Principal"])
+ expect(page).to have_no_select("add_filter_select", with_options: ["ID"])
+ expect(page).to have_no_select("add_filter_select", with_options: ["Subproject of"])
end
end
- describe 'column selection',
+ describe "column selection",
with_ee: %i[custom_fields_in_projects_list], with_settings: { enabled_projects_columns: %w[name created_at] } do
# Will still receive the :view_project permission
shared_let(:user) do
@@ -1096,54 +1099,54 @@ def expect_projects_in_order(*projects)
development_project.at_risk!
end
- it 'allows to select columns to be displayed' do
+ it "allows to select columns to be displayed" do
projects_page.visit!
- projects_page.set_columns('Name', 'Status', integer_custom_field.name)
+ projects_page.set_columns("Name", "Status", integer_custom_field.name)
- projects_page.expect_no_columns('Public', 'Description', 'Project status description')
+ projects_page.expect_no_columns("Public", "Description", "Project status description")
projects_page.within_row(project) do
expect(page)
- .to have_css('.name', text: project.name)
+ .to have_css(".name", text: project.name)
expect(page)
.to have_css(".cf_#{integer_custom_field.id}", text: 2)
expect(page)
- .to have_css('.project_status', text: 'OFF TRACK')
+ .to have_css(".project_status", text: "OFF TRACK")
expect(page)
- .to have_no_css('.created_at ')
+ .to have_no_css(".created_at ")
end
projects_page.within_row(public_project) do
expect(page)
- .to have_css('.name', text: public_project.name)
+ .to have_css(".name", text: public_project.name)
expect(page)
.to have_css(".cf_#{integer_custom_field.id}", text: 1)
expect(page)
- .to have_css('.project_status', text: 'ON TRACK')
+ .to have_css(".project_status", text: "ON TRACK")
expect(page)
- .to have_no_css('.created_at ')
+ .to have_no_css(".created_at ")
end
projects_page.within_row(development_project) do
expect(page)
- .to have_css('.name', text: development_project.name)
+ .to have_css(".name", text: development_project.name)
expect(page)
.to have_css(".cf_#{integer_custom_field.id}", text: 3)
expect(page)
- .to have_css('.project_status', text: 'AT RISK')
+ .to have_css(".project_status", text: "AT RISK")
expect(page)
- .to have_no_css('.created_at ')
+ .to have_no_css(".created_at ")
end
end
end
- context 'with a multi-value custom field', with_ee: %i[custom_fields_in_projects_list] do
+ context "with a multi-value custom field", with_ee: %i[custom_fields_in_projects_list] do
let!(:list_custom_field) { create(:list_project_custom_field, multi_value: true) }
before do
- project.custom_values << CustomValue.new(custom_field: list_custom_field, value: list_custom_field.value_of('A'))
- project.custom_values << CustomValue.new(custom_field: list_custom_field, value: list_custom_field.value_of('B'))
+ project.custom_values << CustomValue.new(custom_field: list_custom_field, value: list_custom_field.value_of("A"))
+ project.custom_values << CustomValue.new(custom_field: list_custom_field, value: list_custom_field.value_of("B"))
project.save!
@@ -1155,7 +1158,7 @@ def expect_projects_in_order(*projects)
visit projects_path
end
- it 'shows the multi selection' do
+ it "shows the multi selection" do
expected_sort = list_custom_field
.custom_options
.where(value: %w[A B])
@@ -1165,10 +1168,10 @@ def expect_projects_in_order(*projects)
end
end
- describe 'project activity menu item' do
- context 'for projects with activity module enabled' do
+ describe "project activity menu item" do
+ context "for projects with activity module enabled" do
shared_let(:project_with_activity_enabled) { project }
- shared_let(:work_packages_viewer) { create(:project_role, name: 'Viewer', permissions: [:view_work_packages]) }
+ shared_let(:work_packages_viewer) { create(:project_role, name: "Viewer", permissions: [:view_work_packages]) }
shared_let(:simple_member) do
create(:user,
member_with_roles: { project_with_activity_enabled => work_packages_viewer })
@@ -1180,7 +1183,7 @@ def expect_projects_in_order(*projects)
project_with_activity_enabled.save
end
- it 'is displayed and redirects to project activity page with only project attributes visible' do
+ it "is displayed and redirects to project activity page with only project attributes visible" do
login_as(simple_member)
visit projects_path
@@ -1188,13 +1191,13 @@ def expect_projects_in_order(*projects)
# 'More' becomes visible on hover
# because we use css opacity we can not test for the visibility changes
- page.find('tbody tr', text: project.name).hover
- expect(page).to have_css('.icon-show-more-horizontal')
+ page.find("tbody tr", text: project.name).hover
+ expect(page).to have_css(".icon-show-more-horizontal")
# "Project activity" item should be displayed in the 'more' menu
- page.find('tbody tr .icon-show-more-horizontal').click
+ page.find("tbody tr .icon-show-more-horizontal").click
- menu = page.find('tbody tr .project-actions')
+ menu = page.find("tbody tr .project-actions")
expect(menu).to have_text(I18n.t(:label_project_activity))
# Clicking the menu item should redirect to project activity page
@@ -1202,8 +1205,8 @@ def expect_projects_in_order(*projects)
menu.find_link(text: I18n.t(:label_project_activity)).click
expect(page).to have_current_path(project_activity_index_path(project_with_activity_enabled), ignore_query: true)
- expect(page).to have_checked_field(id: 'event_types_project_attributes')
- expect(page).to have_unchecked_field(id: 'event_types_work_packages')
+ expect(page).to have_checked_field(id: "event_types_project_attributes")
+ expect(page).to have_unchecked_field(id: "event_types_work_packages")
end
end
end
diff --git a/spec/support/components/projects/project_custom_fields/edit_dialog.rb b/spec/support/components/projects/project_custom_fields/edit_dialog.rb
index 3db7c11bbb03..3acdfad47f2c 100644
--- a/spec/support/components/projects/project_custom_fields/edit_dialog.rb
+++ b/spec/support/components/projects/project_custom_fields/edit_dialog.rb
@@ -50,7 +50,7 @@ def dialog_css_selector
end
def async_content_container_css_selector
- "#{dialog_css_selector} [data-qa-selector='async-dialog-content']"
+ "#{dialog_css_selector} [data-test-selector='async-dialog-content']"
end
def within_dialog(&)
@@ -77,7 +77,7 @@ def close_via_button
def submit
within(dialog_css_selector) do
- page.find("[data-qa-selector='save-project-attributes-button']").click
+ page.find("[data-test-selector='save-project-attributes-button']").click
end
end
@@ -104,7 +104,7 @@ def input_containers
def within_custom_field_input_container(custom_field, &)
# wrapping in `within_async_content` to make sure the container is properly loaded
within_async_content do
- within("[data-qa-selector='project-custom-field-input-container-#{custom_field.id}']", &)
+ within("[data-test-selector='project-custom-field-input-container-#{custom_field.id}']", &)
end
end
end
diff --git a/spec/support/pages/projects/show.rb b/spec/support/pages/projects/show.rb
index 5ad63c542823..ce537a482669 100644
--- a/spec/support/pages/projects/show.rb
+++ b/spec/support/pages/projects/show.rb
@@ -26,7 +26,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
-require 'support/pages/page'
+require "support/pages/page"
module Pages
module Projects
@@ -44,7 +44,7 @@ def path
end
def within_sidebar(&)
- within('#menu-sidebar', &)
+ within("#menu-sidebar", &)
end
def toast_type
@@ -56,29 +56,54 @@ def visit_page
end
def within_async_loaded_sidebar(&)
- within '#project-custom-fields-sidebar' do
- expect(page).to have_css("[data-qa-selector='project-custom-fields-sidebar-async-content']")
+ within "#project-custom-fields-sidebar" do
+ expect(page).to have_css("[data-test-selector='project-custom-fields-sidebar-async-content']")
yield
end
end
def within_custom_field_section_container(section, &)
- within("[data-qa-selector='project-custom-field-section-#{section.id}']", &)
+ within("[data-test-selector='project-custom-field-section-#{section.id}']", &)
end
def within_custom_field_container(custom_field, &)
- within("[data-qa-selector='project-custom-field-#{custom_field.id}']", &)
+ within("[data-test-selector='project-custom-field-#{custom_field.id}']", &)
end
def open_edit_dialog_for_section(section)
within_async_loaded_sidebar do
- scroll_to_element(page.find("[data-qa-selector='project-custom-field-section-#{section.id}']"))
+ scroll_to_element(page.find("[data-test-selector='project-custom-field-section-#{section.id}']"))
within_custom_field_section_container(section) do
- page.find("[data-qa-selector='project-custom-field-section-edit-button']").click
+ page.find("[data-test-selector='project-custom-field-section-edit-button']").click
end
end
- expect(page).to have_css("[data-qa-selector='async-dialog-content']", wait: 5)
+ expect(page).to have_css("[data-test-selector='async-dialog-content']", wait: 5)
+ end
+
+ def expand_text(custom_field)
+ within_custom_field_container(custom_field) do
+ page.find('[data-test-selector="expand-button"]').click
+ end
+ end
+
+ def expect_text_not_truncated(custom_field)
+ within_custom_field_container(custom_field) do
+ expect(page).to have_no_css('[data-test-selector="expand-button"]')
+ end
+ end
+
+ def expect_text_truncated(custom_field)
+ within_custom_field_container(custom_field) do
+ expect(page).to have_css('[data-test-selector="expand-button"]')
+ end
+ end
+
+ def expect_full_text_in_dialog(text)
+ within('[data-test-selector="attribute-dialog"]') do
+ expect(page)
+ .to have_content(text)
+ end
end
end
end