diff --git a/.changeset/popular-stingrays-cough.md b/.changeset/popular-stingrays-cough.md new file mode 100644 index 0000000000..feff572662 --- /dev/null +++ b/.changeset/popular-stingrays-cough.md @@ -0,0 +1,5 @@ +--- +'@openproject/primer-view-components': minor +--- + +Add `FeedbackDialog` and `FeedbackMessage` components to display different kinds of user feedback diff --git a/.gitignore b/.gitignore index 717b61ebcd..7bf5fc91be 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ lib/primer/forms/**/*.css lib/primer/forms/**/*.css.json lib/primer/forms/**/*.css.map lib/primer/forms/**/*.d.ts -app/assets/ +app/assets/* # Generated by demo npm post-install demo/app/assets/stylesheets/primer* @@ -57,3 +57,6 @@ demo/app/assets/builds/ # IDE folders .idea + +# OpenProject custom rules +!app/assets/images diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark.png new file mode 100644 index 0000000000..84e20808c7 Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark_colorblind.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark_colorblind.png new file mode 100644 index 0000000000..bc5da8928a Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark_colorblind.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark_dimmed.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark_dimmed.png new file mode 100644 index 0000000000..34b2d5141c Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark_dimmed.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark_high_contrast.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark_high_contrast.png new file mode 100644 index 0000000000..944b2d92ff Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/dark_high_contrast.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/default.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/default.png new file mode 100644 index 0000000000..5f74991a47 Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/default.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/focused.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/focused.png new file mode 100644 index 0000000000..d9c638e6dc Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/focused.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/light.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/light.png new file mode 100644 index 0000000000..c0787aa915 Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/light.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/light_colorblind.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/light_colorblind.png new file mode 100644 index 0000000000..b82ccd3e4f Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/light_colorblind.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/light_high_contrast.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/light_high_contrast.png new file mode 100644 index 0000000000..d16ae1919f Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_dialog/default/light_high_contrast.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_message/default/default.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_message/default/default.png new file mode 100644 index 0000000000..78a107fbb3 Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_message/default/default.png differ diff --git a/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_message/default/focused.png b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_message/default/focused.png new file mode 100644 index 0000000000..78a107fbb3 Binary files /dev/null and b/.playwright/screenshots/snapshots.test.ts-snapshots/primer/open_project/feedback_message/default/focused.png differ diff --git a/app/assets/images/loading_indicator.svg b/app/assets/images/loading_indicator.svg new file mode 100644 index 0000000000..6f42526c43 --- /dev/null +++ b/app/assets/images/loading_indicator.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/components/primer/open_project/feedback_dialog.html.erb b/app/components/primer/open_project/feedback_dialog.html.erb new file mode 100644 index 0000000000..b9de1f6859 --- /dev/null +++ b/app/components/primer/open_project/feedback_dialog.html.erb @@ -0,0 +1,15 @@ +<%= render @dialog do |dialog| %> + <% dialog.with_body do %> + <%= feedback_message %> + <% if additional_content.present? %> + <%= additional_content %> + <% end %> + <% end %> + <% dialog.with_footer do %> + <% if footer.present? %> + <%= footer %> + <% else %> + <%= render(Primer::Beta::Button.new("data-close-dialog-id": @system_arguments[:id])) { I18n.t("button_close") } %> + <% end %> + <% end %> +<% end %> diff --git a/app/components/primer/open_project/feedback_dialog.rb b/app/components/primer/open_project/feedback_dialog.rb new file mode 100644 index 0000000000..bf12929e7a --- /dev/null +++ b/app/components/primer/open_project/feedback_dialog.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Primer + module OpenProject + # A pre-configured dialog which includes the FeedbackMessage + class FeedbackDialog < Primer::Component + status :open_project + + # A feedback message with some defaults that are necessary for rendering nicely + # + # @param heading [String] the heading for the success message + # @param description [String] the description for the success message + # @param icon_arguments [Hash] the system_arguments for the icon + # @param system_arguments [Hash] <%= link_to_system_arguments_docs %> + renders_one :feedback_message, lambda { |icon_arguments: {}, **system_arguments| + system_arguments[:border] = false + Primer::OpenProject::FeedbackMessage.new(icon_arguments: icon_arguments, **system_arguments) + } + + # Optional additional_content like a form input or toast. + # + # @param system_arguments [Hash] <%= link_to_system_arguments_docs %> + renders_one :additional_content, lambda { |**system_arguments| + deny_tag_argument(**system_arguments) + system_arguments[:tag] = :div + system_arguments[:classes] = class_names( + system_arguments[:classes], + "FeedbackDialog-additionalContent" + ) + + system_arguments[:display] ||= :flex + system_arguments[:align_items] ||= :center + system_arguments[:justify_content] ||= :center + system_arguments[:mb] ||= 3 + + Primer::BaseComponent.new(**system_arguments) + } + + renders_one :footer + + # @param system_arguments [Hash] <%= link_to_system_arguments_docs %> + def initialize(**system_arguments) + @system_arguments = system_arguments + @system_arguments[:classes] = class_names( + system_arguments[:classes], + "FeedbackDialog" + ) + @system_arguments[:id] ||= self.class.generate_id + + @dialog = Primer::Alpha::Dialog.new(title: @system_arguments[:title], subtitle: nil, visually_hide_title: true, **@system_arguments) + end + + delegate :header?, :header, :with_header, :with_header_content, + :show_button?, :show_button, :with_show_button, :with_show_button_content, + to: :@dialog + + private + + def before_render + content + end + end + end +end diff --git a/app/components/primer/open_project/feedback_message.html.erb b/app/components/primer/open_project/feedback_message.html.erb new file mode 100644 index 0000000000..01738d7fe0 --- /dev/null +++ b/app/components/primer/open_project/feedback_message.html.erb @@ -0,0 +1 @@ +<%= render(@blankslate) %> diff --git a/app/components/primer/open_project/feedback_message.rb b/app/components/primer/open_project/feedback_message.rb new file mode 100644 index 0000000000..cd0bfeab62 --- /dev/null +++ b/app/components/primer/open_project/feedback_message.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Primer + module OpenProject + # A view component for messages, inspired by the Primer Blankslate, + # which serves a different use-case (messages for when data is missing). + # We decided to wrap the Blankslate, because we don't want to have to adapt + # lots of different usages if Primer decides to change the Blankslate + # in a way that does not go well with our "misuse". + class FeedbackMessage < Primer::Component + status :open_project + + # @param icon_arguments [Hash] special arguments for the icon + # @param loading [Boolean] Show a loading spinner instead of an icon + # @param system_arguments [Hash] <%= link_to_system_arguments_docs %> + def initialize(icon_arguments: {}, loading: false, **system_arguments) + @system_arguments = system_arguments + @icon_arguments = icon_arguments + @system_arguments[:classes] = class_names( + system_arguments[:classes], + "FeedbackMessage" + ) + + @icon_arguments[:icon] ||= :"check-circle" + @icon_arguments[:color] ||= :success + + @loading = loading + + @blankslate = Primer::Beta::Blankslate.new(**@system_arguments) + end + + delegate :description?, :description, :with_description, :with_description_content, + :heading?, :heading, :with_heading, :with_heading_content, + to: :@blankslate + + private + + def before_render + if @loading + @blankslate.with_visual_image(src: asset_path("loading_indicator.svg"), alt: I18n.t(:label_loading)) + else + @blankslate.with_visual_icon(size: :medium, **@icon_arguments) + end + + content + end + + def render? + heading.present? + end + end + end +end diff --git a/previews/primer/open_project/feedback_dialog_preview.rb b/previews/primer/open_project/feedback_dialog_preview.rb new file mode 100644 index 0000000000..27b6bff5be --- /dev/null +++ b/previews/primer/open_project/feedback_dialog_preview.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +# Setup Playground to use all available component props +# Setup Features to use individual component props and combinations + +module Primer + module OpenProject + # @label FeedbackDialog + class FeedbackDialogPreview < ViewComponent::Preview + # @label Default + # @snapshot interactive + def default + render(Primer::OpenProject::FeedbackDialog.new(title: "Success dialog")) do |dialog| + dialog.with_show_button { "Click me" } + dialog.with_feedback_message do |message| + message.with_heading(tag: :h2) { "Success" } + message.with_description { "Great! Everything worked well." } + end + end + end + + # @label Playground + # @param icon [Symbol] octicon + # @param icon_color [Symbol] select [default, muted, subtle, accent, success, attention, severe, danger, open, closed, done, sponsors, on_emphasis, inherit] + # @param loading_state [Boolean] toggle + # @param show_description toggle + # @param show_additional_content toggle + # @param custom_footer toggle + def playground(icon: :"check-circle", icon_color: :success, loading_state: false, show_description: true, show_additional_content: false, custom_footer: false) + render_with_template(locals: { icon: icon, + icon_color: icon_color, + loading_state: loading_state, + show_description: show_description, + show_additional_content: show_additional_content, + custom_footer: custom_footer }) + end + + # @label With additional content + def additional_content + render_with_template(locals: {}) + end + + # @label With custom icon + def custom_icon + render(Primer::OpenProject::FeedbackDialog.new(title: "Error message")) do |dialog| + dialog.with_show_button { "Click me" } + dialog.with_feedback_message(icon_arguments: { icon: :"x-circle", color: :danger }) do |message| + message.with_heading(tag: :h2) { "Ups, something went wrong" } + message.with_description { "Please try again or contact your administrator if the issue persists." } + end + end + end + + # @label With custom footer + def custom_footer + render_with_template(locals: {}) + end + + # @label With loading spinner + def loading_spinner + render(Primer::OpenProject::FeedbackDialog.new(title: "Waiting...")) do |dialog| + dialog.with_show_button { "Click me" } + dialog.with_feedback_message(loading: true) do |message| + message.with_heading(tag: :h2) { "Please wait, your request is being processed." } + end + end + end + end + end +end diff --git a/previews/primer/open_project/feedback_dialog_preview/additional_content.html.erb b/previews/primer/open_project/feedback_dialog_preview/additional_content.html.erb new file mode 100644 index 0000000000..9e90b4aa2f --- /dev/null +++ b/previews/primer/open_project/feedback_dialog_preview/additional_content.html.erb @@ -0,0 +1,9 @@ +<%= render(Primer::OpenProject::FeedbackDialog.new) do |dialog| %> + <% dialog.with_show_button { "Click me" } %> + <% dialog.with_feedback_message do |message| %> + <% message.with_heading(tag: :h2).with_content("Action successful") %> + <% end %> + <% dialog.with_additional_content do %> + <% render(Primer::Beta::Text.new) { "You can render whatever component you want here." } %> + <% end %> +<% end %> diff --git a/previews/primer/open_project/feedback_dialog_preview/custom_footer.html.erb b/previews/primer/open_project/feedback_dialog_preview/custom_footer.html.erb new file mode 100644 index 0000000000..d7a85106ee --- /dev/null +++ b/previews/primer/open_project/feedback_dialog_preview/custom_footer.html.erb @@ -0,0 +1,10 @@ +<%= render(Primer::OpenProject::FeedbackDialog.new(id: "my-dialog")) do |dialog| %> + <% dialog.with_show_button { "Click me" } %> + <% dialog.with_feedback_message do |message| %> + <% message.with_heading(tag: :h2).with_content("Action successful") %> + <% end %> + <% dialog.with_footer do %> + <%= render(Primer::Beta::Button.new("data-close-dialog-id": "my-dialog")) { "Cancel" } %> + <%= render(Primer::Beta::Button.new(scheme: :primary)) { "Accept" } %> + <% end %> +<% end %> diff --git a/previews/primer/open_project/feedback_dialog_preview/playground.html.erb b/previews/primer/open_project/feedback_dialog_preview/playground.html.erb new file mode 100644 index 0000000000..1e21127848 --- /dev/null +++ b/previews/primer/open_project/feedback_dialog_preview/playground.html.erb @@ -0,0 +1,18 @@ +<%= render(Primer::OpenProject::FeedbackDialog.new(id: "my-dialog")) do |dialog| %> + <% dialog.with_show_button { "Click me" } %> + <% dialog.with_feedback_message(icon_arguments: { icon: icon, color: icon_color }, loading: loading_state) do |message| %> + <% message.with_heading(tag: :h2).with_content("Awesome!") %> + <% message.with_description { "Great! Everything worked well." } if show_description %> + <% end %> + <% if show_additional_content %> + <% dialog.with_additional_content(display: :inline) do %> + <%= render(Primer::Alpha::Banner.new) { "Some additional content below" } %> + <% end %> + <% end %> + <% if custom_footer %> + <% dialog.with_footer do %> + <%= render(Primer::Beta::Button.new("data-close-dialog-id": "my-dialog")) { "Cancel" } %> + <%= render(Primer::Beta::Button.new(scheme: :primary)) { "Accept" } %> + <% end %> + <% end %> +<% end %> diff --git a/previews/primer/open_project/feedback_message_preview.rb b/previews/primer/open_project/feedback_message_preview.rb new file mode 100644 index 0000000000..6b8599d6d0 --- /dev/null +++ b/previews/primer/open_project/feedback_message_preview.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Primer + module OpenProject + # @label FeedbackMessage + class FeedbackMessagePreview < ViewComponent::Preview + # @label Default + # @snapshot + def default + render Primer::OpenProject::FeedbackMessage.new do |component| + component.with_heading(tag: :h2) { "Success" } + component.with_description { "You successfully created your first FeedbackMessage component" } + end + end + + + # @label Playground + # + # @param icon [Symbol] octicon + # @param icon_color [Symbol] select [default, muted, subtle, accent, success, attention, severe, danger, open, closed, done, sponsors, on_emphasis, inherit] + # @param loading_state [Boolean] toggle + # @param title [String] + # @param description [String] + # @param narrow [Boolean] toggle + # @param spacious [Boolean] toggle + # @param border [Boolean] toggle + def playground(icon: "check-circle", icon_color: :success, loading_state: false, title: "Yeah!", description: "Some description below...", narrow: false, spacious: false, border: false) + render Primer::OpenProject::FeedbackMessage.new(icon_arguments: { icon: icon, color: icon_color}, loading: loading_state, narrow: narrow, spacious: spacious, border: border) do |component| + component.with_heading(tag: :h2).with_content(title) + component.with_description { description } + end + end + + # @label With custom icon + def with_custom_icon + render Primer::OpenProject::FeedbackMessage.new(icon_arguments: { icon: :"op-enterprise-addons", classes: "upsale-colored" }) do |component| + component.with_heading(tag: :h2) { "You are a hero" } + component.with_description { "Thanks for supporting an open source project!" } + end + end + + # @label With custom color + def with_custom_color + render Primer::OpenProject::FeedbackMessage.new(icon_arguments: { icon: :"x-circle", color: :danger }) do |component| + component.with_heading(tag: :h2) { "Ups, something went wrong" } + component.with_description { "Please try again or contact your administrator." } + end + end + + # @label With loading spinner + def loading_spinner + render(Primer::OpenProject::FeedbackMessage.new(loading: true)) do |component| + component.with_heading(tag: :h2) { "Please wait, your request is being processed." } + end + end + end + end +end diff --git a/test/components/component_test.rb b/test/components/component_test.rb index 8c0bcd81e2..f55ea9b8bf 100644 --- a/test/components/component_test.rb +++ b/test/components/component_test.rb @@ -8,6 +8,14 @@ class PrimerComponentTest < Minitest::Test # Components with any arguments necessary to make them render COMPONENTS_WITH_ARGS = [ + [Primer::OpenProject::FeedbackDialog, {}, proc { |component| + component.with_feedback_message do |feedback| + feedback.with_heading(tag: :h2) { "You are a hero" } + end + }], + [Primer::OpenProject::FeedbackMessage, {}, proc { |component| + component.with_heading(tag: :h2) { "Foo" } + }], [Primer::OpenProject::SidePanel, {}, proc { |component| component.with_section do |section| section.with_title { "First" } diff --git a/test/components/primer/open_project/feedback_dialog_test.rb b/test/components/primer/open_project/feedback_dialog_test.rb new file mode 100644 index 0000000000..eb9997570f --- /dev/null +++ b/test/components/primer/open_project/feedback_dialog_test.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require "components/test_helper" + +class PrimerOpenProjectFeedbackDialogTest < Minitest::Test + include Primer::ComponentTestHelpers + + def test_renders + render_inline(Primer::OpenProject::FeedbackDialog.new) do |dialog| + dialog.with_feedback_message do |message| + message.with_heading(tag: :h2) { "Success" } + end + end + + assert_selector("dialog.FeedbackDialog") do + assert_selector(".Overlay-body h2", text: "Success") + assert_selector(".octicon-check-circle.blankslate-icon") + assert_selector(".Overlay-footer .Button") + end + end + + def test_renders_additional_content + render_inline(Primer::OpenProject::FeedbackDialog.new) do |dialog| + dialog.with_feedback_message do |message| + message.with_heading(tag: :h2) { "Success" } + end + dialog.with_additional_content { "Some additional content" } + end + + assert_selector("dialog.FeedbackDialog") do + assert_selector(".FeedbackDialog-additionalContent", text: "Some additional content") + end + end + + def test_renders_custom_footer + render_inline(Primer::OpenProject::FeedbackDialog.new) do |dialog| + dialog.with_feedback_message do |message| + message.with_heading(tag: :h2) { "Success" } + end + dialog.with_footer { "My custom footer" } + end + + assert_selector("dialog.FeedbackDialog") do + assert_selector(".Overlay-footer", text: "My custom footer") + end + end + + def test_renders_custom_icon + render_inline(Primer::OpenProject::FeedbackDialog.new) do |dialog| + dialog.with_feedback_message(icon_arguments: { icon: :"x-circle", color: :danger }) do |message| + message.with_heading(tag: :h2) { "Ups, something went wrong" } + message.with_description { "Please try again or contact your administrator if the issue persists." } + end + end + + assert_selector("dialog.FeedbackDialog") do + assert_selector(".Overlay-body h2", text: "Ups, something went wrong") + assert_selector(".Overlay-body p", text: "Please try again or contact your administrator if the issue persists.") + assert_selector(".octicon-x-circle.blankslate-icon") + end + end + + def test_renders_loading_spinner + render_inline(Primer::OpenProject::FeedbackDialog.new) do |dialog| + dialog.with_feedback_message(loading: true) do |message| + message.with_heading(tag: :h2) { "Ups, something went wrong" } + end + end + + assert_selector("dialog.FeedbackDialog") do + assert_selector(".Overlay-body h2", text: "Ups, something went wrong") + assert_selector("img.blankslate-image[src^='/assets/loading_indicator']") + end + end +end diff --git a/test/components/primer/open_project/feedback_message_test.rb b/test/components/primer/open_project/feedback_message_test.rb new file mode 100644 index 0000000000..bab6409e94 --- /dev/null +++ b/test/components/primer/open_project/feedback_message_test.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require "components/test_helper" + +class PrimerOpenProjectFeedbackMessageTest < Minitest::Test + include Primer::ComponentTestHelpers + + def test_renders + render_inline(Primer::OpenProject::FeedbackMessage.new) do |component| + component.with_heading(tag: :h2).with_content("Some title") + component.with_description { "Some description" } + end + + assert_selector "h2", text: "Some title" + assert_text "Some description" + + # Check for default octicon and color + assert_selector ".octicon-check-circle.blankslate-icon.color-fg-success" + end + + def test_does_not_render_if_no_heading_provided + render_inline(Primer::OpenProject::FeedbackMessage.new) + + refute_component_rendered + end + + def test_custom_icon + render_inline(Primer::OpenProject::FeedbackMessage.new(icon_arguments: { icon: "plus", color: :danger, classes: "test-class" })) do |component| + component.with_heading(tag: :h2).with_content("Some title") + end + + assert_selector "h2", text: "Some title" + + # Check for default octicon and color + assert_selector ".octicon-plus.blankslate-icon.color-fg-danger.test-class" + end + + def test_renders_loading_spinner + render_inline(Primer::OpenProject::FeedbackMessage.new(loading: true)) do |dialog| + dialog.with_heading(tag: :h2) { "Ups, something went wrong" } + end + + assert_selector("h2", text: "Ups, something went wrong") + assert_selector("img.blankslate-image[src^='/assets/loading_indicator']") + end +end diff --git a/test/system/open_project/feedback_dialog_test.rb b/test/system/open_project/feedback_dialog_test.rb new file mode 100644 index 0000000000..d8a76eb7fb --- /dev/null +++ b/test/system/open_project/feedback_dialog_test.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require "system/test_case" + +class IntegrationOpenProjectFeedbackDialogTest < System::TestCase + def test_renders_component + visit_preview(:default) + + click_button("Click me") + + assert_selector(".FeedbackDialog") + end +end diff --git a/test/system/open_project/feedback_message_test.rb b/test/system/open_project/feedback_message_test.rb new file mode 100644 index 0000000000..cf82d40cef --- /dev/null +++ b/test/system/open_project/feedback_message_test.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require "system/test_case" + +class IntegrationOpenProjectFeedbackMessageTest < System::TestCase + def test_renders_component + visit_preview(:default) + + assert_selector(".FeedbackMessage") + end +end