Merge pull request #16789 from opf/chore/primerized-flashes

Primerize all backend flashes
This commit is contained in:
Oliver Günther
2024-09-30 22:12:42 +02:00
committed by GitHub
121 changed files with 532 additions and 648 deletions
+5 -1
View File
@@ -31,7 +31,11 @@ See COPYRIGHT and LICENSE files for more details.
render(Primer::BaseComponent.new(
tag: :div,
classes: "op-primer-flash--item",
data: { unique_key: @unique_key }.compact
data: {
"flash-target": "item",
"autohide": @autohide,
unique_key: @unique_key
}.compact
)) do
render_parent
end
+3 -1
View File
@@ -35,10 +35,12 @@ module OpPrimer
def initialize(**system_arguments)
@unique_key = system_arguments.delete(:unique_key)
system_arguments[:test_selector] ||= "primer-banner-message-component"
system_arguments[:test_selector] ||= "op-primer-flash-message"
system_arguments[:dismiss_scheme] ||= :remove
system_arguments[:dismiss_label] ||= I18n.t(:button_close)
@autohide = system_arguments[:scheme] == :success && system_arguments[:dismiss_scheme] != :none
super
end
end
+2 -2
View File
@@ -174,13 +174,13 @@ class MyController < ApplicationController
# rubocop:disable Rails/ActionControllerFlashBeforeRender
result.on_success do
flash[:op_primer_flash] = { message: t("my.access_token.notice_api_token_revoked") }
flash[:notice] = t("my.access_token.notice_api_token_revoked")
end
result.on_failure do |r|
error = r.errors.map(&:message).join("; ")
Rails.logger.error("Failed to revoke api token ##{current_user.id}: #{error}")
flash[:op_primer_flash] = { message: t("my.access_token.failed_to_revoke_token", error:), scheme: :danger }
flash[:error] = t("my.access_token.failed_to_revoke_token", error:)
end
# rubocop:enable Rails/ActionControllerFlashBeforeRender
+29 -10
View File
@@ -34,32 +34,51 @@ module ErrorMessageHelper
object = convert_to_model(object)
return unless object
render_error_messages_partial(object.errors, object)
assign_flash_error(object.errors, object)
# Don't output anything for compability
nil
end
def render_error_messages_partial(errors, object)
return "" if errors.empty?
def assign_flash_error(errors, object)
return if errors.empty?
base_error_messages = errors.full_messages_for(:base)
fields_error_messages = errors.full_messages - base_error_messages
render partial: "common/validation_error",
locals: { base_error_messages:,
fields_error_messages:,
object_name: object.class.model_name.human }
flash[:error] = {
message: error_message_header(object.class.model_name.human, base_error_messages.count + fields_error_messages.count),
description: error_flash_description(object, base_error_messages, fields_error_messages)
}
end
def error_flash_description(_object, base_error_messages, fields_error_messages)
capture do
concat list_of_messages(base_error_messages)
concat text_header_invalid_fields(base_error_messages, fields_error_messages)
concat list_of_messages(fields_error_messages)
end
end
def error_message_header(object_name, count)
t("activerecord.errors.template.header", model: object_name, count:)
end
def text_header_invalid_fields(base_error_messages, fields_error_messages)
return if fields_error_messages.blank?
i18n_key = base_error_messages.present? ? "errors.header_additional_invalid_fields" : "errors.header_invalid_fields"
t(i18n_key, count: fields_error_messages.count)
out = "".html_safe
out << t(i18n_key, count: fields_error_messages.count)
out << "<br/>".html_safe
out
end
def list_of_messages(messages)
return if messages.blank?
messages = messages.map { |message| tag.li message }
tag.ul { safe_join(messages, "\n") }
safe_join(messages, "<br/>".html_safe)
end
end
+24 -27
View File
@@ -27,34 +27,34 @@
#++
module ErrorsHelper
def render_400(options = {})
@project = nil
def render_400(options = {}) # rubocop:disable Naming/VariableNumber
unset_template_magic
render_error({ message: :notice_bad_request, status: 400 }.merge(options))
false
end
def render_403(options = {})
@project = nil
def render_403(options = {}) # rubocop:disable Naming/VariableNumber
unset_template_magic
render_error({ message: :notice_not_authorized, status: 403 }.merge(options))
false
end
def render_404(options = {})
def render_404(options = {}) # rubocop:disable Naming/VariableNumber
render_error({ message: :notice_file_not_found, status: 404 }.merge(options))
false
end
def render_500(options = {})
message = t(:notice_internal_server_error, app_title: Setting.app_title)
def render_500(options = {}) # rubocop:disable Naming/VariableNumber
unset_template_magic
message = t(:notice_internal_server_error, app_title: Setting.app_title)
# Append error information
if current_user.admin?
options[:message_details] = get_additional_message
end
render_error({ message: }.merge(options))
render_error({ message:, status: 500 }.merge(options))
false
end
@@ -80,37 +80,34 @@ module ErrorsHelper
end
# Renders an error response
def render_error(arg)
def render_error(arg) # rubocop:disable Metrics/AbcSize
arg = { message: arg } unless arg.is_a?(Hash)
@status = arg[:status] || 500
@message = arg[:message]
status = arg[:status] || 500
message = arg[:message]
if @status >= 500
op_handle_error(arg[:exception] || "[Error #@status] #@message", payload: arg[:payload])
if status >= 500
op_handle_error(arg[:exception] || "[Error #status] #message", payload: arg[:payload])
end
@message = I18n.t(@message) if @message.is_a?(Symbol)
@message_details = arg[:message_details]
message = I18n.t(message) if message.is_a?(Symbol)
message_details = arg[:message_details]
respond_to do |format|
format.html do
render template: "common/error", layout: use_layout, status: @status
error_message = "[#{I18n.t(:error_code, code: status)}] #{message}\n#{message_details}"
flash.now[:error] = { message: error_message, dismiss_scheme: :none }
render template: "common/error",
layout: use_layout,
status:,
locals: { status:, params: }
end
format.any do
head @status
head status
end
end
end
def unset_template_magic
if $ERROR_INFO.is_a?(ActionView::ActionViewError)
@template.instance_variable_set(:@project, nil)
@template.instance_variable_set(:@status, 500)
@template.instance_variable_set(:@message, message)
else
@project = nil
end
rescue StandardError
# bad luck
@project = nil # rubocop:disable Rails/HelperInstanceVariable
end
end
+30 -28
View File
@@ -37,44 +37,46 @@ module FlashMessagesHelper
# Renders flash messages
def render_flash_messages
messages = flash
.reject { |k, _| k.to_s == "op_primer_flash" }
.reject { |k, _| k.start_with? "_" }
.map do |k, v|
if k.to_sym == :modal
component = v[:type].constantize
component.new(**v.fetch(:parameters, {})).render_in(self)
else
render_flash_message(k, v)
end
end
.reject { |k, _| k.to_s == "modal" }
.map { |k, v| render_flash_content(k.to_sym, v) }
safe_join messages, "\n"
end
def render_flash_message(type, message, html_options = {}) # rubocop:disable Metrics/AbcSize
if type.to_s == "notice"
type = "success"
def render_flash_content(key, content)
case content
when Hash
render_flash_message(key, **content)
else
render_flash_message(key, message: content)
end
end
toast_css_classes = ["op-toast -#{type}", html_options.delete(:class)]
def render_flash_modal
content = flash[:modal]
return if content.blank?
# Add autohide class to notice flashes if configured
if type.to_s == "success" && User.current.pref.auto_hide_popups?
toast_css_classes << "autohide-toaster"
component = content[:type].constantize
component.new(**content.fetch(:parameters, {})).render_in(self)
end
def mapped_flash_type(type)
case type
when :error, :danger
:danger
when :warning
:warning
when :success, :notice
:success
else
:default
end
end
html_options = { class: toast_css_classes.join(" "), role: "alert" }.merge(html_options)
close_button = content_tag :a, "", class: "op-toast--close icon-context icon-close",
title: I18n.t("js.close_popup_title"),
tabindex: "0"
toast = content_tag(:div, join_flash_messages(message), class: "op-toast--content")
content_tag :div, "", class: "op-toast--wrapper" do
content_tag :div, "", class: "op-toast--casing" do
content_tag :div, html_options do
concat(close_button)
concat(toast)
end
end
def render_flash_message(type, message:, **args)
render(OpPrimer::FlashComponent.new(scheme: mapped_flash_type(type), **args)) do
join_flash_messages(message)
end
end
end
-43
View File
@@ -1,43 +0,0 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
#
module PrimerizedFlashHelper
extend ActiveSupport::Concern
def render_primerized_flash
return if flash[:op_primer_flash].blank?
system_arguments = flash[:op_primer_flash]
message = system_arguments.delete(:message)
render(OpPrimer::FlashComponent.new(**system_arguments)) do
message
end
end
end
-53
View File
@@ -1,53 +0,0 @@
<%#-- copyright
OpenProject is an open source project management software.
Copyright (C) the OpenProject GmbH
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
Copyright (C) 2006-2013 Jean-Philippe Lang
Copyright (C) 2010-2013 the ChiliProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
See COPYRIGHT and LICENSE files for more details.
++#%>
<div class="op-toast--wrapper">
<div class="op-toast--casing">
<div id="errorExplanation"
data-members-form-target="errorExplanation"
class="op-toast errorExplanation -error <%= local_assigns[:classes] || '' %>"
tabindex="0"
role="alert">
<div class="op-toast--content">
<% if content_for?(:error_details) %>
<p>
<strong><%= error_message %></strong>
</p>
<%= content_for :error_details %>
<% else %>
<%= error_message %>
<% end %>
</div>
<span class="close-handler" role="button" tabindex="0" aria-label="{{ ::I18n.t('js.close_popup_title') }}">
<%= op_icon('icon-close') %>
</span>
</div>
</div>
</div>
@@ -1,42 +0,0 @@
<%#-- copyright
OpenProject is an open source project management software.
Copyright (C) the OpenProject GmbH
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
Copyright (C) 2006-2013 Jean-Philippe Lang
Copyright (C) 2010-2013 the ChiliProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
See COPYRIGHT and LICENSE files for more details.
++#%>
<% content_for :error_details, flush: true do %>
<%= list_of_messages(base_error_messages) %>
<%= text_header_invalid_fields(base_error_messages, fields_error_messages) %>
<%= list_of_messages(fields_error_messages) %>
<% end %>
<%= render partial: "common/error_base",
locals: {
error_message: t("activerecord.errors.template.header",
model: object_name,
count: base_error_messages.count + fields_error_messages.count)
}
%>
+1 -9
View File
@@ -27,14 +27,6 @@ See COPYRIGHT and LICENSE files for more details.
++#%>
<% if @message_details %>
<% content_for :error_details do %>
<p><%= @message_details %></p>
<% end %>
<% end %>
<% error_message = "[#{I18n.t(:error_code, code: @status)}] #{@message}" %>
<%= render partial: "common/error_base", locals: { error_message: error_message } %>
<%= call_hook(:view_common_error_details, { params: params, project: ((defined? @project) ? @project : nil) }) %>
<% html_title h(@status) %>
<% html_title h(status) %>
+10
View File
@@ -0,0 +1,10 @@
<%# Primerized flash messages are being rendered separately %>
<div id="primerized-flash-messages"
class="op-primer-flash"
data-controller="flash"
data-flash-autohide-value="<%= User.current.pref.auto_hide_popups? %>">
<%= render_flash_messages %>
</div>
<%# Flash modals render modal components %>
<%= render_flash_modal %>
+1 -8
View File
@@ -117,14 +117,7 @@ See COPYRIGHT and LICENSE files for more details.
<% end %>
<div class="content-overlay"></div>
<%= content_tag :main, id: "content-wrapper", class: initial_classes, data: stimulus_content_data do %>
<%# Primerized flash messages are being rendered separately %>
<div id="primerized-flash-messages" class="op-primer-flash">
<%= render_primerized_flash %>
</div>
<%# Flash messages are being rendered using the old op-flash style %>
<turbo-frame id="flash-messages">
<%= render_flash_messages %>
</turbo-frame>
<%= render partial: "layouts/flashes" %>
<% if show_onboarding_modal? %>
<section data-augmented-model-wrapper
data-modal-initialize-now="true"
+4 -1
View File
@@ -44,7 +44,10 @@ See COPYRIGHT and LICENSE files for more details.
<%= link_to(I18n.t('label_home'), home_url, class: 'op-logo--link') %>
</div>
</header>
<%= yield %>
<main id="content-wrapper">
<%= render partial: "layouts/flashes" %>
<%= yield %>
</main>
</div>
</body>
</html>
@@ -5,8 +5,6 @@ export function setupServerResponse() {
focusFirstErroneousField();
activateFlashNotice();
activateFlashError();
autoHideFlashMessage();
flashCloseHandler();
jQuery(document).ajaxComplete(activateFlashNotice);
jQuery(document).ajaxComplete(activateFlashError);
@@ -90,22 +88,6 @@ export function setupServerResponse() {
});
}
function flashCloseHandler() {
jQuery('body').on('click keydown touchend', '.close-handler,.op-toast--close', function (e) {
if (e.type === 'click' || e.which === 13) {
jQuery(this).parent('.errorExplanation, .op-toast')
.not('.persistent-toggle--notification')
.remove();
}
});
}
function autoHideFlashMessage() {
setTimeout(() => {
jQuery('.op-toast.autohide-toaster').remove();
}, 5000);
}
function addClickEventToAllErrorMessages() {
jQuery('a.afocus').each(function () {
const target = jQuery(this);
@@ -0,0 +1,24 @@
import { ApplicationController } from 'stimulus-use';
export const SUCCESS_AUTOHIDE_TIMEOUT = 5000;
export default class FlashController extends ApplicationController {
static values = {
autohide: Boolean,
};
declare autohideValue:boolean;
static targets = [
'item',
];
declare readonly itemTargets:HTMLElement;
itemTargetConnected(element:HTMLElement) {
const autohide = element.dataset.autohide === 'true';
if (this.autohideValue && autohide) {
setTimeout(() => element.remove(), SUCCESS_AUTOHIDE_TIMEOUT);
}
}
}
+2
View File
@@ -10,6 +10,7 @@ import PollForChangesController from './controllers/poll-for-changes.controller'
import TableHighlightingController from './controllers/table-highlighting.controller';
import OpShowWhenCheckedController from './controllers/show-when-checked.controller';
import OpShowWhenValueSelectedController from './controllers/show-when-value-selected.controller';
import FlashController from './controllers/flash.controller';
declare global {
interface Window {
@@ -31,6 +32,7 @@ instance.register('menus--main', MainMenuController);
instance.register('show-when-checked', OpShowWhenCheckedController);
instance.register('disable-when-checked', OpDisableWhenCheckedController);
instance.register('show-when-value-selected', OpShowWhenValueSelectedController);
instance.register('flash', FlashController);
instance.register('print', PrintController);
instance.register('refresh-on-form-changes', RefreshOnFormChangesController);
instance.register('async-dialog', AsyncDialogController);
+15 -5
View File
@@ -17,21 +17,31 @@ See below for available arguments.
## Render primer banner / flash from controllers
In many views in OpenProject, you will find `flash[:notice], flash[:alert], flash[:error]` messages.
These are rendered using the previous `op-flash` styles, and are not yet primerized.
All of these are now rendered with primer banners by default.
So if you find yourself in need to render a primerized flash. You can use this pattern instead:
If you find the need to customize the rendering of the flash, you can also pass a hash to the flash:
```ruby
flash[:op_primer_flash] = { message: "Successful update", scheme: :success, icon: :check }
flash[:notice] = { message: "Successful update", icon: :check }
```
Or for an error:
```ruby
flash[:op_primer_flash] = { message: "Oh no! Something went wrong", scheme: :danger, icon: :alert }
flash[:error] = { message: "Oh no! Something went wrong", icon: :alert }
```
These are rendered in the layout through the `render_banner_messages` helper using the `OpPrimer::FlashComponent`.
If you want to render multiple lines, `message` can also be an array that will be joined by breaklines for rendering:
```ruby
flash[:error] = { message: ["Oh no! Something went wrong", "Some more details here"], icon: :alert }
```
If you want to make the flash non-dismissable, you can pass `dismiss_scheme: :none`:
```ruby
flash[:error] = { message: "Oh no!", icon: :alert, dismiss_scheme: :none }
```
## Usage in turbo streams
@@ -185,8 +185,7 @@ RSpec.describe "Backlogs in backlog view", :js,
click_button "Save"
backlogs_page
.expect_and_dismiss_toaster(message: "Successful update.")
expect_and_dismiss_flash(message: "Successful update.")
backlogs_page
.expect_backlog(sprint)
@@ -206,8 +205,7 @@ RSpec.describe "Backlogs in backlog view", :js,
click_button "Save"
backlogs_page
.expect_and_dismiss_toaster(message: "Successful update.")
expect_and_dismiss_flash(message: "Successful update.")
# Now works as a sprint instead of a backlog
backlogs_page
@@ -228,8 +226,7 @@ RSpec.describe "Backlogs in backlog view", :js,
click_button "Save"
backlogs_page
.expect_and_dismiss_toaster(message: "Successful update.")
expect_and_dismiss_flash(message: "Successful update.")
# the disabled backlog/sprint is no longer visible
expect(page)
@@ -250,8 +247,7 @@ RSpec.describe "Backlogs in backlog view", :js,
click_button "Save"
backlogs_page
.expect_and_dismiss_toaster(message: "Successful update.")
expect_and_dismiss_flash(message: "Successful update.")
# the disabled backlog/sprint is no longer visible
expect(page)
@@ -57,11 +57,11 @@ RSpec.describe "authorization for BCF api", :js, with_config: { edition: "bim" }
fill_in "application_redirect_uri", with: "not a url!"
click_on "Create"
expect(page).to have_css(".errorExplanation", text: "Redirect URI must be an absolute URI.")
expect(page).to have_text("Redirect URI must be an absolute URI.")
fill_in "application_redirect_uri", with: "urn:ietf:wg:oauth:2.0:oob\nhttps://localhost/my/callback"
click_on "Create"
expect(page).to have_css(".op-toast.-success", text: "Successful creation.")
expect_flash(message: "Successful creation.")
expect(page).to have_css(".attributes-key-value--key",
text: "Client ID")
@@ -103,7 +103,7 @@ RSpec.describe "Copy work packages through Rails view", :js, :with_cuprite, with
select budget.subject, from: "work_package_budget_id"
click_on "Submit"
wp_table.expect_and_dismiss_toaster message: "Successful update."
expect_and_dismiss_flash message: "Successful update."
expect(work_package.reload.budget_id).to eq(budget.id)
expect(work_package2.reload.budget_id).to eq(budget.id)
@@ -130,7 +130,7 @@ RSpec.describe "model management", :js, with_config: { edition: "bim" } do
it "I can't see any models and perform no actions" do
expected = "[Error 403] You are not authorized to access this page."
expect(page).to have_css(".op-toast.-error", text: expected)
expect_flash(type: :error, message: expected)
index_page.add_model_allowed false
end
@@ -45,6 +45,7 @@ RSpec.describe "model viewer", :js, with_config: { edition: "bim" } do
uploader: user)
end
let(:show_default_page) { Pages::IfcModels::ShowDefault.new(project) }
let(:show_model_page) { Pages::IfcModels::Show.new(project, model.id) }
let(:model_tree) { Components::XeokitModelTree.new }
let(:card_view) { Pages::WorkPackageCards.new(project) }
@@ -93,7 +94,7 @@ RSpec.describe "model viewer", :js, with_config: { edition: "bim" } do
it "shows a warning that no IFC models exist yet" do
login_as user
visit defaults_bcf_project_ifc_models_path(project)
expect(page).to have_css(".op-toast.-info", text: I18n.t("js.ifc_models.empty_warning"))
show_default_page.expect_toast(type: :info, message: I18n.t("js.ifc_models.empty_warning"))
end
end
end
@@ -134,7 +135,7 @@ RSpec.describe "model viewer", :js, with_config: { edition: "bim" } do
it "shows no viewer" do
expected = "[Error 403] You are not authorized to access this page."
expect(page).to have_css(".op-toast.-error", text: expected)
expect_flash(type: :error, message: expected)
show_model_page.model_viewer_visible false
show_model_page.model_viewer_shows_a_toolbar false
@@ -300,7 +300,7 @@ RSpec.describe "Board management spec", :js, with_ee: %i[board_view] do
it "does not allow viewing of boards" do
visit project_work_package_board_path(project, board_view)
expect(page).to have_css("#errorExplanation", text: I18n.t(:notice_not_authorized))
expect_flash(type: :error, message: I18n.t(:notice_not_authorized))
board_index.expect_editable false
end
@@ -311,7 +311,7 @@ RSpec.describe "Board management spec", :js, with_ee: %i[board_view] do
it "does not allow viewing of boards" do
board_index.visit!
expect(page).to have_css("#errorExplanation", text: I18n.t(:notice_not_authorized))
expect_flash(type: :error, message: I18n.t(:notice_not_authorized))
end
end
end
@@ -195,8 +195,9 @@ RSpec.describe "Boards",
it "renders a required attribute validation error" do
expect(Boards::Grid.all).to be_empty
new_board_page.expect_toast message: "Project #{I18n.t('activerecord.errors.messages.blank')}",
type: :error
expect_flash message: "Project #{I18n.t('activerecord.errors.messages.blank')}",
type: :error
new_board_page.expect_project_dropdown
end
end
@@ -72,7 +72,7 @@ module Pages
new_board_page.set_board_type action
new_board_page.click_on_submit
new_board_page.expect_and_dismiss_toaster
expect_and_dismiss_flash(message: I18n.t(:notice_successful_create))
if expect_empty
expect(page).to have_css(".boards-list--add-item-text", wait: 10)
@@ -284,7 +284,7 @@ module Pages
click_dropdown_entry "Delete"
accept_alert_dialog!
expect_and_dismiss_toaster message: I18n.t("js.notice_successful_delete")
expect_and_dismiss_flash message: I18n.t("js.notice_successful_delete")
end
def back_to_index
@@ -122,7 +122,7 @@ RSpec.describe "adding a new budget", :js do
new_budget_page.add_labor_costs! "0,5", user_name: user.name, comment: "attendance", expected_costs: "12,50 EUR"
page.find('[data-test-selector="budgets-create-button"]').click
expect(page).to have_content(I18n.t(:notice_successful_create, locale: :de))
expect_and_dismiss_flash(message: I18n.t(:notice_successful_create, locale: :de))
expect(new_budget_page.unit_costs_at(1)).to have_content "175,00 EUR"
expect(new_budget_page.unit_costs_at(2)).to have_content "50.025,00 EUR"
@@ -59,6 +59,8 @@ RSpec.describe "Upload attachment to budget", :js do
click_on "Create"
expect_and_dismiss_flash(message: "Successful creation.")
expect(page).to have_css("#content img", count: 1)
expect(page).to have_content("Image uploaded on creation")
attachments_list.expect_attached("image.png")
@@ -96,6 +98,8 @@ RSpec.describe "Upload attachment to budget", :js do
click_on "Create"
expect_and_dismiss_flash(message: "Successful creation.")
attachments_list.expect_attached("image.png")
within ".toolbar-items" do
@@ -88,7 +88,7 @@ RSpec.describe "Copying a budget", :js do
click_button "Create"
budget_page.expect_toast message: "Successful creation."
expect_flash message: "Successful creation."
expect(page)
.to have_css(".author", text: current_user.name)
@@ -181,7 +181,7 @@ RSpec.describe "updating a budget", :js do
# Update first element
budget_page.edit_planned_costs! material_budget_item.id, type: :material, costs: 123
expect(budget_page).to have_content("Successful update")
expect_and_dismiss_flash(message: "Successful update")
expect(page).to have_css("tbody td.currency", text: "123.00 EUR")
click_on "Update"
@@ -218,7 +218,7 @@ RSpec.describe "updating a budget", :js do
# Update first element
budget_page.edit_planned_costs! material_budget_item.id, type: :material, costs: 123
expect(budget_page).to have_content("Successful update")
expect_and_dismiss_flash(message: "Successful update")
expect(page).to have_css("tbody td.currency", text: "USD 123.00")
click_on "Update"
@@ -258,7 +258,7 @@ RSpec.describe "updating a budget", :js do
# Update first element
budget_page.edit_planned_costs! labor_budget_item.id, type: :labor, costs: 456
expect(budget_page).to have_content("Successful update")
expect_and_dismiss_flash(message: "Successful update")
expect(page).to have_css("tbody td.currency", text: "456.00 EUR")
click_on "Update"
@@ -295,7 +295,7 @@ RSpec.describe "updating a budget", :js do
# Update first element
budget_page.edit_planned_costs! labor_budget_item.id, type: :labor, costs: 456
expect(budget_page).to have_content("Successful update")
expect_and_dismiss_flash(message: "Successful update")
expect(page).to have_css("tbody td.currency", text: "USD 456.00")
click_on "Update"
@@ -99,7 +99,7 @@ RSpec.describe "Work Package cost fields", :js do
click_on "Save"
# Expect correct costs
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_cost_logged_successfully))
expect_flash(message: I18n.t(:notice_cost_logged_successfully))
entry = CostEntry.last
expect(entry.cost_type_id).to eq(cost_type2.id)
expect(entry.units).to eq(2.0)
@@ -136,7 +136,7 @@ RSpec.describe "Work Package cost fields", :js do
click_on I18n.t(:button_save)
# Expect correct costs
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_cost_logged_successfully))
expect_flash(message: I18n.t(:notice_cost_logged_successfully))
entry = CostEntry.last
expect(entry.cost_type_id).to eq(cost_type2.id)
expect(entry.units).to eq(1.42)
@@ -77,7 +77,7 @@ RSpec.describe "Create cost entry without rate permissions", :js do
click_on "Save"
# Expect correct costs
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_cost_logged_successfully))
expect_flash(message: I18n.t(:notice_cost_logged_successfully))
entry = CostEntry.last
expect(entry.cost_type_id).to eq(cost_type.id)
expect(entry.units).to eq(1.0)
@@ -35,7 +35,7 @@ RSpec.describe "LDAP group sync administration spec", :js do
check "synchronized_group_sync_users"
click_on "Create"
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_create))
expect_flash(message: I18n.t(:notice_successful_create))
expect(page).to have_css("td.dn", text: "cn=foo,ou=groups,dc=example,dc=com")
expect(page).to have_css("td.ldap_auth_source", text: "ldap")
expect(page).to have_css("td.group", text: "foo")
@@ -69,7 +69,7 @@ RSpec.describe "LDAP group sync administration spec", :js do
SeleniumHubWaiter.wait
click_on "Delete"
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_delete))
expect_flash(message: I18n.t(:notice_successful_delete))
expect(page).to have_css ".generic-table--empty-row"
expect(LdapGroups::Membership.where(id: memberships)).to be_empty
@@ -167,8 +167,7 @@ RSpec.describe MeetingsController do
expect(response).to have_http_status :ok
expect(response).to render_template :new
expect(response.body)
.to have_css "#errorExplanation li",
text: "Date #{I18n.t('activerecord.errors.messages.not_an_iso_date')}"
.to have_text("Date #{I18n.t('activerecord.errors.messages.not_an_iso_date')}")
end
end
@@ -181,8 +180,7 @@ RSpec.describe MeetingsController do
expect(response).to have_http_status :ok
expect(response).to render_template :new
expect(response.body)
.to have_css "#errorExplanation li",
text: "Start time #{I18n.t('activerecord.errors.messages.invalid_time_format')}"
.to have_text("Start time #{I18n.t('activerecord.errors.messages.invalid_time_format')}")
end
end
end
@@ -194,8 +192,7 @@ RSpec.describe MeetingsController do
expect(response).to have_http_status :ok
expect(response).to render_template :new
expect(response.body)
.to have_css "#errorExplanation li",
text: "Project #{I18n.t('activerecord.errors.messages.blank')}"
.to have_text("Project #{I18n.t('activerecord.errors.messages.blank')}")
end
end
@@ -207,8 +204,7 @@ RSpec.describe MeetingsController do
expect(response).to have_http_status :ok
expect(response).to render_template :new
expect(response.body)
.to have_css "#errorExplanation li",
text: "Project #{I18n.t('activerecord.errors.messages.blank')}"
.to have_text("Project #{I18n.t('activerecord.errors.messages.blank')}")
end
end
end
@@ -97,7 +97,7 @@ RSpec.describe "Meetings new", :js, with_cuprite: false do
show_page = new_page.click_create
show_page.expect_toast(message: "Successful creation")
expect_flash(message: "Successful creation.")
show_page.expect_invited(user, other_user)
@@ -143,8 +143,8 @@ RSpec.describe "Meetings new", :js, with_cuprite: false do
it "renders a validation error" do
new_page.click_create
new_page.expect_toast(message: "#{Project.model_name.human} #{I18n.t('activerecord.errors.messages.blank')}",
type: :error)
expect_flash(type: :error,
message: "#{Project.model_name.human} #{I18n.t('activerecord.errors.messages.blank')}")
new_page.expect_project_dropdown
end
@@ -178,7 +178,7 @@ RSpec.describe "Meetings new", :js, with_cuprite: false do
show_page = new_page.click_create
show_page.expect_toast(message: "Successful creation")
expect_flash(message: "Successful creation.")
# Not sure if that is then intended behaviour but that is what is currently programmed
show_page.expect_invited(admin)
@@ -194,8 +194,10 @@ RSpec.describe "Meetings new", :js, with_cuprite: false do
it "renders a validation error" do
new_page.click_create
new_page.expect_toast(message: "#{Project.model_name.human} #{I18n.t('activerecord.errors.messages.blank')}",
type: :error)
expect_flash(
message: "#{Project.model_name.human} #{I18n.t('activerecord.errors.messages.blank')}",
type: :error
)
new_page.expect_project_dropdown
end
end
@@ -254,7 +256,7 @@ RSpec.describe "Meetings new", :js, with_cuprite: false do
show_page = new_page.click_create
show_page.expect_toast(message: "Successful creation")
expect_flash(message: "Successful creation.")
show_page.expect_invited(user, other_user)
@@ -315,7 +317,7 @@ RSpec.describe "Meetings new", :js, with_cuprite: false do
show_page = new_page.click_create
show_page.expect_toast(message: "Successful creation")
expect_flash(message: "Successful creation.")
# Not sure if that is then intended behaviour but that is what is currently programmed
show_page.expect_invited(admin)
@@ -342,9 +344,9 @@ RSpec.describe "Meetings new", :js, with_cuprite: false do
new_page.set_title "Some title"
new_page.set_type "Classic"
show_page = new_page.click_create
new_page.click_create
show_page.expect_toast(message: "Successful creation")
expect_flash(message: "Successful creation.")
meeting = Meeting.last
@@ -352,7 +354,7 @@ RSpec.describe "Meetings new", :js, with_cuprite: false do
field.submit_by_enter
show_page.expect_and_dismiss_toaster message: "Successful update"
expect_flash(message: "Successful update")
meeting.reload
@@ -64,7 +64,7 @@ RSpec.describe "Meetings participants" do
edit_page.invite(viewer_user)
show_page = edit_page.click_save
show_page.expect_toast(message: "Successful update")
expect_flash(message: "Successful update")
show_page.expect_invited(viewer_user)
@@ -126,7 +126,7 @@ RSpec.describe "Meetings", :js do
field.submit_by_enter
show_page.expect_and_dismiss_toaster message: "Successful update"
expect_and_dismiss_flash(message: "Successful update")
meeting.reload
@@ -355,6 +355,6 @@ RSpec.describe "history",
visit history_meeting_path(meeting)
expected = "[Error 403] You are not authorized to access this page."
expect(page).to have_css(".op-toast.-error", text: expected)
expect_flash(type: :error, message: expected)
end
end
@@ -26,11 +26,14 @@
# See COPYRIGHT and LICENSE files for more details.
#++
require "support/flash/expectations"
module Components
class CostReportsBaseTable
include Capybara::DSL
include Capybara::RSpecMatchers
include RSpec::Matchers
include Flash::Expectations
attr_reader :time_logging_modal
@@ -78,7 +81,7 @@ module Components
SeleniumHubWaiter.wait
fill_in("cost_entry_units", with: new_value)
click_button "Save"
expect(page).to have_css(".op-toast.-success")
expect_flash(message: "Successful update.")
end
def delete_entry(row)
@@ -73,10 +73,7 @@ class Storages::Admin::AutomaticallyManagedProjectFoldersController < Applicatio
service_result = call_update_service
if service_result.success?
flash[:op_primer_flash] = {
message: I18n.t(:"storages.notice_successful_storage_connection"),
scheme: :success
}
flash[:notice] = I18n.t(:"storages.notice_successful_storage_connection")
redirect_to edit_admin_settings_storage_path(@storage)
else
respond_with_ampf_form_turbo_stream_or_edit_html
@@ -125,7 +125,7 @@ class Storages::Admin::OAuthClientsController < ApplicationController
end
def finish_setup
flash[:op_primer_flash] = { message: I18n.t(:"storages.notice_successful_storage_connection"), scheme: :success }
flash[:notice] = I18n.t(:"storages.notice_successful_storage_connection")
redirect_to edit_admin_settings_storage_path(@storage)
end
@@ -191,9 +191,7 @@ class Storages::Admin::StoragesController < ApplicationController
update_via_turbo_stream(component: Storages::Admin::SidePanel::HealthNotificationsComponent.new(storage: @storage))
respond_with_turbo_streams
else
flash.now[:op_primer_flash] = {
message: I18n.t("storages.health_email_notifications.error_could_not_be_saved"), scheme: :danger
}
flash.now[:error] = I18n.t("storages.health_email_notifications.error_could_not_be_saved")
render :edit
end
end
@@ -209,11 +207,11 @@ class Storages::Admin::StoragesController < ApplicationController
# rubocop:disable Rails/ActionControllerFlashBeforeRender
service_result.on_failure do
flash[:op_primer_flash] = { message: join_flash_messages(service_result.errors.full_messages), scheme: :danger }
flash[:error] = service_result.errors.full_messages
end
service_result.on_success do
flash[:op_primer_flash] = { message: I18n.t(:notice_successful_delete), scheme: :success }
flash[:notice] = I18n.t(:notice_successful_delete)
end
# rubocop:enable Rails/ActionControllerFlashBeforeRender
@@ -265,7 +263,7 @@ class Storages::Admin::StoragesController < ApplicationController
def ensure_valid_provider_type_selected
short_provider_type = params[:provider]
if short_provider_type.blank? || (@provider_type = ::Storages::Storage::PROVIDER_TYPE_SHORT_NAMES[short_provider_type]).blank?
flash[:op_primer_flash] = { message: I18n.t("storages.error_invalid_provider_type"), scheme: :danger }
flash[:error] = I18n.t("storages.error_invalid_provider_type")
redirect_to admin_settings_storages_path
end
end
@@ -181,7 +181,7 @@ RSpec.describe "Admin Create a new file storage",
expect(page).to have_current_path(edit_admin_settings_storage_path(Storages::Storage.last))
expect(page).to have_test_selector(
"primer-banner-message-component",
"op-primer-flash-message",
text: "Storage connected successfully! Remember to activate the module and the specific " \
"storage in the project settings of each desired project to use it."
)
@@ -318,7 +318,7 @@ RSpec.describe "Admin Create a new file storage",
expect(page).to have_current_path(edit_admin_settings_storage_path(Storages::Storage.last))
wait_for { page }.to have_test_selector(
"primer-banner-message-component",
"op-primer-flash-message",
text: "Storage connected successfully! Remember to activate the module and the specific " \
"storage in the project settings of each desired project to use it."
)
@@ -50,7 +50,7 @@ RSpec.describe "activating an invited account", :js,
activate!
expect(page).to have_css(".op-toast.-success", text: "Developer strategy generated the following one-time password:")
expect_flash(message: "Developer strategy generated the following one-time password:")
SeleniumHubWaiter.wait
fill_in I18n.t(:field_otp), with: sms_token
@@ -63,7 +63,7 @@ RSpec.describe "activating an invited account", :js,
it "handles faulty user input on two factor authentication" do
activate!
expect(page).to have_css(".op-toast.-success", text: "Developer strategy generated the following one-time password:")
expect_flash(message: "Developer strategy generated the following one-time password:")
fill_in I18n.t(:field_otp), with: "asdf" # faulty token
click_button I18n.t(:button_login)
@@ -44,7 +44,7 @@ RSpec.describe "Admin 2FA management", :js, with_settings: {
click_button I18n.t(:button_continue)
# Enter valid phone number
expect(page).to have_css("#errorExplanation", text: "Phone number must be of format +XX XXXXXXXXX")
expect_flash(type: :error, message: "Phone number must be of format +XX XXXXXXXXX")
SeleniumHubWaiter.wait
fill_in "device_phone_number", with: "+49 123456789"
@@ -50,7 +50,7 @@ RSpec.describe "Login with 2FA backup code", :js, with_settings: {
click_on "Submit"
# Expect failure
expect(page).to have_css(".op-toast.-error", text: I18n.t("two_factor_authentication.error_invalid_backup_code"))
expect_flash(type: :error, message: I18n.t("two_factor_authentication.error_invalid_backup_code"))
expect(page).to have_current_path signin_path
# Try again!
@@ -36,7 +36,7 @@ RSpec.describe "Login with enforced 2FA", :js, with_settings: {
first_login_step
two_factor_step("whatever")
expect(page).to have_css(".op-toast.-error", text: I18n.t(:notice_account_otp_invalid))
expect_flash(type: :error, message: I18n.t(:notice_account_otp_invalid))
expect(page).to have_current_path signin_path
end
end
@@ -35,7 +35,7 @@ RSpec.describe "Login with 2FA device", :js, with_settings: {
first_login_step
two_factor_step("whatever")
expect(page).to have_css(".op-toast.-error", text: I18n.t(:notice_account_otp_invalid))
expect_flash(type: :error, message: I18n.t(:notice_account_otp_invalid))
expect(page).to have_current_path signin_path
end
end
@@ -35,7 +35,7 @@ RSpec.describe "My Account 2FA configuration", :js, with_settings: {
click_button I18n.t(:button_continue)
# Enter valid phone number
expect(page).to have_css("#errorExplanation", text: "Phone number must be of format +XX XXXXXXXXX")
expect_flash(type: :error, message: "Phone number must be of format +XX XXXXXXXXX")
fill_in "device_phone_number", with: "+49 123456789"
click_button I18n.t(:button_continue)
@@ -55,8 +55,8 @@ RSpec.describe "My Account 2FA configuration", :js, with_settings: {
expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.devices.confirm_device"))
expect(page).to have_css("input#otp")
expect(page).to have_css(".op-toast.-error",
text: I18n.t("two_factor_authentication.devices.registration_failed_token_invalid"))
expect_flash(type: :error, message: I18n.t("two_factor_authentication.devices.registration_failed_token_invalid"))
# Fill in correct token
fill_in "otp", with: sms_token
@@ -60,7 +60,7 @@ RSpec.describe "Login with 2FA remember cookie", :js, with_settings: {
visit my_2fa_devices_path
find(".two-factor-authentication--remove-remember-cookie-link").click
expect(page).to have_css(".op-toast.-success")
expect_flash(message: I18n.t("two_factor_authentication.remember.cookie_removed"))
expect(page).to have_no_css(".two-factor-authentication--remove-remember-cookie-link")
# Log out and in again
@@ -35,8 +35,8 @@ end
RSpec.shared_examples "create enforced sms device" do
it do
expect(page).to have_css(".op-toast.-info",
text: I18n.t("two_factor_authentication.forced_registration.required_to_add_device"))
expect_flash(type: :info,
message: I18n.t("two_factor_authentication.forced_registration.required_to_add_device"))
SeleniumHubWaiter.wait
# Create SMS device
@@ -46,7 +46,7 @@ RSpec.shared_examples "create enforced sms device" do
click_on "Continue"
# Expect error on invalid phone
expect(page).to have_css("#errorExplanation", text: "Phone number must be of format +XX XXXXXXXXX")
expect_flash(type: :error, message: "Phone number must be of format +XX XXXXXXXXX")
SeleniumHubWaiter.wait
fill_in "device_phone_number", with: "+49 123456789"
@@ -63,7 +63,7 @@ RSpec.shared_examples "create enforced sms device" do
# Log token for next access
sms_token = nil
allow_any_instance_of(OpenProject::TwoFactorAuthentication::TokenStrategy::Developer)
.to receive(:create_mobile_otp).and_wrap_original do |m|
.to receive(:create_mobile_otp).and_wrap_original do |m|
sms_token = m.call
end
@@ -71,8 +71,7 @@ RSpec.shared_examples "create enforced sms device" do
expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.devices.confirm_device"))
expect(page).to have_css("input#otp")
expect(page).to have_css(".op-toast.-error",
text: I18n.t("two_factor_authentication.devices.registration_failed_token_invalid"))
expect_flash(type: :error, message: I18n.t("two_factor_authentication.devices.registration_failed_token_invalid"))
SeleniumHubWaiter.wait
# Fill in wrong token
@@ -40,7 +40,7 @@ RSpec.describe "Manage webhooks through UI", :js do
# 1st webhook created
#
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_create))
expect_flash(message: I18n.t(:notice_successful_create))
expect(page).to have_css(".webhooks--outgoing-webhook-row .name", text: "My webhook")
webhook = Webhooks::Webhook.last
expect(webhook.event_names).to eq %w(work_package:created)
@@ -65,7 +65,7 @@ RSpec.describe "Manage webhooks through UI", :js do
find(".webhooks--selected-project-ids[value='#{project.id}']").set true
click_on "Save"
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update))
expect_flash(message: I18n.t(:notice_successful_update))
expect(page).to have_css(".webhooks--outgoing-webhook-row .name", text: "My webhook")
webhook = Webhooks::Webhook.last
expect(webhook.event_names).to eq %w(work_package:updated)
@@ -77,7 +77,7 @@ RSpec.describe "Manage webhooks through UI", :js do
find(".webhooks--outgoing-webhook-row-#{webhook.id} .icon-delete").click
page.driver.browser.switch_to.alert.accept
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_delete))
expect_flash(message: I18n.t(:notice_successful_delete))
expect(page).to have_css(".generic-table--empty-row")
end
+1 -1
View File
@@ -133,7 +133,7 @@ RSpec.describe NewsController do
expect(assigns(:news)).not_to be_nil
expect(assigns(:news)).to be_new_record
expect(response.body).to have_css("div.op-toast.-error", text: /1 error/)
expect(response.body).to have_text /1 error/
end
end
@@ -52,7 +52,8 @@ RSpec.describe "Wiki Activity", :js, :with_cuprite do
editor.set_markdown("First content")
click_button "Save"
expect(page).to have_text("Successful creation")
expect_and_dismiss_flash(message: "Successful creation.")
# We mock letting some time pass by altering the timestamps
Journal.last.update_columns(created_at: Time.now - 5.days, updated_at: Time.now - 5.days)
@@ -113,7 +113,7 @@ RSpec.describe "Attribute help texts", :js, :with_cuprite do
click_button "Save"
# Handle errors
expect(page).to have_css("#errorExplanation", text: "Help text can't be blank.")
expect_flash(type: :error, message: "Help text can't be blank.")
SeleniumHubWaiter.wait
editor.set_markdown("New**help**text")
click_button "Save"
@@ -60,9 +60,8 @@ RSpec.describe "Enterprise token", :js, :with_cuprite do
submit_button.click
# Error output
expect(page).to have_css(".errorExplanation",
text: "Enterprise support token can't be read. " \
"Are you sure it is a support token?")
expect_flash(type: :error,
message: "Enterprise support token can't be read. Are you sure it is a support token?")
within "span.errorSpan" do
expect(page).to have_css("#enterprise_token_encoded_token")
@@ -78,7 +77,7 @@ RSpec.describe "Enterprise token", :js, :with_cuprite do
textarea.set "foobar"
submit_button.click
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update))
expect_flash(message: I18n.t(:notice_successful_update))
expect(page).to have_test_selector("op-enterprise--active-token")
expect(page.all(".attributes-key-value--key").map(&:text))
@@ -101,7 +100,7 @@ RSpec.describe "Enterprise token", :js, :with_cuprite do
wait_for_reload
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update))
expect_flash(message: I18n.t(:notice_successful_update))
# Assume next request
RequestStore.clear!
@@ -115,7 +114,7 @@ RSpec.describe "Enterprise token", :js, :with_cuprite do
wait_for_reload
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_delete))
expect_flash(message: I18n.t(:notice_successful_delete))
# Assume next request
RequestStore.clear!
@@ -257,7 +257,7 @@ RSpec.describe "Enterprise trial management",
it "can confirm that trial regularly" do
find_test_selector("op-ee-trial-waiting-resend-link", text: "Resend").click
expect(page).to have_css(".op-toast.-success", text: "Email has been resent.", wait: 20)
expect(page).to have_css(".op-toast", text: "Email has been resent.", wait: 20)
expect(page).to have_text "foo@foocorp.example"
expect(page).to have_text "email sent - waiting for confirmation"
@@ -276,7 +276,7 @@ RSpec.describe "Enterprise trial management",
# advance to close
click_on "Continue"
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_and_dismiss_flash(message: "Successful update.")
expect(page).to have_css(".attributes-key-value--value-container", text: "OpenProject Test")
expect(page).to have_css(".attributes-key-value--value-container", text: "01/01/2020")
expect(page).to have_css(".attributes-key-value--value-container", text: "01/02/2020")
@@ -49,20 +49,20 @@ RSpec.describe "OAuth applications management", :js, :with_cuprite do
fill_in "application_redirect_uri", with: "not a url!"
click_on "Create"
expect(page).to have_css(".errorExplanation", text: "Redirect URI must be an absolute URI.")
expect_flash(type: :error, message: "Redirect URI must be an absolute URI.")
fill_in("application_redirect_uri", with: "")
# Fill redirect_uri which does not provide a Secure Context
fill_in "application_redirect_uri", with: "http://example.org"
click_on "Create"
expect(page).to have_css(".errorExplanation", text: 'Redirect URI is not providing a "Secure Context"')
expect_flash(type: :error, message: 'Redirect URI is not providing a "Secure Context"')
# Can create localhost without https (https://community.openproject.com/wp/34025)
fill_in "application_redirect_uri", with: "urn:ietf:wg:oauth:2.0:oob\nhttp://localhost/my/callback"
click_on "Create"
expect(page).to have_css(".op-toast.-success", text: "Successful creation.")
expect_flash(message: "Successful creation.")
expect(page).to have_css(".attributes-key-value--key", text: "Client ID")
expect(page).to have_css(".attributes-key-value--value", text: "urn:ietf:wg:oauth:2.0:oob\nhttp://localhost/my/callback")
@@ -51,7 +51,7 @@ RSpec.describe "Progress tracking admin page", :js, :with_cuprite do
expect(page).to have_text(expected_warning_text)
click_on "Save"
expect_and_dismiss_toaster(message: "Successful update.")
expect_and_dismiss_flash(message: "Successful update.")
expect(Setting.find_by(name: "work_package_done_ratio").value).to eq("status")
# now change from status-based to work-based
@@ -65,7 +65,7 @@ RSpec.describe "Progress tracking admin page", :js, :with_cuprite do
expect(page).to have_text(expected_warning_text)
click_on "Save"
expect_and_dismiss_toaster(message: "Successful update.")
expect_and_dismiss_flash(message: "Successful update.")
expect(Setting.find_by(name: "work_package_done_ratio").value).to eq("field")
end
@@ -44,7 +44,7 @@ RSpec.describe "Test mail notification", :js, :with_cuprite do
click_link "Send a test email"
expected = "An error occurred while sending mail (#{error_message})"
expect(page).to have_css(".op-toast.-error", text: expected)
expect_flash(type: :error, message: expected)
expect(page).to have_no_css(".op-toast.-error strong")
end
end
+6 -7
View File
@@ -101,7 +101,7 @@ RSpec.describe "Working Days", :js, :with_cuprite do
dialog.confirm
end
expect(page).to have_css(".op-toast.-success", text: "Successful update.")
expect_flash(message: "Successful update.")
expect(page).to have_unchecked_field "Monday"
expect(page).to have_unchecked_field "Friday"
expect(page).to have_unchecked_field "Saturday"
@@ -141,8 +141,7 @@ RSpec.describe "Working Days", :js, :with_cuprite do
dialog.confirm
end
expect(page).to have_css(".op-toast.-error",
text: "At least one day of the week must be defined as a working day.")
expect_flash(type: :error, message: "At least one day of the week must be defined as a working day.")
# Restore the checkboxes to their valid state
expect(page).to have_checked_field "Monday"
expect(page).to have_checked_field "Tuesday"
@@ -172,8 +171,8 @@ RSpec.describe "Working Days", :js, :with_cuprite do
# Not executing the background jobs
dialog.confirm
expect(page).to have_css(".op-toast.-error",
text: "The previous changes to the working days configuration have not been applied yet.")
expect_flash(type: :error,
message: "The previous changes to the working days configuration have not been applied yet.")
end
end
@@ -230,7 +229,7 @@ RSpec.describe "Working Days", :js, :with_cuprite do
click_on "Apply changes"
click_on "Save and reschedule"
expect(page).to have_css(".op-toast.-success", text: "Successful update.")
expect_flash(message: "Successful update.")
nwd1 = NonWorkingDay.find_by(name: "My holiday")
expect(nwd1.date).to eq date1
@@ -310,6 +309,6 @@ RSpec.describe "Working Days", :js, :with_cuprite do
click_on "Apply changes"
# No dialog and saved successfully
expect(page).to have_css(".op-toast.-success")
expect_flash(message: "Successful update.")
end
end
@@ -168,7 +168,7 @@ RSpec.describe "Authentication Stages" do
find_by_id("toggle_consent_time").set(true)
click_on "Save"
expect(page).to have_css(".op-toast.-success")
expect_flash(message: "Successful update.")
Setting.clear_cache
expect(Setting.consent_time).to be_present
@@ -215,7 +215,7 @@ RSpec.describe "Authentication Stages" do
check "consent_check"
click_on I18n.t(:button_create)
expect(page).to have_css(".op-toast.-success")
expect_flash(message: I18n.t(:notice_account_registered_and_logged_in))
expect_logged_in("/?first_time_user=true")
end
@@ -256,7 +256,7 @@ RSpec.describe "Authentication Stages" do
# Decline the consent
click_on I18n.t(:button_decline)
expect(page).to have_css(".op-toast.-error", text: "foo@example.org")
expect_flash(type: :error, message: "foo@example.org")
end
end
end
+5 -5
View File
@@ -39,14 +39,14 @@ RSpec.describe "Lost password" do
fill_in "mail", with: "invalid mail"
click_on "Submit"
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_account_lost_email_sent))
expect_flash(message: I18n.t(:notice_account_lost_email_sent))
perform_enqueued_jobs
expect(ActionMailer::Base.deliveries.size).to be 0
fill_in "mail", with: user.mail
click_on "Submit"
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_account_lost_email_sent))
expect_flash(message: I18n.t(:notice_account_lost_email_sent))
perform_enqueued_jobs
expect(ActionMailer::Base.deliveries.size).to be 1
@@ -60,7 +60,7 @@ RSpec.describe "Lost password" do
click_button "Save"
expect(page).to have_css(".op-toast.-info", text: I18n.t(:notice_account_password_updated))
expect_flash(type: :info, message: I18n.t(:notice_account_password_updated))
login_with user.login, new_password
@@ -79,7 +79,7 @@ RSpec.describe "Lost password" do
fill_in "mail", with: user.mail
click_on "Submit"
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_account_lost_email_sent))
expect_flash(message: I18n.t(:notice_account_lost_email_sent))
perform_enqueued_jobs
expect(ActionMailer::Base.deliveries.size).to be 1
@@ -99,7 +99,7 @@ RSpec.describe "Lost password" do
fill_in "mail", with: user.mail
click_on "Submit"
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_account_lost_email_sent))
expect_flash(message: I18n.t(:notice_account_lost_email_sent))
perform_enqueued_jobs
expect(ActionMailer::Base.deliveries.size).to be 1
@@ -38,7 +38,7 @@ RSpec.describe "Reordering custom options of a list custom field", :js do
click_link "Reorder values alphabetically"
cf_page.accept_alert_dialog!
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update))
expect_flash(message: I18n.t(:notice_successful_update))
expect(custom_field.custom_options.order(:position).pluck(:value))
.to eq get_possible_values_reordered(200)
end
@@ -60,7 +60,7 @@ RSpec.describe "Tabs navigation and content switching on the admin/design page"
it "selects a color theme and redirect to the interface tab" do
select("OpenProject Gray", from: "theme")
find("[data-test-selector='color-theme-button']").click
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update))
expect_flash(message: I18n.t(:notice_successful_update))
expect(page).to have_current_path custom_style_path(tab: "interface")
end
@@ -78,7 +78,7 @@ RSpec.describe "Tabs navigation and content switching on the admin/design page"
# select a color theme and redirect to the branding tab
select("OpenProject Navy Blue", from: "theme")
find("[data-test-selector='color-theme-button']").click
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update))
expect_flash(message: I18n.t(:notice_successful_update))
expect(page).to have_current_path custom_style_path(tab: "branding")
# remove the logo and redirect to the branding tab
@@ -94,7 +94,7 @@ RSpec.describe "Tabs navigation and content switching on the admin/design page"
# select a color theme and redirect to the PDF export styles tab
select("OpenProject (default)", from: "theme")
find("[data-test-selector='color-theme-button']").click
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update))
expect_flash(message: I18n.t(:notice_successful_update))
expect(page).to have_current_path custom_style_path(tab: "pdf_export_styles")
# change export cover text color and redirect to the PDF export styles tab
+1 -1
View File
@@ -45,7 +45,7 @@ RSpec.describe "group memberships through groups page", :js, :with_cuprite do
groups_page.delete_group! "Bob's Team"
expect(page).to have_css(".op-toast.-info", text: I18n.t(:notice_deletion_scheduled))
expect_flash(type: :info, message: I18n.t(:notice_deletion_scheduled))
expect(groups_page).to have_group "Bob's Team"
perform_enqueued_jobs
+1 -1
View File
@@ -71,7 +71,7 @@ RSpec.describe "Homescreen", "index", :with_cuprite do
welcome_text_editor.click_and_type_slowly("Hello! ")
general_settings_page.press_save_button
general_settings_page.expect_and_dismiss_toaster
expect_and_dismiss_flash(message: "Successful update.")
visit root_url
expect(page)
+3 -3
View File
@@ -52,7 +52,7 @@ RSpec.describe "CRUD LDAP connections", :js, :with_cuprite do
click_on "Create"
ldap_page.expect_and_dismiss_toaster message: "Successful creation."
expect_and_dismiss_flash message: "Successful creation."
expect(page).to have_css("td.name", text: "My LDAP connection")
expect(page).to have_css("td.host", text: "localhost")
@@ -71,7 +71,7 @@ RSpec.describe "CRUD LDAP connections", :js, :with_cuprite do
accept_prompt { click_on "Delete" }
end
ldap_page.expect_and_dismiss_toaster message: "Successful deletion."
expect_and_dismiss_flash message: "Successful deletion."
expect(page).to have_no_text "My LDAP connection"
expect(page).to have_text "Admin connection"
@@ -88,7 +88,7 @@ RSpec.describe "CRUD LDAP connections", :js, :with_cuprite do
fill_in "ldap_auth_source_name", with: "Updated Admin connection"
click_on "Save"
ldap_page.expect_and_dismiss_toaster message: "Successful update."
expect_flash(message: "Successful update.")
expect(page).to have_css("td.name", text: "Updated Admin connection")
end
+1 -1
View File
@@ -84,7 +84,7 @@ RSpec.describe "members pagination", :js do
members_page.visit!
SeleniumHubWaiter.wait
members_page.remove_user! "Alice Alison"
members_page.expect_and_dismiss_toaster
expect_and_dismiss_flash message: "Removed Alice Alison from project"
expect(members_page).to have_user "Bob Bobbit"
SeleniumHubWaiter.wait
@@ -101,7 +101,7 @@ RSpec.describe "OAuth authorization code flow", :js do
page.driver.browser.switch_to.alert.accept
# Should be back on access_token path
expect(page).to have_css(".op-toast.-success")
expect_flash(message: "Revocation of application Cool API app! successful.")
expect(page).to have_no_css("[id^=oauth-application-grant]")
expect(page).to have_current_path /\/my\/access_token/
@@ -40,7 +40,7 @@ RSpec.describe "create placeholder users", :selenium do
new_placeholder_user_page.submit!
expect(page).to have_css(".op-toast", text: "Successful creation.")
expect_flash(message: "Successful creation.")
new_placeholder_user = PlaceholderUser.order(Arel.sql("id DESC")).first
@@ -49,7 +49,7 @@ RSpec.describe "delete placeholder user", :js do
expect(page).to have_css(".danger-zone--verification button:not([disabled])")
click_on "Delete"
expect(page).to have_css(".op-toast.-info", text: I18n.t(:notice_deletion_scheduled))
expect_flash(type: :info, message: I18n.t(:notice_deletion_scheduled))
# The user is still there
placeholder_user.reload
@@ -41,7 +41,7 @@ RSpec.describe "edit placeholder users", :js do
click_on "Save"
expect(page).to have_css(".op-toast.-success", text: "Successful update.")
expect_flash(message: "Successful update.")
placeholder_user.reload
@@ -30,7 +30,7 @@ RSpec.shared_examples "principal membership management flows" do
principal_page.expect_project(project.name)
principal_page.edit_roles!(member, %w())
expect(page).to have_css(".op-toast.-error", text: "Roles need to be assigned.")
expect_flash(type: :error, message: "Roles need to be assigned.")
# Remove the user from the project
principal_page.remove_from_project!(project.name)
+1 -1
View File
@@ -53,7 +53,7 @@ RSpec.describe "Projects#destroy", :js, :with_cuprite do
expect(danger_zone).not_to be_disabled
danger_zone.danger_button.click
expect(page).to have_css ".op-toast.-success", text: I18n.t("projects.delete.scheduled")
expect_flash message: I18n.t("projects.delete.scheduled")
expect(project.reload).to eq(project)
perform_enqueued_jobs
+4 -5
View File
@@ -65,11 +65,10 @@ RSpec.describe "Projects module administration" do
check "Calendar"
click_button "Save"
expect(page)
.to have_css ".op-toast.-error",
text: I18n.t(:"activerecord.errors.models.project.attributes.enabled_modules.dependency_missing",
dependency: "Work packages",
module: "Calendars")
expect_flash(type: :error, message:
I18n.t(:"activerecord.errors.models.project.attributes.enabled_modules.dependency_missing",
dependency: "Work packages",
module: "Calendars"))
expect(page).to have_no_xpath(project_work_packages_menu_link_selector)
@@ -117,7 +117,7 @@ RSpec.describe "Edit project custom fields on project overview page", :js do
member_with_project_attributes_edit_permissions.reload
dialog.submit
expect(page).to have_css("#errorExplanation", text: I18n.t(:notice_not_authorized))
expect_flash(type: :error, message: I18n.t(:notice_not_authorized))
end
end
end
@@ -274,9 +274,9 @@ RSpec.describe "Projects index page", :js, :with_cuprite, with_settings: { login
error_text = "Orders ><script src='/foobar js'></script> is not set to one of the allowed values. and does not exist."
error_html = "Orders &gt;&lt;script src='/foobar js'&gt;&lt;/script&gt; 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_flash(type: :error, message: error_text)
error_container = page.find(".op-toast.-error")
error_container = find_flash_element(type: :error)
expect(error_container["innerHTML"]).to include error_html
end
end
@@ -115,7 +115,7 @@ RSpec.describe "Projects index page", :js, :with_cuprite, with_settings: { login
# Save the page
scroll_to_and_click(find(".button", text: "Save"))
expect(page).to have_css(".op-toast.-success", text: "Successful update.")
expect_flash(message: "Successful update.")
RequestStore.clear!
query = JSON.parse Setting.project_gantt_query
+1
View File
@@ -44,6 +44,7 @@ RSpec.describe "Project templates", :js, :with_cuprite,
# Make a template
find(".button", text: "Set as template").click
expect_and_dismiss_flash(message: "Successful update.")
expect(page).to have_css(".button", text: "Remove from templates")
project.reload
@@ -149,8 +149,7 @@ RSpec.describe "Create repository", :js, :selenium do
click_button(I18n.t(:button_create))
expect(page).to have_css("div.op-toast.-success",
text: I18n.t("repositories.create_successful"))
expect_flash(message: I18n.t("repositories.create_successful"))
expect(page).to have_css("a.icon-delete", text: I18n.t(:button_delete))
end
end
@@ -162,8 +161,7 @@ RSpec.describe "Create repository", :js, :selenium do
click_button(I18n.t(:button_create))
expect(page).to have_css("div.op-toast.-success",
text: I18n.t("repositories.create_successful"))
expect_flash(message: I18n.t("repositories.create_successful"))
expect(page).to have_css('button[type="submit"]', text: I18n.t(:button_save))
expect(page).to have_css("a.icon-remove", text: I18n.t(:button_remove))
end
@@ -193,8 +193,7 @@ RSpec.describe "Repository Settings", :js do
click_button(I18n.t(:button_save))
expect(page).to have_css('[name="repository[login]"][value="foobar"]')
expect(page).to have_css(".op-toast",
text: I18n.t("repositories.update_settings_successful"))
expect_flash(message: I18n.t("repositories.update_settings_successful"))
end
end
end
+4 -7
View File
@@ -55,8 +55,7 @@ RSpec.describe "Role creation", :js, :with_cuprite do
click_button "Create"
expect(page)
.to have_css(".errorExplanation", text: "Name has already been taken")
expect_flash(type: :error, message: "Name has already been taken")
fill_in "Name", with: "New role name"
@@ -65,17 +64,15 @@ RSpec.describe "Role creation", :js, :with_cuprite do
click_button "Create"
expect(page)
.to have_css(".errorExplanation",
text: "Permissions need to also include 'View members' as 'Manage members' is selected.")
expect_flash(type: :error,
message: "Permissions need to also include 'View members' as 'Manage members' is selected.")
check "View members"
select existing_role.name, from: "Copy workflow from"
click_button "Create"
expect(page)
.to have_css(".-success", text: "Successful creation.")
expect_and_dismiss_flash(message: "Successful creation.")
expect(page)
.to have_current_path(roles_path)
+2 -5
View File
@@ -52,8 +52,7 @@ RSpec.describe "Types", :js, :with_cuprite do
click_button "Create"
expect(page)
.to have_css(".errorExplanation", text: "Name has already been taken.")
expect_flash(type: :error, message: "Name has already been taken.")
# Values are retained
expect(page)
@@ -123,9 +122,7 @@ RSpec.describe "Types", :js, :with_cuprite do
end
it "renders an error message with links to the archived project in the projects list" do
within ".op-toast.-error" do
expect(page).to have_link(project.name)
end
expect_flash type: :error, message: project.name
end
end
end
@@ -93,7 +93,7 @@ RSpec.describe "form query configuration", :js, :with_cuprite do
it "can save an empty query group" do
form.add_query_group("Empty test", :children)
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
type_bug.reload
query_group = type_bug.attribute_groups.detect { |x| x.is_a?(Type::QueryGroup) }
@@ -105,7 +105,7 @@ RSpec.describe "form query configuration", :js, :with_cuprite do
form.add_query_group("Subtasks", :children)
# Save changed query
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
# Visit wp_table
wp_table.visit!
@@ -131,7 +131,7 @@ RSpec.describe "form query configuration", :js, :with_cuprite do
form.add_query_group("Subtasks", :children)
# Save changed query
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
# Visit new wp page
visit new_project_work_packages_path(project)
@@ -156,7 +156,7 @@ RSpec.describe "form query configuration", :js, :with_cuprite do
filters.save
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash message: "Successful update."
archived.update_attribute(:active, false)
@@ -184,7 +184,7 @@ RSpec.describe "form query configuration", :js, :with_cuprite do
# Save changed query
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
type_bug.reload
query = type_bug.attribute_groups.detect { |x| x.key == "Columns Test" }
@@ -206,7 +206,7 @@ RSpec.describe "form query configuration", :js, :with_cuprite do
# Save changed query
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
type_bug.reload
query = type_bug.attribute_groups.detect { |x| x.key == "Columns Test" }
@@ -253,7 +253,7 @@ RSpec.describe "form query configuration", :js, :with_cuprite do
filters.save
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
# Visit work package with that type
wp_page.visit!
@@ -91,7 +91,7 @@ RSpec.describe "form configuration", :js do
# Save configuration
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
form.expect_empty
@@ -171,7 +171,7 @@ RSpec.describe "form configuration", :js do
# Save configuration
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
# Expect configuration to be correct now
form.expect_no_attribute("assignee", "Cool Stuff")
@@ -269,7 +269,7 @@ RSpec.describe "form configuration", :js do
form.expect_attribute(key: cf_identifier)
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
end
end
@@ -299,7 +299,7 @@ RSpec.describe "form configuration", :js do
form.expect_attribute(key: cf_identifier)
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
end
context "if inactive in project" do
@@ -60,7 +60,7 @@ RSpec.describe "Reset form configuration", :js do
form.expect_attribute(key: cf_identifier)
form.save_changes
expect(page).to have_css(".op-toast.-success", text: "Successful update.", wait: 10)
expect_flash(message: "Successful update.")
SeleniumHubWaiter.wait
form.reset_button.click
+1 -1
View File
@@ -45,7 +45,7 @@ RSpec.describe "create users", :with_cuprite do
shared_examples_for "successful user creation" do |redirect_to_edit_page: true|
it "creates the user" do
expect(page).to have_css(".op-toast", text: "Successful creation.")
expect_flash(message: "Successful creation.")
new_user = User.order(Arel.sql("id DESC")).first
+2 -2
View File
@@ -127,7 +127,7 @@ RSpec.describe "edit users", :js, :with_cuprite do
click_button "Save"
expect(page).to have_css(".op-toast.-success", text: "Successful update.")
expect_flash(message: "Successful update.")
user.reload
@@ -140,7 +140,7 @@ RSpec.describe "edit users", :js, :with_cuprite do
click_on "Send invitation"
expect(page).to have_css(".op-toast.-success", text: "An invitation has been sent to foo@example.com")
expect_flash(message: "An invitation has been sent to foo@example.com")
end
it "can not edit attributes of an admin user" do
+6 -6
View File
@@ -60,7 +60,7 @@ RSpec.describe "random password generation", :js, :with_cuprite do
click_on "Save"
expect(page).to have_css(".op-toast", text: I18n.t(:notice_successful_update))
expect_flash(message: "Successful update.")
expect(password).to be_present
# Logout
@@ -90,7 +90,7 @@ RSpec.describe "random password generation", :js, :with_cuprite do
expect(Sessions::UserSession.for_user(user.id).count).to be >= 1
click_on "Save"
expect(page).to have_css(".op-toast.-info", text: I18n.t(:notice_account_password_updated))
expect_flash(type: :info, message: I18n.t(:notice_account_password_updated))
# The old session is removed
expect(Sessions::UserSession.find_by(session_id: "other")).to be_nil
@@ -126,7 +126,7 @@ RSpec.describe "random password generation", :js, :with_cuprite do
find_by_id("settings_password_min_adhered_rules").set 3
scroll_to_and_click(find(".button", text: "Save"))
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update))
expect_flash(message: "Successful update.")
Setting.clear_cache
@@ -144,19 +144,19 @@ RSpec.describe "random password generation", :js, :with_cuprite do
fill_in "user_password", with: "adminADMIN"
fill_in "user_password_confirmation", with: "adminADMIN"
scroll_to_and_click(find(".button", text: "Save"))
expect(page).to have_css(".errorExplanation", text: "Password Must contain characters of the following classes")
expect_flash(type: :error, message: "Password Must contain characters of the following classes")
# 2 of 3 classes
fill_in "user_password", with: "adminADMIN123"
fill_in "user_password_confirmation", with: "adminADMIN123"
scroll_to_and_click(find(".button", text: "Save"))
expect(page).to have_css(".errorExplanation", text: "Password Must contain characters of the following classes")
expect_flash(type: :error, message: "Password Must contain characters of the following classes")
# All classes
fill_in "user_password", with: "adminADMIN!"
fill_in "user_password_confirmation", with: "adminADMIN!"
scroll_to_and_click(find(".button", text: "Save"))
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update))
expect_flash(message: I18n.t(:notice_successful_update))
end
end
+2 -2
View File
@@ -53,7 +53,7 @@ RSpec.describe "version delete", :js, :with_cuprite do
end
end
expect(page).to have_css(".op-toast.-error", text: I18n.t(:error_can_not_delete_in_use_archived_undisclosed))
expect_flash(type: :error, message: I18n.t(:error_can_not_delete_in_use_archived_undisclosed))
expect(page).to have_no_css("a", text: "Archived child")
user.update!(admin: true)
@@ -67,7 +67,7 @@ RSpec.describe "version delete", :js, :with_cuprite do
end
end
expect(page).to have_css(".op-toast.-error", text: "There are also work packages in archived projects.")
expect_flash(type: :error, message: "There are also work packages in archived projects.")
expect(page).to have_css("a", text: "Archived child")
end
end
@@ -82,6 +82,7 @@ RSpec.describe "wiki pages", :js, with_settings: { journal_aggregation_time_minu
find(".ck-content").base.send_keys(content_first_version)
click_button "Save"
expect_and_dismiss_flash(message: "Successful creation.")
expect(page).to have_css(".title-container", text: "New page")
expect(page).to have_css(".wiki-content", text: content_first_version)
+2 -5
View File
@@ -56,14 +56,11 @@ RSpec.describe "Upload attachment to wiki page", :js do
click_on "Save"
expect(page).to have_text("Successful creation")
expect_and_dismiss_flash(message: "Successful creation")
expect(page).to have_css("#content img", count: 1)
expect(page).to have_content("Image uploaded the first time")
attachments_list.expect_attached("image.png")
# required sleep otherwise clicking on the Edit button doesn't do anything
SeleniumHubWaiter.wait
within ".toolbar-items" do
click_on "Edit"
end
@@ -116,7 +113,7 @@ RSpec.describe "Upload attachment to wiki page", :js do
click_on "Save"
expect(page).to have_text("Successful creation")
expect_and_dismiss_flash(message: "Successful creation")
attachments_list.expect_attached("image.png")
# required sleep otherwise clicking on the Edit button doesn't do anything
+1 -1
View File
@@ -41,6 +41,6 @@ RSpec.describe "Editing a new wiki page", :js do
expect(page).to have_field "page_title", with: "Foobar"
click_on "Save"
expect(page).to have_css(".op-toast.-success", text: "Successful creation.", wait: 10)
expect_flash(message: "Successful creation.", wait: 10)
end
end
@@ -201,35 +201,17 @@ RSpec.describe "Copy work packages through Rails view", :js, :with_cuprite do
it "fails, informing of the reasons" do
click_on "Copy and follow"
expect(page)
.to have_css(
".op-toast.-error",
text: I18n.t("work_packages.bulk.none_could_be_saved", total: 3)
)
expect(page)
.to have_css(
".op-toast.-error",
text: I18n.t("work_packages.bulk.selected_because_descendants", total: 3, selected: 2)
)
expect(page)
.to have_css(
".op-toast.-error",
text: "#{work_package.id}: Type #{I18n.t('activerecord.errors.messages.inclusion')}"
)
expect(page)
.to have_css(
".op-toast.-error",
text: "#{work_package2.id}: Type #{I18n.t('activerecord.errors.messages.inclusion')}"
)
expect(page)
.to have_css(
".op-toast.-error",
text: "#{child.id} (descendant of selected): Type #{I18n.t('activerecord.errors.messages.inclusion')}"
)
expect_flash(type: :error, message: I18n.t("work_packages.bulk.none_could_be_saved", total: 3))
expect_flash(type: :error,
message: I18n.t(
"work_packages.bulk.selected_because_descendants", total: 3, selected: 2
))
expect_flash(type: :error,
message: "#{work_package.id}: Type #{I18n.t('activerecord.errors.messages.inclusion')}")
expect_flash(type: :error,
message: "#{work_package2.id}: Type #{I18n.t('activerecord.errors.messages.inclusion')}")
expect_flash(type: :error, message:
"#{child.id} (descendant of selected): Type #{I18n.t('activerecord.errors.messages.inclusion')}")
end
context "when the limit to move in the frontend is 0",
@@ -316,9 +298,7 @@ RSpec.describe "Copy work packages through Rails view", :js, :with_cuprite do
click_on "Copy and follow"
expect(page)
.to have_css(".op-toast.-success",
text: I18n.t(:notice_successful_create))
expect_flash(message: I18n.t(:notice_successful_create))
wp_page = Pages::FullWorkPackage.new(WorkPackage.last)
@@ -140,10 +140,7 @@ RSpec.describe "Moving a work package through Rails view", :js do
click_on "Move and follow"
wait_for_reload
expect(page)
.to have_css(".op-toast.-error",
text: I18n.t(:"work_packages.bulk.none_could_be_saved",
total: 1))
expect_flash type: :error, message: I18n.t(:"work_packages.bulk.none_could_be_saved", total: 1)
# Should NOT have moved
child_wp.reload
@@ -170,10 +167,7 @@ RSpec.describe "Moving a work package through Rails view", :js do
click_on "Move and follow"
end
expect(page)
.to have_css(".op-toast.-error",
text: I18n.t(:"work_packages.bulk.none_could_be_saved",
total: 1))
expect_flash type: :error, message: I18n.t(:"work_packages.bulk.none_could_be_saved", total: 1)
child_wp.reload
work_package.reload
expect(work_package.project_id).to eq(project.id)
@@ -215,23 +209,16 @@ RSpec.describe "Moving a work package through Rails view", :js do
end
it "displays an error message explaining which work package could not be moved and why" do
expect(page)
.to have_css(".op-toast.-error",
text: I18n.t("work_packages.bulk.could_not_be_saved"),
wait: 10)
expect_flash(type: :error,
message: I18n.t("work_packages.bulk.could_not_be_saved"))
expect_flash(type: :error,
message: "#{work_package2.id}: Project #{I18n.t('activerecord.errors.messages.error_readonly')}")
expect(page)
.to have_css(
".op-toast.-error",
text: "#{work_package2.id}: Project #{I18n.t('activerecord.errors.messages.error_readonly')}"
)
expect(page)
.to have_css(".op-toast.-error",
text: I18n.t("work_packages.bulk.x_out_of_y_could_be_saved",
failing: 1,
total: 2,
success: 1))
expect_flash(type: :error, message:
I18n.t("work_packages.bulk.x_out_of_y_could_be_saved",
failing: 1,
total: 2,
success: 1))
expect(work_package.reload.project_id).to eq(project2.id)
expect(work_package2.reload.project_id).to eq(project.id)
@@ -111,27 +111,17 @@ RSpec.describe "Bulk update work packages through Rails view", :js, :with_cuprit
fill_in "Parent", with: "-1"
click_on "Submit"
expect(page)
.to have_css(
".op-toast.-error",
text: I18n.t("work_packages.bulk.none_could_be_saved", total: 2)
)
expect_flash(type: :error, message: I18n.t("work_packages.bulk.none_could_be_saved", total: 2))
expect_flash(type: :error,
message: "#{work_package.id}: Parent #{I18n.t('activerecord.errors.messages.does_not_exist')}")
expect(page)
.to have_css(
".op-toast.-error",
text: "#{work_package.id}: Parent #{I18n.t('activerecord.errors.messages.does_not_exist')}"
)
expect(page)
.to have_css(
".op-toast.-error",
text: <<~MSG.squish
#{work_package2.id}:
Parent #{I18n.t('activerecord.errors.messages.does_not_exist')}
Status #{I18n.t('activerecord.errors.models.work_package.attributes.status_id.status_transition_invalid')}
MSG
)
expect_flash(type: :error, message:
<<~MSG.squish
#{work_package2.id}:
Parent #{I18n.t('activerecord.errors.messages.does_not_exist')}
Status #{I18n.t('activerecord.errors.models.work_package.attributes.status_id.status_transition_invalid')}
MSG
)
# Should not update the status
work_package2.reload
@@ -153,21 +143,16 @@ RSpec.describe "Bulk update work packages through Rails view", :js, :with_cuprit
fill_in custom_field.name, with: "Custom field text"
click_on "Submit"
expect(page)
.to have_css(
".op-toast.-error",
text: I18n.t("work_packages.bulk.x_out_of_y_could_be_saved", total: 2, failing: 1, success: 1)
)
expect_flash(type: :error, message:
I18n.t("work_packages.bulk.x_out_of_y_could_be_saved", total: 2, failing: 1, success: 1))
expect(page)
.to have_css(
".op-toast.-error",
text: <<~MSG.squish
#{work_package2.id}:
#{custom_field.name} #{I18n.t('activerecord.errors.messages.error_readonly')}
#{I18n.t('activerecord.errors.models.work_package.readonly_status')}
MSG
)
expect_flash(type: :error, message:
<<~MSG.squish
#{work_package2.id}:
#{custom_field.name} #{I18n.t('activerecord.errors.messages.error_readonly')}
#{I18n.t('activerecord.errors.models.work_package.readonly_status')}
MSG
)
# Should update 1 work package custom field only
work_package.reload
@@ -189,7 +174,7 @@ RSpec.describe "Bulk update work packages through Rails view", :js, :with_cuprit
fill_in custom_field.name, with: "Custom field text"
click_on "Submit"
expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update))
expect_and_dismiss_flash(message: I18n.t(:notice_successful_update))
# Should update 2 work package custom fields
work_package.reload
@@ -186,7 +186,7 @@ RSpec.describe "Work display", :js do
visit admin_settings_working_days_and_hours_path
select "Days and hours", from: "Duration format"
click_on "Apply changes"
expect_and_dismiss_toaster(message: "Successful update.")
expect_and_dismiss_flash(message: "Successful update.")
wp_table.visit_query query
@@ -148,11 +148,11 @@ RSpec.describe "Work package navigation", :js, :selenium do
it "loading an unknown work package ID" do
visit "/work_packages/999999999"
page404 = Pages::Page.new
page404.expect_toast type: :error, message: I18n.t(:notice_file_not_found)
expect_flash type: :error, message: I18n.t(:notice_file_not_found)
visit "/projects/#{project.identifier}/work_packages/999999999"
page404.expect_and_dismiss_toaster type: :error, message: I18n.t("api_v3.errors.not_found.work_package")
global_work_packages = Pages::WorkPackagesTable.new
global_work_packages.expect_toast type: :error, message: I18n.t("api_v3.errors.not_found.work_package")
end
# Regression #29994
+5 -2
View File
@@ -50,7 +50,8 @@ RSpec.describe "Wysiwyg autosave spec",
editor.click_and_type_slowly "Initial version"
click_on "Save"
expect(page).to have_css(".op-toast.-success")
expect_and_dismiss_flash(message: "Successful creation.")
within("#content") do
expect(page).to have_text "Initial version"
end
@@ -69,7 +70,7 @@ RSpec.describe "Wysiwyg autosave spec",
# Save wiki page
click_on "Save"
expect(page).to have_css(".op-toast.-success")
expect_flash(message: "Successful update.")
within("#content") do
expect(page).to have_text "This should be saved"
end
@@ -79,6 +80,8 @@ RSpec.describe "Wysiwyg autosave spec",
keys = page.evaluate_script "Object.keys(localStorage)"
expect(keys).to include "op_ckeditor_rev_/api/v3/wiki_pages/#{wiki_page.id}_page[text]"
expect_and_dismiss_flash(message: "Successful update.")
# Edit again
click_on "Edit"

Some files were not shown because too many files have changed in this diff Show More