From bdb76ce44623453b61df33234c42c510e2d59002 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Sun, 17 Mar 2024 22:21:35 +0100 Subject: [PATCH] Add alchemy-message component And use this for Rails `flash` messages, `render_message` helper and `Alchemy.growl` notices. --- .../alchemy/alchemy.dialog.js.coffee | 19 +- app/assets/stylesheets/alchemy/flash.scss | 84 ++----- app/assets/stylesheets/alchemy/notices.scss | 87 ++++--- app/components/alchemy/admin/message.rb | 19 ++ app/helpers/alchemy/base_helper.rb | 32 +-- app/javascript/alchemy_admin.js | 1 + .../alchemy_admin/components/message.js | 69 ++++++ app/javascript/alchemy_admin/growler.js | 37 +-- app/javascript/alchemy_admin/initializer.js | 7 - .../alchemy/admin/partials/_flash.html.erb | 4 - .../admin/partials/_flash_notices.html.erb | 4 +- .../alchemy/admin/styleguide/index.html.erb | 37 +-- app/views/alchemy/base/error_notice.html.erb | 4 +- spec/components/alchemy/admin/message_spec.rb | 55 +++++ spec/features/admin/nodes_management_spec.rb | 2 +- spec/helpers/alchemy/base_helper_spec.rb | 80 +++---- .../alchemy_admin/components/message.spec.js | 216 ++++++++++++++++++ .../admin/elements/element_view_spec.rb | 8 +- .../alchemy/ingredients/select_editor_spec.rb | 2 +- 19 files changed, 513 insertions(+), 254 deletions(-) create mode 100644 app/components/alchemy/admin/message.rb create mode 100644 app/javascript/alchemy_admin/components/message.js delete mode 100644 app/views/alchemy/admin/partials/_flash.html.erb create mode 100644 spec/components/alchemy/admin/message_spec.rb create mode 100644 spec/javascript/alchemy_admin/components/message.spec.js diff --git a/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee b/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee index ba1116649d..3d9fbfe62a 100644 --- a/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +++ b/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee @@ -136,10 +136,10 @@ class window.Alchemy.Dialog else error_header = "#{xhr.statusText} (#{xhr.status})" error_body = "Please check log and try again." - $errorDiv = $("
") - $errorDiv.append Alchemy.messageIcon(error_type) - $errorDiv.append "

#{error_header}

" - $errorDiv.append "

#{error_body}

" + $errorDiv = $(" +

#{error_header}

+

#{error_body}

+
") $container.html $errorDiv # Binds close events on: @@ -265,14 +265,3 @@ window.Alchemy.watchForDialogs = (scope = '#alchemy') -> return event.preventDefault() return - -# Returns a Remix icon for given message type -# -window.Alchemy.messageIcon = (messageType) -> - icon_name = switch messageType - when "warning", "warn", "alert" then "alert" - when "notice" then "check" - when "info" then "information" - when "error" then "bug" - else messageType - "" diff --git a/app/assets/stylesheets/alchemy/flash.scss b/app/assets/stylesheets/alchemy/flash.scss index 0a5ca3589d..a38b2cc5c4 100644 --- a/app/assets/stylesheets/alchemy/flash.scss +++ b/app/assets/stylesheets/alchemy/flash.scss @@ -5,74 +5,28 @@ div#flash_notices { width: 400px; top: 0; - .flash.error { - cursor: pointer; - padding-right: 32px; - - alchemy-icon[name="close"] { - position: absolute; - left: initial; - right: 2 * $default-padding; + alchemy-message { + font-weight: bold; + margin: $default-margin $default-margin 2 * $default-margin; + opacity: 0.95; + transition-property: opacity, transform; + transition-duration: 0.4s; + + &.dismissed { + display: block; + opacity: 0; + transform: translate3d(0, -100%, 0); } - } -} - -div.flash { - border-radius: $default-border-radius; - opacity: 0.95; - padding: 8px 16px 8px 32px; - font-weight: bold; - border-width: 1px; - border-style: solid; - z-index: 1000; - margin: $default-margin $default-margin 2 * $default-margin; - position: relative; - min-height: 2.6em; - word-break: break-word; - transition-property: opacity, transform; - transition-duration: 0.4s; - line-height: 1.5; - alchemy-icon { - position: absolute; - top: 9px; - left: 2 * $default-padding; - vertical-align: bottom; + &[type="error"] { + cursor: pointer; + padding-right: 32px; - .icon { - fill: currentColor; + alchemy-icon[name="close"] { + position: absolute; + left: initial; + right: 2 * $default-padding; + } } } - - &.dismissed { - display: block; - opacity: 0; - transform: translate3d(0, -100%, 0); - } - - &.notice { - border-color: $success_border_color; - color: $success_text_color; - background-color: $success_background_color; - } - - &.error { - border-color: $error_border_color; - color: $error_text_color; - background-color: $error_background_color; - } - - &.info { - border-color: $info_border_color; - color: $info_text_color; - background-color: $info_background_color; - } - - &.warn, - &.warning, - &.alert { - border-color: $warning_border_color; - color: $warning_text_color; - background-color: $warning_background_color; - } } diff --git a/app/assets/stylesheets/alchemy/notices.scss b/app/assets/stylesheets/alchemy/notices.scss index 2a9a512b5c..51e472d1b0 100644 --- a/app/assets/stylesheets/alchemy/notices.scss +++ b/app/assets/stylesheets/alchemy/notices.scss @@ -1,18 +1,51 @@ -// Some table columns also have .message class -div.message { - padding: 8px 8px 8px 32px; - line-height: 17px; +alchemy-message { + display: block; border-width: $default-border-width; border-style: $default-border-style; border-radius: $default-border-radius; position: relative; + padding: 8px 16px 8px 32px; margin-bottom: 8px; text-align: left; + min-height: 2.6em; + word-break: break-word; + line-height: 1.5; - h1, - h2, - h3 { - margin-top: 0; + &[type="footnote"] { + font-size: $small-font-size; + margin: 16px; + } + + &[type="notice"] { + border-color: $success_border_color; + color: $success_text_color; + background-color: $success_background_color; + } + + &[type="hint"] { + background-color: $hint-background-color; + border-color: $hint-background-color; + color: $hint-text-color; + } + + &[type="info"] { + background-color: $info_background_color; + border-color: $info_border_color; + color: $info_text_color; + } + + &[type="error"] { + background-color: $error_background_color; + border-color: $error_border_color; + color: $error_text_color; + } + + &[type="warning"], + &[type="warn"], + &[type="alert"] { + background-color: $warning_background_color; + border-color: $warning_border_color; + color: $warning_text_color; } alchemy-icon { @@ -26,9 +59,15 @@ div.message { } } - &.footnote { - font-size: $small-font-size; - margin: 16px; + h1 { + font-size: 1.3rem; + line-height: 1.1; + } + + h1, + h2, + h3 { + margin-top: 0; } a { @@ -49,30 +88,4 @@ div.message { margin-bottom: 4px; } } - - &.hint { - background-color: $hint-background-color; - border-color: $hint-background-color; - color: $hint-text-color; - } - - &.info { - background-color: $info_background_color; - border-color: $info_border_color; - color: $info_text_color; - } - - &.error { - background-color: $error_background_color; - border-color: $error_border_color; - color: $error_text_color; - } - - &.warning, - &.warn, - &.alert { - background-color: $warning_background_color; - border-color: $warning_border_color; - color: $warning_text_color; - } } diff --git a/app/components/alchemy/admin/message.rb b/app/components/alchemy/admin/message.rb new file mode 100644 index 0000000000..7c9dd3bcf0 --- /dev/null +++ b/app/components/alchemy/admin/message.rb @@ -0,0 +1,19 @@ +module Alchemy + module Admin + class Message < ViewComponent::Base + attr_reader :message, :type, :dismissable + + erb_template <<~ERB + > + <%= message || content %> + + ERB + + def initialize(message = nil, type: :info, dismissable: false) + @message = message + @dismissable = dismissable + @type = type + end + end + end +end diff --git a/app/helpers/alchemy/base_helper.rb b/app/helpers/alchemy/base_helper.rb index 07a9fcf624..44124aec63 100644 --- a/app/helpers/alchemy/base_helper.rb +++ b/app/helpers/alchemy/base_helper.rb @@ -41,21 +41,16 @@ def render_icon(icon_name, options = {}) # <% end %> # def render_message(type = :info, msg = nil, &blk) - icon_class = message_icon_class(type) - if blk - content_tag :div, render_icon(icon_class) + capture(&blk), class: "#{type} message" - else - content_tag :div, render_icon(icon_class) + msg, class: "#{type} message" - end + render Alchemy::Admin::Message.new(msg || capture(&blk), type: type) end - # Renders the flash partial (+alchemy/admin/partials/flash+) + # Renders a dismissable growl message. # - # @param [String] notice The notice you want to display - # @param [Symbol] style The style of this flash. Valid values are +:notice+ (default), +:warn+ and +:error+ + # @param [String] notice - The notice you want to display + # @param [Symbol] type - The type of this flash. Valid values are +:notice+ (default), +:warn+, +:info+ and +:error+ # - def render_flash_notice(notice, style = :notice) - render("alchemy/admin/partials/flash", flash_type: style, message: notice) + def render_flash_notice(notice, type = :notice) + render Alchemy::Admin::Message.new(notice, type: type, dismissable: true) end # Checks if the given argument is a String or a Page object. @@ -77,20 +72,5 @@ def page_or_find(page) page end end - - # Returns the icon name for given message type - # - # @param message_type [String] The message type. One of +warning+, +info+, +notice+, +error+ - # @return [String] The icon name - def message_icon_class(message_type) - case message_type.to_s - when "warning", "warn", "alert" then "exclamation" - when "notice" then "check" - when "error" then "bug" - when "hint" then "info" - else - message_type - end - end end end diff --git a/app/javascript/alchemy_admin.js b/app/javascript/alchemy_admin.js index f3cee5d0ee..0e94f13757 100644 --- a/app/javascript/alchemy_admin.js +++ b/app/javascript/alchemy_admin.js @@ -26,6 +26,7 @@ import "alchemy_admin/components/clipboard_button" import "alchemy_admin/components/datepicker" import "alchemy_admin/components/dialog_link" import "alchemy_admin/components/element_editor" +import "alchemy_admin/components/message" import "alchemy_admin/components/growl" import "alchemy_admin/components/icon" import "alchemy_admin/components/ingredient_group" diff --git a/app/javascript/alchemy_admin/components/message.js b/app/javascript/alchemy_admin/components/message.js new file mode 100644 index 0000000000..6380cdd45d --- /dev/null +++ b/app/javascript/alchemy_admin/components/message.js @@ -0,0 +1,69 @@ +const DISMISS_DELAY = 5000 + +class Message extends HTMLElement { + #message + + constructor() { + super() + this.#message = this.innerHTML + if (this.dismissable || this.type === "error") { + this.addEventListener("click", this) + } + } + + handleEvent(event) { + if (event.type === "click") { + this.dismiss() + } + } + + connectedCallback() { + this.innerHTML = ` + + ${this.dismissable && this.type === "error" ? '' : ""} + ${this.#message} + ` + if (this.dismissable && this.type !== "error") { + setTimeout(() => { + this.dismiss() + }, this.delay) + } + } + + dismiss() { + this.addEventListener("transitionend", () => this.remove()) + this.classList.add("dismissed") + } + + get dismissable() { + return this.hasAttribute("dismissable") + } + + get type() { + return this.getAttribute("type") || "notice" + } + + get delay() { + return parseInt(this.getAttribute("delay") || DISMISS_DELAY) + } + + get iconName() { + switch (this.type) { + case "warning": + case "warn": + case "alert": + return "alert" + case "notice": + return "check" + case "info": + case "hint": + return "information" + case "error": + return "bug" + default: + return this.type + } + } +} + +customElements.define("alchemy-message", Message) diff --git a/app/javascript/alchemy_admin/growler.js b/app/javascript/alchemy_admin/growler.js index dc8c5d9e92..2b25dbdeb3 100644 --- a/app/javascript/alchemy_admin/growler.js +++ b/app/javascript/alchemy_admin/growler.js @@ -1,36 +1,13 @@ import { createHtmlElement } from "alchemy_admin/utils/dom_helpers" function build(message, flashType) { - const notices = document.getElementById("flash_notices") - const flashContainer = createHtmlElement( - `
` - ) - const icon = createHtmlElement(Alchemy.messageIcon(flashType)) - flashContainer.append(icon) - if (flashType === "error") { - const closeButton = createHtmlElement( - '' - ) - flashContainer.append(closeButton) - } - flashContainer.append(message) - notices.append(flashContainer) - flashContainer.addEventListener("click", () => dismiss(flashContainer)) - - fade() -} - -function dismiss(element) { - element.addEventListener("transitionend", () => element.remove()) - element.classList.add("dismissed") -} - -export function fade() { - const notices = document.getElementById("flash_notices") - const flashNotices = notices.querySelectorAll(".flash:not(.error)") - setTimeout(() => { - flashNotices.forEach((notice) => dismiss(notice)) - }, 5000) + const flashNotices = document.getElementById("flash_notices") + const flashMessage = createHtmlElement(` + + ${message} + + `) + flashNotices.append(flashMessage) } export function growl(message, style = "notice") { diff --git a/app/javascript/alchemy_admin/initializer.js b/app/javascript/alchemy_admin/initializer.js index 69e1d3fbbb..fb0fbd4017 100644 --- a/app/javascript/alchemy_admin/initializer.js +++ b/app/javascript/alchemy_admin/initializer.js @@ -1,5 +1,3 @@ -import { fade as fadeGrowl } from "alchemy_admin/growler" - /** * add change listener to select to redirect the user after selecting another locale or site * @param {string} selectId @@ -27,11 +25,6 @@ function Initialize() { // Initialize the GUI. Alchemy.GUI.init() - // Fade all growl notifications. - if ($("#flash_notices").length > 0) { - fadeGrowl() - } - // Add observer for please wait overlay. $(".please_wait") .not("*[data-alchemy-confirm]") diff --git a/app/views/alchemy/admin/partials/_flash.html.erb b/app/views/alchemy/admin/partials/_flash.html.erb deleted file mode 100644 index 7a94803849..0000000000 --- a/app/views/alchemy/admin/partials/_flash.html.erb +++ /dev/null @@ -1,4 +0,0 @@ -
- <%= render_icon message_icon_class(flash_type) %> - <%= message %> -
diff --git a/app/views/alchemy/admin/partials/_flash_notices.html.erb b/app/views/alchemy/admin/partials/_flash_notices.html.erb index 2aa7496122..3ff6440cf4 100644 --- a/app/views/alchemy/admin/partials/_flash_notices.html.erb +++ b/app/views/alchemy/admin/partials/_flash_notices.html.erb @@ -1,5 +1,7 @@
<% flash.keys.each do |flash_type| %> - <%= render_flash_notice(flash[flash_type.to_sym], flash_type) if flash[flash_type.to_sym].present? %> + <% if flash[flash_type.to_sym].present? %> + <%= render_flash_notice(flash[flash_type.to_sym], flash_type) %> + <% end %> <% end %>
diff --git a/app/views/alchemy/admin/styleguide/index.html.erb b/app/views/alchemy/admin/styleguide/index.html.erb index 4ccbf7bc16..0c9fd4b87f 100644 --- a/app/views/alchemy/admin/styleguide/index.html.erb +++ b/app/views/alchemy/admin/styleguide/index.html.erb @@ -38,13 +38,13 @@

Info Message

<%= render_message do %> -

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

<% end %>

Warning Message

<%= render_message :warning do %> -

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

<% end %>

Error Message

@@ -53,27 +53,32 @@

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

<% end %> +

Growl Messages

+ +<%= link_to render_icon(:check), 'javascript:Alchemy.growl("Success message")', class: "icon_button" %> +<%= link_to render_icon(:info), 'javascript:Alchemy.growl("Info message", "info")', class: "icon_button" %> +<%= link_to render_icon(:alert), 'javascript:Alchemy.growl("Warning message", "warn")', class: "icon_button" %> +<%= link_to render_icon(:bug), 'javascript:Alchemy.growl("Error message", "error")', class: "icon_button" %> +

Dialog Links

- + + + <%= render_icon "window" %> +

Forms

diff --git a/app/views/alchemy/base/error_notice.html.erb b/app/views/alchemy/base/error_notice.html.erb index 649c79e1db..52b0cf7df7 100644 --- a/app/views/alchemy/base/error_notice.html.erb +++ b/app/views/alchemy/base/error_notice.html.erb @@ -1 +1,3 @@ -<%= render_flash_notice @notice, :error %> +<%= render_message :error do %> + <%= @notice %> +<% end %> diff --git a/spec/components/alchemy/admin/message_spec.rb b/spec/components/alchemy/admin/message_spec.rb new file mode 100644 index 0000000000..55a67bab09 --- /dev/null +++ b/spec/components/alchemy/admin/message_spec.rb @@ -0,0 +1,55 @@ +require "rails_helper" + +RSpec.describe Alchemy::Admin::Message, type: :component do + before do + render + end + + subject(:render) do + render_inline described_class.new(message) + end + + let(:message) { "This is a message" } + + it "renders an alchemy-message with default type" do + expect(page).to have_css('alchemy-message[type="info"]', text: "This is a message") + end + + it "renders a not-dismissable alchemy-message by default" do + expect(page).to_not have_css "alchemy-message[dismissable]" + end + + context "with message given as block" do + subject(:render) do + render_inline described_class.new do + "

This is a block message

".html_safe + end + end + + it "renders an alchemy-message with default type" do + expect(page).to have_css('alchemy-message[type="info"] > p', text: "This is a block message") + end + end + + context "with type given" do + subject(:render) do + render_inline described_class.new(message, type: type) + end + + let(:type) { "alert" } + + it "renders an alchemy-message with given type" do + expect(page).to have_css 'alchemy-message[type="alert"]' + end + end + + context "with dismissable set to true" do + subject(:render) do + render_inline described_class.new(message, dismissable: true) + end + + it "renders an dismissable alchemy-message" do + expect(page).to have_css "alchemy-message[dismissable]" + end + end +end diff --git a/spec/features/admin/nodes_management_spec.rb b/spec/features/admin/nodes_management_spec.rb index 14ccb86a19..83c6d932a7 100644 --- a/spec/features/admin/nodes_management_spec.rb +++ b/spec/features/admin/nodes_management_spec.rb @@ -41,7 +41,7 @@ def add_menu_item open_page_properties click_button "Add a menu node" - within ".flash.error" do + within "alchemy-message[type='error']" do expect(page).to have_content("Menu Type can't be blank") end end diff --git a/spec/helpers/alchemy/base_helper_spec.rb b/spec/helpers/alchemy/base_helper_spec.rb index db9db94884..c08e751aa7 100644 --- a/spec/helpers/alchemy/base_helper_spec.rb +++ b/spec/helpers/alchemy/base_helper_spec.rb @@ -24,18 +24,44 @@ module Alchemy describe "#render_message" do context "if no argument is passed" do - it "should render a div with an info icon and the given content" do - expect(helper.render_message { content_tag(:p, "my notice") }).to match( - /
<\/alchemy-icon>

my notice/ - ) + it "should render an alchemy-message with an info icon and the given content" do + expect(helper.render_message { content_tag(:p, "my notice") }).to eq <<~HTML + +

my notice

+ + HTML end end context "if an argument is passed" do - it "should render the passed argument as the css classname for the icon container" do - expect(helper.render_message(:error) { content_tag(:p, "my notice") }).to match( - /
/ - ) + it "should render the passed argument as the type for the message" do + expect(helper.render_message(:error) { content_tag(:p, "my notice") }).to eq <<~HTML + +

my notice

+
+ HTML + end + end + end + + describe "#render_flash_notice" do + context "if no argument is passed" do + it "should render an alchemy-message with an check icon and the given content" do + expect(helper.render_flash_notice("my notice")).to eq <<~HTML + + my notice + + HTML + end + end + + context "if an argument is passed" do + it "should render the passed argument as the type for the message" do + expect(helper.render_flash_notice("A error", :error)).to eq <<~HTML + + A error + + HTML end end end @@ -63,43 +89,5 @@ module Alchemy end end end - - describe "#message_icon_class" do - subject { helper.message_icon_class(message_type) } - - context "when `warning`, `warn` or `alert` message type is given" do - %w[warning warn alert].each do |type| - let(:message_type) { type } - - it { is_expected.to eq "exclamation" } - end - end - - context "when `notice` message type is given" do - let(:message_type) { "notice" } - - it { is_expected.to eq "check" } - end - - context "when `hint` message type is given" do - let(:message_type) { "hint" } - - it { is_expected.to eq "info" } - end - - context "when `error` message type is given" do - let(:message_type) { "error" } - - it { is_expected.to eq "bug" } - end - - context "when unknown message type is given" do - let(:message_type) { "info" } - - it "returns the given message type as icon name" do - is_expected.to eq "info" - end - end - end end end diff --git a/spec/javascript/alchemy_admin/components/message.spec.js b/spec/javascript/alchemy_admin/components/message.spec.js new file mode 100644 index 0000000000..43caea0770 --- /dev/null +++ b/spec/javascript/alchemy_admin/components/message.spec.js @@ -0,0 +1,216 @@ +import "alchemy_admin/components/message" +import { renderComponent } from "./component.helper" + +describe("alchemy-message", () => { + describe("dismiss", () => { + describe("when dismissable", () => { + it("dismisses on click", () => { + const html = ` + + A message + + ` + const component = renderComponent("alchemy-message", html) + const spy = jest.spyOn(component, "dismiss") + component.dispatchEvent(new Event("click")) + expect(spy).toHaveBeenCalled() + }) + + it("dismisses after delay", () => { + return new Promise((resolve) => { + const html = ` + + A message + + ` + const component = renderComponent("alchemy-message", html) + const spy = jest.spyOn(component, "dismiss") + setTimeout(() => { + expect(spy).toHaveBeenCalled() + resolve() + }, 15) + }) + }, 100) + + it("when type error, does not dismis after delay", () => { + return new Promise((resolve) => { + const html = ` + + A message + + ` + const component = renderComponent("alchemy-message", html) + const spy = jest.spyOn(component, "dismiss") + setTimeout(() => { + expect(spy).not.toHaveBeenCalled() + resolve() + }, 15) + }) + }, 100) + }) + + describe("when type error", () => { + it("dismisses on click", () => { + const html = ` + + A message + + ` + const component = renderComponent("alchemy-message", html) + const spy = jest.spyOn(component, "dismiss") + component.dispatchEvent(new Event("click")) + expect(spy).toHaveBeenCalled() + }) + }) + + describe("when not type error nor dismissable", () => { + it("dismisses on click", () => { + const html = ` + + A message + + ` + const component = renderComponent("alchemy-message", html) + const spy = jest.spyOn(component, "dismiss") + component.dispatchEvent(new Event("click")) + expect(spy).not.toHaveBeenCalled() + }) + }) + }) + + describe("type", () => { + describe("when message type is given", () => { + it("is given type", () => { + const html = ` + + A warning message + + ` + const component = renderComponent("alchemy-message", html) + expect(component.type).toEqual("warning") + }) + }) + + describe("when message type is not given", () => { + it("is given type", () => { + const html = ` + + A warning message + + ` + const component = renderComponent("alchemy-message", html) + expect(component.type).toEqual("notice") + }) + }) + }) + + describe("dismissable", () => { + describe("when dismissable is set", () => { + it("is dismissable", () => { + const html = ` + + A dismissable message + + ` + const component = renderComponent("alchemy-message", html) + expect(component.dismissable).toBe(true) + }) + + it("and type error, it shows close icon", () => { + const html = ` + + A dismissable message + + ` + const component = renderComponent("alchemy-message", html) + expect( + component.querySelector("alchemy-icon[name='close']") + ).toBeDefined() + }) + }) + + describe("when dismissable is not set", () => { + it("is not dismissable", () => { + const html = ` + + A not dismissable message + + ` + const component = renderComponent("alchemy-message", html) + expect(component.dismissable).toBe(false) + }) + }) + }) + + describe("iconName", () => { + describe("when 'warning', 'warn' or 'alert' message type is given", () => { + ;["warning", "warn", "alert"].forEach((type) => { + it("is alert", () => { + const html = ` + + A ${type} message + + ` + const component = renderComponent("alchemy-message", html) + expect(component.iconName).toEqual("alert") + }) + }) + }) + + describe("when 'notice' message type is given", () => { + const html = ` + + A notice message + + ` + + it("is check", () => { + const component = renderComponent("alchemy-message", html) + + expect(component.iconName).toEqual("check") + }) + }) + + describe("when 'info' or 'hint' message type is given", () => { + ;["hint", "info"].forEach((type) => { + it("is alert", () => { + const html = ` + + A ${type} message + + ` + const component = renderComponent("alchemy-message", html) + expect(component.iconName).toEqual("information") + }) + }) + }) + + describe("when 'error' message type is given", () => { + const html = ` + + A error message + + ` + + it("is check", () => { + const component = renderComponent("alchemy-message", html) + + expect(component.iconName).toEqual("bug") + }) + }) + + describe("when unknown message type is given", () => { + const html = ` + + A foo message + + ` + + it("is the given message type as icon name", () => { + const component = renderComponent("alchemy-message", html) + + expect(component.iconName).toEqual("foo") + }) + }) + }) +}) diff --git a/spec/views/alchemy/admin/elements/element_view_spec.rb b/spec/views/alchemy/admin/elements/element_view_spec.rb index f08b637e8c..67112b97e5 100644 --- a/spec/views/alchemy/admin/elements/element_view_spec.rb +++ b/spec/views/alchemy/admin/elements/element_view_spec.rb @@ -23,7 +23,7 @@ let(:element) { create(:alchemy_element, name: "with_message") } it "renders the message" do - is_expected.to have_css('.message:contains("One nice message")') + is_expected.to have_css('alchemy-message:contains("One nice message")') end context "that contains HTML" do @@ -35,7 +35,7 @@ end it "renders the HTML message" do - is_expected.to have_css('.message h1:contains("One nice message")') + is_expected.to have_css('alchemy-message[type="info"] h1:contains("One nice message")') end end end @@ -51,7 +51,7 @@ end it "renders the warning" do - is_expected.to have_css('.warning:contains("One nice warning")') + is_expected.to have_css('alchemy-message[type="warning"]:contains("One nice warning")') end context "that contains HTML" do @@ -63,7 +63,7 @@ end it "renders the HTML warning" do - is_expected.to have_css('.warning h1:contains("One nice warning")') + is_expected.to have_css('alchemy-message[type="warning"] h1:contains("One nice warning")') end end end diff --git a/spec/views/alchemy/ingredients/select_editor_spec.rb b/spec/views/alchemy/ingredients/select_editor_spec.rb index cbd17173ed..548dcc3f89 100644 --- a/spec/views/alchemy/ingredients/select_editor_spec.rb +++ b/spec/views/alchemy/ingredients/select_editor_spec.rb @@ -30,7 +30,7 @@ end it "renders a warning" do - is_expected.to have_css(".warning") + is_expected.to have_css('alchemy-message[type="warning"]') end end