diff options
author | Sean McGivern <sean@gitlab.com> | 2019-02-22 13:46:00 +0300 |
---|---|---|
committer | Sean McGivern <sean@gitlab.com> | 2019-02-22 13:46:00 +0300 |
commit | 695df38fce2893becfd858d9e96f2f4d648af2f2 (patch) | |
tree | 9f695eba7dbf063b1aa8e7e594fd0211e8a0ed8f | |
parent | 6fa88ed77e1693cda845efe49bf2c9a77aed2e4f (diff) | |
parent | 28e1739a3fd8c93e4805fe0053faf820cec4e1bc (diff) |
Merge branch '55057-system-message-to-core' into 'master'
Port EE System Header And Footer feature to CE
Closes #55057
See merge request gitlab-org/gitlab-ce!25241
25 files changed, 594 insertions, 3 deletions
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index 62d471bc30c..555ea276c6c 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -65,3 +65,4 @@ @import 'framework/terms'; @import 'framework/read_more'; @import 'framework/flex_grid'; +@import 'framework/system_messages'; diff --git a/app/assets/stylesheets/framework/system_messages.scss b/app/assets/stylesheets/framework/system_messages.scss new file mode 100644 index 00000000000..3d66136938f --- /dev/null +++ b/app/assets/stylesheets/framework/system_messages.scss @@ -0,0 +1,110 @@ +.header-message, +.footer-message { + padding: 0 15px; + border: 1px solid transparent; + border-radius: 0; + position: fixed; + left: 0; + width: 100%; + text-align: center; + margin: 0; + z-index: 1000; + + p { + @include str-truncated(100%); + margin-top: 0; + margin-bottom: 0; + } +} + +.header-message { + top: 0; + height: $system-header-height; + line-height: $system-header-height; +} + +.footer-message { + bottom: 0; + height: $system-footer-height; + line-height: $system-footer-height; +} + +.with-performance-bar { + .header-message { + top: $performance-bar-height; + } +} + +// System Header +.with-system-header { + // main navigation + // login page + .navbar-gitlab, + .fixed-top { + top: $system-header-height; + } + + // left sidebar eg: project page + // right sidebar eg: MR page + .nav-sidebar, + .right-sidebar { + top: $system-header-height + $header-height; + } + + .content-wrapper { + margin-top: $system-header-height + $header-height; + } + + // Performance Bar + // System Header + &.with-performance-bar { + // main navigation + header.navbar-gitlab { + top: $performance-bar-height + $system-header-height; + } + + .layout-page { + margin-top: $header-height + $performance-bar-height + $system-header-height; + } + + // left sidebar eg: project page + // right sidebar eg: MR page + .nav-sidebar, + .right-sidebar { + top: $header-height + $performance-bar-height + $system-header-height; + } + } +} + +// System Footer +.with-system-footer { + // left sidebar eg: project page + // right sidebar eg: mr page + .nav-sidebar, + .right-sidebar, + // navless pages' footer eg: login page + // navless pages' footer border eg: login page + &.devise-layout-html body .footer-container, + &.devise-layout-html body hr.footer-fixed { + bottom: $system-footer-height; + } +} + +.fullscreen-layout { + .header-message, + .footer-message { + position: static; + top: auto; + bottom: auto; + } + + .content-wrapper { + .with-system-header & { + margin-top: 0; + } + + .with-system-footer & { + margin-top: 0; + } + } +} diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index dc1a73ed923..27c54cb0b75 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -276,6 +276,8 @@ $general-hover-transition-duration: 100ms; $general-hover-transition-curve: linear; $highlight-changes-color: rgb(235, 255, 232); $performance-bar-height: 35px; +$system-header-height: 35px; +$system-footer-height: $system-header-height; $flash-height: 52px; $context-header-height: 60px; $breadcrumb-min-height: 48px; diff --git a/app/controllers/admin/appearances_controller.rb b/app/controllers/admin/appearances_controller.rb index e3226c86b0b..2b9cae21da2 100644 --- a/app/controllers/admin/appearances_controller.rb +++ b/app/controllers/admin/appearances_controller.rb @@ -74,6 +74,10 @@ class Admin::AppearancesController < Admin::ApplicationController favicon_cache new_project_guidelines updated_by + header_message + footer_message + message_background_color + message_font_color ] end end diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb index 7fbbbb04154..023e44258b7 100644 --- a/app/helpers/appearances_helper.rb +++ b/app/helpers/appearances_helper.rb @@ -40,4 +40,36 @@ module AppearancesHelper render 'shared/logo_type.svg' end end + + def header_message + return unless current_appearance&.show_header? + + class_names = [] + class_names << 'with-performance-bar' if performance_bar_enabled? + + render_message(:header_message, class_names) + end + + def footer_message + return unless current_appearance&.show_footer? + + render_message(:footer_message) + end + + private + + def render_message(field_sym, class_names = []) + class_names << field_sym.to_s.dasherize + + content_tag :div, class: class_names, style: message_style do + markdown_field(current_appearance, field_sym) + end + end + + def message_style + style = [] + style << "background-color: #{current_appearance.message_background_color};" + style << "color: #{current_appearance.message_font_color}" + style.join + end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 9efa84b02f0..ffa5719fefb 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -214,12 +214,19 @@ module ApplicationHelper class_names = [] class_names << 'issue-boards-page' if current_controller?(:boards) class_names << 'with-performance-bar' if performance_bar_enabled? - + class_names << system_message_class class_names end - # EE feature: System header and footer, unavailable in CE def system_message_class + class_names = [] + + return class_names unless appearance + + class_names << 'with-system-header' if appearance.show_header? + class_names << 'with-system-footer' if appearance.show_footer? + + class_names end # Returns active css class when condition returns true @@ -292,4 +299,10 @@ module ApplicationHelper snippets: snippets_project_autocomplete_sources_path(object) } end + + private + + def appearance + ::Appearance.current + end end diff --git a/app/models/appearance.rb b/app/models/appearance.rb index ff1ecfda684..b9ad676ca47 100644 --- a/app/models/appearance.rb +++ b/app/models/appearance.rb @@ -8,12 +8,19 @@ class Appearance < ActiveRecord::Base cache_markdown_field :description cache_markdown_field :new_project_guidelines + cache_markdown_field :header_message, pipeline: :broadcast_message + cache_markdown_field :footer_message, pipeline: :broadcast_message validates :logo, file_size: { maximum: 1.megabyte } validates :header_logo, file_size: { maximum: 1.megabyte } + validates :message_background_color, allow_blank: true, color: true + validates :message_font_color, allow_blank: true, color: true validate :single_appearance_row, on: :create + default_value_for :message_background_color, '#E75E40' + default_value_for :message_font_color, '#FFFFFF' + mount_uploader :logo, AttachmentUploader mount_uploader :header_logo, AttachmentUploader mount_uploader :favicon, FaviconUploader @@ -41,6 +48,14 @@ class Appearance < ActiveRecord::Base logo_system_path(favicon, 'favicon') end + def show_header? + header_message.present? + end + + def show_footer? + footer_message.present? + end + private def logo_system_path(logo, mount_type) diff --git a/app/views/admin/appearances/_form.html.haml b/app/views/admin/appearances/_form.html.haml index 77e84abd76e..a5f34d0dab2 100644 --- a/app/views/admin/appearances/_form.html.haml +++ b/app/views/admin/appearances/_form.html.haml @@ -42,6 +42,7 @@ %br Images with incorrect dimensions are not resized automatically, and may result in unexpected behavior. + = render partial: 'admin/appearances/system_header_footer_form', locals: { form: f } %hr .row diff --git a/app/views/admin/appearances/_system_header_footer_form.html.haml b/app/views/admin/appearances/_system_header_footer_form.html.haml new file mode 100644 index 00000000000..ca9d6adebeb --- /dev/null +++ b/app/views/admin/appearances/_system_header_footer_form.html.haml @@ -0,0 +1,24 @@ +- form = local_assigns.fetch(:form) + +%hr +.row + .col-lg-4.profile-settings-sidebar + %h4.prepend-top-0 + = _('System header and footer') + + .col-lg-8 + .form-group + = form.label :header_message, _('Header message'), class: 'col-form-label label-bold' + = form.text_area :header_message, placeholder: _('State your message to activate'), class: "form-control js-autosize" + .form-group + = form.label :footer_message, _('Footer message'), class: 'col-form-label label-bold' + = form.text_area :footer_message, placeholder: _('State your message to activate'), class: "form-control js-autosize" + .form-group.js-toggle-colors-container + %button.btn.btn-link.js-toggle-colors-link{ type: 'button' } + = _('Customize colors') + .form-group.js-toggle-colors-container.hide + = form.label :message_background_color, _('Background Color'), class: 'col-form-label label-bold' + = form.color_field :message_background_color, class: "form-control" + .form-group.js-toggle-colors-container.hide + = form.label :message_font_color, _('Font Color'), class: 'col-form-label label-bold' + = form.color_field :message_font_color, class: "form-control" diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 4373240001e..043cca6ad38 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -5,7 +5,9 @@ = render "layouts/init_auto_complete" if @gfm_form = render "layouts/init_client_detection_flags" = render 'peek/bar' - = render partial: "layouts/header/default", locals: { project: @project, group: @group } + = header_message + = render partial: "layouts/header/default", locals: { project: @project, group: @group } = render 'layouts/page', sidebar: sidebar, nav: nav + = footer_message = yield :scripts_body diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index 6003d973c88..2f3c13aaf6e 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -2,6 +2,7 @@ %html.devise-layout-html{ class: system_message_class } = render "layouts/head" %body.ui-indigo.login-page.application.navless.qa-login-page{ data: { page: body_data_page } } + = header_message .page-wrap = render "layouts/header/empty" .login-page-broadcast @@ -34,3 +35,4 @@ = link_to _("Explore"), explore_root_path = link_to _("Help"), help_path = link_to _("About GitLab"), "https://about.gitlab.com/" + = footer_message diff --git a/app/views/layouts/devise_empty.html.haml b/app/views/layouts/devise_empty.html.haml index 663e5b24368..6c9c8aa4431 100644 --- a/app/views/layouts/devise_empty.html.haml +++ b/app/views/layouts/devise_empty.html.haml @@ -2,6 +2,7 @@ %html{ lang: "en", class: system_message_class } = render "layouts/head" %body.ui-indigo.login-page.application.navless + = header_message = render "layouts/header/empty" = render "layouts/broadcast" .container.navless-container @@ -15,3 +16,4 @@ = link_to _("Explore"), explore_root_path = link_to _("Help"), help_path = link_to _("About GitLab"), "https://about.gitlab.com/" + = footer_message diff --git a/changelogs/unreleased/55057-system-message-to-core.yml b/changelogs/unreleased/55057-system-message-to-core.yml new file mode 100644 index 00000000000..3381879eb4a --- /dev/null +++ b/changelogs/unreleased/55057-system-message-to-core.yml @@ -0,0 +1,5 @@ +--- +title: Port System Header and Footer feature to Core +merge_request: 25241 +author: +type: added diff --git a/db/migrate/20180314145917_add_header_and_footer_banners_to_appearances_table.rb b/db/migrate/20180314145917_add_header_and_footer_banners_to_appearances_table.rb new file mode 100644 index 00000000000..8aba3448035 --- /dev/null +++ b/db/migrate/20180314145917_add_header_and_footer_banners_to_appearances_table.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddHeaderAndFooterBannersToAppearancesTable < ActiveRecord::Migration[4.2] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + add_column :appearances, :header_message, :text + add_column :appearances, :header_message_html, :text + + add_column :appearances, :footer_message, :text + add_column :appearances, :footer_message_html, :text + + add_column :appearances, :message_background_color, :text + add_column :appearances, :message_font_color, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 1651a24f412..1bdc9682cc9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -37,6 +37,12 @@ ActiveRecord::Schema.define(version: 20190204115450) do t.integer "cached_markdown_version" t.text "new_project_guidelines" t.text "new_project_guidelines_html" + t.text "header_message" + t.text "header_message_html" + t.text "footer_message" + t.text "footer_message_html" + t.text "message_background_color" + t.text "message_font_color" t.string "favicon" end diff --git a/doc/customization/system_header_and_footer_messages.md b/doc/customization/system_header_and_footer_messages.md new file mode 100644 index 00000000000..cf7d8b3f3e8 --- /dev/null +++ b/doc/customization/system_header_and_footer_messages.md @@ -0,0 +1,18 @@ +# Adding a system message to every page + +> [Introduced][ee-1283] in [GitLab Premium][eep] 10.7. + +Navigate to the **Admin** area and go to the **Appearance** page. + +Under **System header and footer** insert your header message and/or footer message. +Both background and font color of the header and footer are customizable. + +![appearance](system_header_and_footer_messages/appearance.png) + +After saving, all GitLab pages will contain the custom system header and/or footer messages: + +![custom_header_footer](system_header_and_footer_messages/custom_header_footer.png) + +The GitLab sign in page will also show the header and the footer messages: + +![sign_up_custom_header_and_footer](system_header_and_footer_messages/sign_up_custom_header_and_footer.png) diff --git a/doc/customization/system_header_and_footer_messages/appearance.png b/doc/customization/system_header_and_footer_messages/appearance.png Binary files differnew file mode 100644 index 00000000000..14667f751c4 --- /dev/null +++ b/doc/customization/system_header_and_footer_messages/appearance.png diff --git a/doc/customization/system_header_and_footer_messages/custom_header_footer.png b/doc/customization/system_header_and_footer_messages/custom_header_footer.png Binary files differnew file mode 100644 index 00000000000..691ca8a3484 --- /dev/null +++ b/doc/customization/system_header_and_footer_messages/custom_header_footer.png diff --git a/doc/customization/system_header_and_footer_messages/sign_up_custom_header_and_footer.png b/doc/customization/system_header_and_footer_messages/sign_up_custom_header_and_footer.png Binary files differnew file mode 100644 index 00000000000..a9c59bc9f62 --- /dev/null +++ b/doc/customization/system_header_and_footer_messages/sign_up_custom_header_and_footer.png diff --git a/locale/gitlab.pot b/locale/gitlab.pot index fa680cd5ef0..2f607708834 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -951,6 +951,9 @@ msgstr "" msgid "Average per day: %{average}" msgstr "" +msgid "Background Color" +msgstr "" + msgid "Background Jobs" msgstr "" @@ -2450,6 +2453,9 @@ msgstr "" msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}." msgstr "" +msgid "Customize colors" +msgstr "" + msgid "Customize how FogBugz email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import." msgstr "" @@ -3432,6 +3438,12 @@ msgstr "" msgid "Follow the steps below to export your Google Code project data." msgstr "" +msgid "Font Color" +msgstr "" + +msgid "Footer message" +msgstr "" + msgid "For internal projects, any logged in user can view pipelines and access job details (output logs and artifacts)" msgstr "" @@ -3759,6 +3771,9 @@ msgstr "" msgid "GroupsTree|Search by name" msgstr "" +msgid "Header message" +msgstr "" + msgid "Health Check" msgstr "" @@ -7051,6 +7066,9 @@ msgstr "" msgid "Starts at (UTC)" msgstr "" +msgid "State your message to activate" +msgstr "" + msgid "Status" msgstr "" @@ -7132,6 +7150,9 @@ msgstr "" msgid "System default (%{default})" msgstr "" +msgid "System header and footer" +msgstr "" + msgid "System metrics (Custom)" msgstr "" diff --git a/spec/controllers/admin/appearances_controller_spec.rb b/spec/controllers/admin/appearances_controller_spec.rb new file mode 100644 index 00000000000..4ddd0953267 --- /dev/null +++ b/spec/controllers/admin/appearances_controller_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper' + +describe Admin::AppearancesController do + let(:admin) { create(:admin) } + let(:header_message) { "Header message" } + let(:footer_message) { "Footer" } + + describe 'POST #create' do + let(:create_params) do + { + title: "Foo", + description: "Bar", + header_message: header_message, + footer_message: footer_message + } + end + + before do + sign_in(admin) + end + + it 'creates appearance with footer and header message' do + post :create, params: { appearance: create_params } + + expect(Appearance.current).to have_attributes( + header_message: header_message, + footer_message: footer_message + ) + end + end + + describe 'PUT #update' do + let(:update_params) do + { + header_message: header_message, + footer_message: footer_message + } + end + + before do + create(:appearance) + + sign_in(admin) + end + + it 'updates appearance with footer and header message' do + put :update, params: { appearance: update_params } + + expect(Appearance.current).to have_attributes( + header_message: header_message, + footer_message: footer_message + ) + end + end +end diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index 57215c0d1e9..83cd686818c 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -39,6 +39,38 @@ describe 'Admin Appearance' do expect_custom_new_project_appearance(appearance) end + context 'Custom system header and footer' do + before do + sign_in(create(:admin)) + end + + context 'when system header and footer messages are empty' do + it 'shows custom system header and footer fields' do + visit admin_appearances_path + + expect(page).to have_field('appearance_header_message', with: '') + expect(page).to have_field('appearance_footer_message', with: '') + expect(page).to have_field('appearance_message_background_color') + expect(page).to have_field('appearance_message_font_color') + end + end + + context 'when system header and footer messages are not empty' do + before do + appearance.update(header_message: 'Foo', footer_message: 'Bar') + end + + it 'shows custom system header and footer fields' do + visit admin_appearances_path + + expect(page).to have_field('appearance_header_message', with: appearance.header_message) + expect(page).to have_field('appearance_footer_message', with: appearance.footer_message) + expect(page).to have_field('appearance_message_background_color') + expect(page).to have_field('appearance_message_font_color') + end + end + end + it 'Custom sign-in page' do visit new_user_session_path diff --git a/spec/features/display_system_header_and_footer_bar_spec.rb b/spec/features/display_system_header_and_footer_bar_spec.rb new file mode 100644 index 00000000000..af9d9a5834f --- /dev/null +++ b/spec/features/display_system_header_and_footer_bar_spec.rb @@ -0,0 +1,137 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Display system header and footer bar' do + let(:header_message) { "Foo" } + let(:footer_message) { "Bar" } + + shared_examples 'system header is configured' do + it 'shows system header' do + expect(page).to have_css('.header-message') + end + + it 'shows the correct content' do + page.within('.header-message') do + expect(page).to have_content(header_message) + end + end + end + + shared_examples 'system footer is configured' do + it 'shows system footer' do + expect(page).to have_css('.footer-message') + end + + it 'shows the correct content' do + page.within('.footer-message') do + expect(page).to have_content(footer_message) + end + end + end + + shared_examples 'system header is not configured' do + it 'does not show system header' do + expect(page).not_to have_css('.header-message') + end + end + + shared_examples 'system footer is not configured' do + it 'does not show system footer' do + expect(page).not_to have_css('.footer-message') + end + end + + context 'when authenticated' do + context 'when system header and footer are not configured' do + before do + sign_in(create(:user)) + + visit root_path + end + + it_behaves_like 'system header is not configured' + it_behaves_like 'system footer is not configured' + end + + context 'when only system header is defined' do + before do + create(:appearance, header_message: header_message) + + sign_in(create(:user)) + visit root_path + end + + it_behaves_like 'system header is configured' + it_behaves_like 'system footer is not configured' + end + + context 'when only system footer is defined' do + before do + create(:appearance, footer_message: footer_message) + + sign_in(create(:user)) + visit root_path + end + + it_behaves_like 'system header is not configured' + it_behaves_like 'system footer is configured' + end + + context 'when system header and footer are defined' do + before do + create(:appearance, header_message: header_message, footer_message: footer_message) + + sign_in(create(:user)) + visit root_path + end + + it_behaves_like 'system header is configured' + it_behaves_like 'system footer is configured' + end + end + + context 'when not authenticated' do + context 'when system header and footer are not configured' do + before do + visit root_path + end + + it_behaves_like 'system header is not configured' + it_behaves_like 'system footer is not configured' + end + + context 'when only system header is defined' do + before do + create(:appearance, header_message: header_message) + + visit root_path + end + + it_behaves_like 'system header is configured' + it_behaves_like 'system footer is not configured' + end + + context 'when only system footer is defined' do + before do + create(:appearance, footer_message: footer_message) + + visit root_path + end + + it_behaves_like 'system header is not configured' + it_behaves_like 'system footer is configured' + end + + context 'when system header and footer are defined' do + before do + create(:appearance, header_message: header_message, footer_message: footer_message) + + visit root_path + end + + it_behaves_like 'system header is configured' + it_behaves_like 'system footer is configured' + end + end +end diff --git a/spec/helpers/appearances_helper_spec.rb b/spec/helpers/appearances_helper_spec.rb new file mode 100644 index 00000000000..8d717b968dd --- /dev/null +++ b/spec/helpers/appearances_helper_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe AppearancesHelper do + before do + user = create(:user) + allow(helper).to receive(:current_user).and_return(user) + end + + describe '#header_message' do + it 'returns nil when header message field is not set' do + create(:appearance) + + expect(helper.header_message).to be_nil + end + + context 'when header message is set' do + it 'includes current message' do + message = "Foo bar" + create(:appearance, header_message: message) + + expect(helper.header_message).to include(message) + end + end + end + + describe '#footer_message' do + it 'returns nil when footer message field is not set' do + create(:appearance) + + expect(helper.footer_message).to be_nil + end + + context 'when footer message is set' do + it 'includes current message' do + message = "Foo bar" + create(:appearance, footer_message: message) + + expect(helper.footer_message).to include(message) + end + end + end + + describe '#brand_image' do + let!(:appearance) { create(:appearance, :with_logo) } + + context 'when there is a logo' do + it 'returns a path' do + expect(helper.brand_image).to match(%r(img data-src="/uploads/-/system/appearance/.*png)) + end + end + + context 'when there is a logo but no associated upload' do + before do + # Legacy attachments were not tracked in the uploads table + appearance.logo.upload.destroy + appearance.reload + end + + it 'falls back to using the original path' do + expect(helper.brand_image).to match(%r(img data-src="/uploads/-/system/appearance/.*png)) + end + end + end + + describe '#brand_title' do + it 'returns the default CE title when no appearance is present' do + allow(helper) + .to receive(:current_appearance) + .and_return(nil) + + expect(helper.brand_title).to eq('GitLab Community Edition') + end + end +end diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb index cc76a2019ec..28d482adebf 100644 --- a/spec/models/appearance_spec.rb +++ b/spec/models/appearance_spec.rb @@ -63,4 +63,19 @@ describe Appearance do %i(logo header_logo favicon).each do |logo_type| it_behaves_like 'logo paths', logo_type end + + describe 'validations' do + let(:triplet) { '#000' } + let(:hex) { '#AABBCC' } + + it { is_expected.to allow_value(nil).for(:message_background_color) } + it { is_expected.to allow_value(triplet).for(:message_background_color) } + it { is_expected.to allow_value(hex).for(:message_background_color) } + it { is_expected.not_to allow_value('000').for(:message_background_color) } + + it { is_expected.to allow_value(nil).for(:message_font_color) } + it { is_expected.to allow_value(triplet).for(:message_font_color) } + it { is_expected.to allow_value(hex).for(:message_font_color) } + it { is_expected.not_to allow_value('000').for(:message_font_color) } + end end |