feat(dossier): fork dossier when editing en construction

This commit is contained in:
Paul Chavard 2023-03-21 18:24:39 +01:00 committed by Colin Darie
parent 025bd5beaf
commit 08a2a2c9aa
No known key found for this signature in database
GPG key ID: 4FB865FDBCA4BCC4
20 changed files with 193 additions and 99 deletions

View file

@ -3,10 +3,10 @@
%span.autosave-explanation-text %span.autosave-explanation-text
- if annotation? - if annotation?
= t('.annotations.explanation') = t('.annotations.explanation')
- elsif dossier.brouillon? - elsif dossier.editing_fork?
= t('.brouillon.explanation')
- else
= t('.en_construction.explanation') = t('.en_construction.explanation')
- else
= t('.brouillon.explanation')
- if !annotation? - if !annotation?
= link_to t('.more_information'), t("links.common.faq.autosave_url"), class: 'autosave-more-infos fr-link fr-link--sm', **external_link_attributes = link_to t('.more_information'), t("links.common.faq.autosave_url"), class: 'autosave-more-infos fr-link fr-link--sm', **external_link_attributes
@ -15,10 +15,10 @@
%span.autosave-label %span.autosave-label
- if annotation? - if annotation?
= t('.annotations.confirmation') = t('.annotations.confirmation')
- elsif dossier.brouillon? - elsif dossier.editing_fork?
= t('.brouillon.confirmation')
- else
= t('.en_construction.confirmation') = t('.en_construction.confirmation')
- else
= t('.brouillon.confirmation')
- if !annotation? - if !annotation?
= link_to t('.more_information'), t("links.common.faq.autosave_url"), class: 'autosave-more-infos fr-link fr-link--sm', **external_link_attributes = link_to t('.more_information'), t("links.common.faq.autosave_url"), class: 'autosave-more-infos fr-link fr-link--sm', **external_link_attributes
@ -27,10 +27,10 @@
%span.autosave-label %span.autosave-label
- if annotation? - if annotation?
= t('.annotations.error') = t('.annotations.error')
- elsif dossier.brouillon? - elsif dossier.editing_fork?
= t('.brouillon.error')
- else
= t('.en_construction.error') = t('.en_construction.error')
- else
= t('.brouillon.error')
%button.button.small.autosave-retry{ type: :button, data: { action: 'autosave-status#onClickRetryButton', autosave_status_target: 'retryButton' } } %button.button.small.autosave-retry{ type: :button, data: { action: 'autosave-status#onClickRetryButton', autosave_status_target: 'retryButton' } }
%span.autosave-retry-label réessayer %span.autosave-retry-label réessayer
%span.autosave-retrying-label enregistrement en cours… %span.autosave-retrying-label enregistrement en cours…

View file

@ -14,7 +14,7 @@ class Dossiers::EditFooterComponent < ApplicationComponent
@annotation.present? @annotation.present?
end end
def button_options def submit_draft_button_options
{ {
class: 'fr-btn fr-btn--sm', class: 'fr-btn fr-btn--sm',
disabled: !owner?, disabled: !owner?,
@ -23,6 +23,14 @@ class Dossiers::EditFooterComponent < ApplicationComponent
} }
end end
def submit_en_construction_button_options
{
class: 'fr-btn fr-btn--sm',
method: :post,
data: { 'disable-with': t('.submitting'), controller: 'autosave-submit' }
}
end
def render? def render?
!@dossier.for_procedure_preview? !@dossier.for_procedure_preview?
end end

View file

@ -1,5 +1,6 @@
--- ---
en: en:
submit: Submit the file submit: Submit the file
submit_changes: Submit file changes
submitting: Submitting… submitting: Submitting…
invite_notice: You are invited to make amendments to this file but only the owner themselves can submit it. invite_notice: You are invited to make amendments to this file but only the owner themselves can submit it.

View file

@ -1,5 +1,6 @@
--- ---
fr: fr:
submit: Déposer le dossier submit: Déposer le dossier
submit_changes: Déposer les modifications
submitting: Envoi en cours… submitting: Envoi en cours…
invite_notice: En tant quinvité, vous pouvez remplir ce formulaire mais le titulaire du dossier doit le déposer lui-même. invite_notice: En tant quinvité, vous pouvez remplir ce formulaire mais le titulaire du dossier doit le déposer lui-même.

View file

@ -3,7 +3,10 @@
= render Dossiers::AutosaveFooterComponent.new(dossier: @dossier, annotation: annotation?) = render Dossiers::AutosaveFooterComponent.new(dossier: @dossier, annotation: annotation?)
- if !annotation? && @dossier.can_transition_to_en_construction? - if !annotation? && @dossier.can_transition_to_en_construction?
= button_to t('.submit'), brouillon_dossier_url(@dossier), button_options = button_to t('.submit'), brouillon_dossier_url(@dossier), submit_draft_button_options
- elsif @dossier.forked_with_changes?
= button_to t('.submit_changes'), modifier_dossier_url(@dossier.editing_fork_origin), submit_en_construction_button_options
- if @dossier.brouillon? && !owner? - if @dossier.brouillon? && !owner?
.send-notice.invite-cannot-submit .send-notice.invite-cannot-submit

View file

@ -3,7 +3,7 @@
= @form.label @champ.main_value_name, id: @champ.labelledby_id, for: @champ.input_id do = @form.label @champ.main_value_name, id: @champ.labelledby_id, for: @champ.input_id do
- render EditableChamp::ChampLabelContentComponent.new champ: @champ, seen_at: @seen_at - render EditableChamp::ChampLabelContentComponent.new champ: @champ, seen_at: @seen_at
- else - else
.form-label.mb-4 .form-label.mb-4{ id: @champ.labelledby_id }
= render EditableChamp::ChampLabelContentComponent.new champ: @champ, seen_at: @seen_at = render EditableChamp::ChampLabelContentComponent.new champ: @champ, seen_at: @seen_at
- if @champ.description.present? - if @champ.description.present?

View file

@ -2,7 +2,10 @@
- if @champ.mandatory? - if @champ.mandatory?
%span.mandatory * %span.mandatory *
- if @champ.updated_at.present? && @seen_at.present? - if @champ.forked_with_changes?
%span.updated-at.highlighted
= @champ.updated_at > 1.minutes.ago ? "modifié à linstant" : "modification à déposer"
- elsif @champ.updated_at.present? && @seen_at.present?
%span.updated-at{ class: highlight_if_unseen_class } %span.updated-at{ class: highlight_if_unseen_class }
= "modifié le #{try_format_datetime(@champ.updated_at)}" = "modifié le #{try_format_datetime(@champ.updated_at)}"

View file

@ -6,7 +6,7 @@ module TurboChampsConcern
def champs_to_turbo_update(params, champs) def champs_to_turbo_update(params, champs)
champ_ids = params.keys.map(&:to_i) champ_ids = params.keys.map(&:to_i)
to_update = champs.filter { _1.id.in?(champ_ids) && _1.refresh_after_update? } to_update = champs.filter { _1.id.in?(champ_ids) && (_1.refresh_after_update? || _1.forked_with_changes?) }
to_show, to_hide = champs.filter(&:conditional?) to_show, to_hide = champs.filter(&:conditional?)
.partition(&:visible?) .partition(&:visible?)
.map { champs_to_one_selector(_1 - to_update) } .map { champs_to_one_selector(_1 - to_update) }

View file

@ -6,12 +6,12 @@ module Users
layout 'procedure_context', only: [:identite, :update_identite, :siret, :update_siret] layout 'procedure_context', only: [:identite, :update_identite, :siret, :update_siret]
ACTIONS_ALLOWED_TO_ANY_USER = [:index, :recherche, :new, :transferer_all] ACTIONS_ALLOWED_TO_ANY_USER = [:index, :recherche, :new, :transferer_all]
ACTIONS_ALLOWED_TO_OWNER_OR_INVITE = [:show, :destroy, :demande, :messagerie, :brouillon, :update_brouillon, :submit_brouillon, :modifier, :update, :create_commentaire, :papertrail, :restore] ACTIONS_ALLOWED_TO_OWNER_OR_INVITE = [:show, :destroy, :demande, :messagerie, :brouillon, :submit_brouillon, :submit_en_construction, :modifier, :update, :create_commentaire, :papertrail, :restore]
before_action :ensure_ownership!, except: ACTIONS_ALLOWED_TO_ANY_USER + ACTIONS_ALLOWED_TO_OWNER_OR_INVITE before_action :ensure_ownership!, except: ACTIONS_ALLOWED_TO_ANY_USER + ACTIONS_ALLOWED_TO_OWNER_OR_INVITE
before_action :ensure_ownership_or_invitation!, only: ACTIONS_ALLOWED_TO_OWNER_OR_INVITE before_action :ensure_ownership_or_invitation!, only: ACTIONS_ALLOWED_TO_OWNER_OR_INVITE
before_action :ensure_dossier_can_be_updated, only: [:update_identite, :update_siret, :brouillon, :update_brouillon, :submit_brouillon, :modifier, :update] before_action :ensure_dossier_can_be_updated, only: [:update_identite, :update_siret, :brouillon, :submit_brouillon, :submit_en_construction, :modifier, :update]
before_action :ensure_dossier_can_be_filled, only: [:brouillon, :modifier, :update_brouillon, :submit_brouillon, :update] before_action :ensure_dossier_can_be_filled, only: [:brouillon, :modifier, :submit_brouillon, :submit_en_construction, :update]
before_action :ensure_dossier_can_be_viewed, only: [:show] before_action :ensure_dossier_can_be_viewed, only: [:show]
before_action :forbid_invite_submission!, only: [:submit_brouillon] before_action :forbid_invite_submission!, only: [:submit_brouillon]
before_action :forbid_closed_submission!, only: [:submit_brouillon] before_action :forbid_closed_submission!, only: [:submit_brouillon]
@ -202,21 +202,30 @@ module Users
@dossier = dossier_with_champs @dossier = dossier_with_champs
end end
def update_brouillon def submit_en_construction
@dossier = dossier_with_champs @dossier = dossier.find_editing_fork(dossier.user)
update_dossier_and_compute_errors @dossier = dossier_with_champs(pj_template: false)
errors = submit_dossier_and_compute_errors
respond_to do |format| if errors.blank?
format.html { render :brouillon } editing_fork_origin = @dossier.editing_fork_origin
format.turbo_stream do editing_fork_origin.merge_fork(@dossier)
@to_show, @to_hide, @to_update = champs_to_turbo_update(champs_public_params.fetch(:champs_public_all_attributes), dossier.champs_public_all) redirect_to dossier_path(editing_fork_origin)
else
flash.now.alert = errors
render(:update, layout: false) respond_to do |format|
format.html { render :modifier }
format.turbo_stream do
@to_show, @to_hide, @to_update = champs_to_turbo_update(champs_public_params.fetch(:champs_public_all_attributes), dossier.champs_public_all)
render :update, layout: false
end
end end
end end
end end
def update def update
@dossier = dossier.en_construction? ? dossier.find_editing_fork(dossier.user) : dossier
@dossier = dossier_with_champs(pj_template: false) @dossier = dossier_with_champs(pj_template: false)
errors = update_dossier_and_compute_errors errors = update_dossier_and_compute_errors
@ -225,9 +234,9 @@ module Users
end end
respond_to do |format| respond_to do |format|
format.html { render :modifier }
format.turbo_stream do format.turbo_stream do
@to_show, @to_hide, @to_update = champs_to_turbo_update(champs_public_params.fetch(:champs_public_all_attributes), dossier.champs_public_all) @to_show, @to_hide, @to_update = champs_to_turbo_update(champs_public_params.fetch(:champs_public_all_attributes), dossier.champs_public_all)
render :update, layout: false
end end
end end
end end
@ -425,8 +434,8 @@ module Users
end end
def dossier_scope def dossier_scope
if action_name == 'update_brouillon' if action_name == 'update'
Dossier.visible_by_user.or(Dossier.for_procedure_preview) Dossier.visible_by_user.or(Dossier.for_procedure_preview).or(Dossier.for_editing_fork)
elsif action_name == 'restore' elsif action_name == 'restore'
Dossier.hidden_by_user Dossier.hidden_by_user
else else
@ -488,10 +497,6 @@ module Users
RoutingEngine.compute(@dossier) RoutingEngine.compute(@dossier)
end end
if dossier.en_construction?
errors += format_errors(errors: @dossier.check_mandatory_and_visible_champs)
end
errors errors
end end
@ -528,9 +533,12 @@ module Users
def append_anchor_link(str_error, model) def append_anchor_link(str_error, model)
return str_error.full_message if !model.is_a?(Champ) return str_error.full_message if !model.is_a?(Champ)
route_helper = @dossier.editing_fork? ? :modifier_dossier_path : :brouillon_dossier_path
[ [
"Le champ « #{model.libelle.truncate(200)} » #{str_error}", "Le champ « #{model.libelle.truncate(200)} » #{str_error}",
helpers.link_to(t('views.users.dossiers.fix_champ'), brouillon_dossier_path(anchor: model.input_id)) helpers.link_to(t('views.users.dossiers.fix_champ'), public_send(route_helper, anchor: model.input_id))
].join(", ") ].join(", ")
rescue # case of invalid type de champ on champ rescue # case of invalid type de champ on champ
str_error str_error

View file

@ -244,6 +244,10 @@ class Champ < ApplicationRecord
input_id input_id
end end
def forked_with_changes?
public? && dossier.champ_forked_with_changes?(self)
end
private private
def html_id def html_id

View file

@ -1,17 +1,13 @@
- dossier_for_editing = dossier.en_construction? ? dossier.owner_editing_fork : dossier
- if dossier.france_connect_information.present? - if dossier.france_connect_information.present?
- content_for(:notice_info) do - content_for(:notice_info) do
= render partial: "shared/dossiers/france_connect_informations_notice", locals: { user_information: dossier.france_connect_information } = render partial: "shared/dossiers/france_connect_informations_notice", locals: { user_information: dossier.france_connect_information }
.dossier-edit.container.counter-start-header-section .dossier-edit.container.counter-start-header-section
= render partial: "shared/dossiers/submit_is_over", locals: { dossier: dossier } = render partial: "shared/dossiers/submit_is_over", locals: { dossier: dossier }
- if dossier.brouillon?
- form_options = { url: brouillon_dossier_url(dossier), method: :patch }
- else
- form_options = { url: modifier_dossier_url(dossier), method: :patch }
= render NestedForms::FormOwnerComponent.new = render NestedForms::FormOwnerComponent.new
= form_for dossier, form_options.merge({ html: { id: 'dossier-edit-form', class: 'form', multipart: true, novalidate: 'novalidate' } }) do |f| = form_for dossier_for_editing, url: brouillon_dossier_url(dossier), method: :patch, html: { id: 'dossier-edit-form', class: 'form', multipart: true, novalidate: 'novalidate' } do |f|
%header.mb-6 %header.mb-6
.fr-highlight .fr-highlight
%p.fr-text--sm %p.fr-text--sm
@ -42,5 +38,7 @@
= f.select :groupe_instructeur_id, = f.select :groupe_instructeur_id,
dossier.procedure.groupe_instructeurs.active.map { |gi| [gi.label, gi.id] }, dossier.procedure.groupe_instructeurs.active.map { |gi| [gi.label, gi.id] },
{ include_blank: dossier.brouillon? } { include_blank: dossier.brouillon? }
= render EditableChamp::SectionComponent.new(champs: dossier.champs_public)
= render Dossiers::EditFooterComponent.new(dossier: dossier, annotation: false)
= render EditableChamp::SectionComponent.new(champs: dossier_for_editing.champs_public)
= render Dossiers::EditFooterComponent.new(dossier: dossier_for_editing, annotation: false)

View file

@ -4,8 +4,14 @@
= turbo_stream.hide_all(@to_hide) = turbo_stream.hide_all(@to_hide)
- @to_update.each do |champ| - @to_update.each do |champ|
= fields_for champ.input_name, champ do |form| = fields_for champ.input_name, champ do |form|
= turbo_stream.replace champ.input_group_id do - if champ.refresh_after_update?
= render EditableChamp::EditableChampComponent.new champ:, form: = turbo_stream.replace champ.input_group_id do
= render EditableChamp::EditableChampComponent.new champ:, form:
- else
= turbo_stream.update champ.labelledby_id do
= render EditableChamp::ChampLabelContentComponent.new champ:
= turbo_stream.remove_all(".editable-champ .spinner-removable"); = turbo_stream.remove_all(".editable-champ .spinner-removable");
= turbo_stream.hide_all(".editable-champ .spinner"); = turbo_stream.hide_all(".editable-champ .spinner");
= turbo_stream.replace_all '.dossier-edit-sticky-footer' do
= render Dossiers::EditFooterComponent.new(dossier: @dossier, annotation: false)

View file

@ -315,10 +315,10 @@ Rails.application.routes.draw do
post 'siret', to: 'dossiers#update_siret' post 'siret', to: 'dossiers#update_siret'
get 'etablissement' get 'etablissement'
get 'brouillon' get 'brouillon'
patch 'brouillon', to: 'dossiers#update_brouillon' patch 'brouillon', to: 'dossiers#update'
post 'brouillon', to: 'dossiers#submit_brouillon' post 'brouillon', to: 'dossiers#submit_brouillon'
get 'modifier', to: 'dossiers#modifier' get 'modifier', to: 'dossiers#modifier'
patch 'modifier', to: 'dossiers#update' post 'modifier', to: 'dossiers#submit_en_construction'
get 'merci' get 'merci'
get 'demande' get 'demande'
get 'messagerie' get 'messagerie'

View file

@ -445,11 +445,76 @@ describe Users::DossiersController, type: :controller do
end end
end end
describe '#update_brouillon' do describe '#submit_en_construction' do
before { sign_in(user) } before { sign_in(user) }
let(:procedure) { create(:procedure, :published, :with_type_de_champ, :with_piece_justificative) } let!(:dossier) { create(:dossier, :en_construction, user: user) }
let!(:dossier) { create(:dossier, user: user, procedure: procedure) } let(:first_champ) { dossier.owner_editing_fork.champs_public.first }
let(:anchor_to_first_champ) { controller.helpers.link_to I18n.t('views.users.dossiers.fix_champ'), modifier_dossier_path(anchor: first_champ.input_id) }
let(:value) { 'beautiful value' }
let(:now) { Time.zone.parse('01/01/2100') }
let(:payload) { { id: dossier.id } }
before { dossier.owner_editing_fork }
subject do
Timecop.freeze(now) do
post :submit_en_construction, params: payload
end
end
context 'when the dossier cannot be updated by the user' do
let!(:dossier) { create(:dossier, :en_instruction, user: user) }
it 'redirects to the dossiers list' do
subject
expect(response).to redirect_to(dossier_path(dossier))
expect(flash.alert).to eq('Votre dossier ne peut plus être modifié')
end
end
context 'when the update fails' do
before do
expect_any_instance_of(Dossier).to receive(:valid?).and_return(false)
expect_any_instance_of(Dossier).to receive(:errors).and_return(
[double(class: ActiveModel::Error, full_message: 'nop', base: first_champ)]
)
subject
end
it { expect(response).to render_template(:modifier) }
it { expect(flash.alert).to eq(["Le champ « #{first_champ.libelle} » nop, #{anchor_to_first_champ}"]) }
end
context 'when a mandatory champ is missing' do
let(:value) { nil }
before do
first_champ.type_de_champ.update(mandatory: true, libelle: 'l')
subject
end
it { expect(response).to render_template(:modifier) }
it { expect(flash.alert).to eq(["Le champ « l » doit être rempli, #{anchor_to_first_champ}"]) }
end
context 'when dossier has no champ' do
let(:submit_payload) { { id: dossier.id } }
it 'does not raise any errors' do
subject
expect(response).to redirect_to(dossier_path(dossier))
end
end
end
describe '#update brouillon' do
before { sign_in(user) }
let(:procedure) { create(:procedure, :published, types_de_champ_public: [{}, { type: :piece_justificative }]) }
let(:dossier) { create(:dossier, user:, procedure:) }
let(:first_champ) { dossier.champs_public.first } let(:first_champ) { dossier.champs_public.first }
let(:piece_justificative_champ) { dossier.champs_public.last } let(:piece_justificative_champ) { dossier.champs_public.last }
let(:value) { 'beautiful value' } let(:value) { 'beautiful value' }
@ -461,16 +526,16 @@ describe Users::DossiersController, type: :controller do
id: dossier.id, id: dossier.id,
dossier: { dossier: {
groupe_instructeur_id: dossier.groupe_instructeur_id, groupe_instructeur_id: dossier.groupe_instructeur_id,
champs_public_attributes: [ champs_public_attributes: {
{ first_champ.id => {
id: first_champ.id, id: first_champ.id,
value: value value: value
}, },
{ piece_justificative_champ.id => {
id: piece_justificative_champ.id, id: piece_justificative_champ.id,
piece_justificative_file: file piece_justificative_file: file
} }
] }
} }
} }
end end
@ -478,12 +543,12 @@ describe Users::DossiersController, type: :controller do
subject do subject do
Timecop.freeze(now) do Timecop.freeze(now) do
patch :update_brouillon, params: payload patch :update, params: payload, format: :turbo_stream
end end
end end
context 'when the dossier cannot be updated by the user' do context 'when the dossier cannot be updated by the user' do
let!(:dossier) { create(:dossier, :en_instruction, user: user) } let(:dossier) { create(:dossier, :en_instruction, user:, procedure:) }
it 'redirects to the dossiers list' do it 'redirects to the dossiers list' do
subject subject
@ -507,7 +572,7 @@ describe Users::DossiersController, type: :controller do
{ {
id: dossier.id, id: dossier.id,
dossier: { dossier: {
champs_public_attributes: [{ value: '' }] champs_public_attributes: { first_champ.id => { id: first_champ.id } }
} }
} }
end end
@ -520,7 +585,7 @@ describe Users::DossiersController, type: :controller do
end end
context 'when the user has an invitation but is not the owner' do context 'when the user has an invitation but is not the owner' do
let(:dossier) { create(:dossier) } let(:dossier) { create(:dossier, procedure: procedure) }
let!(:invite) { create(:invite, dossier: dossier, user: user) } let!(:invite) { create(:invite, dossier: dossier, user: user) }
before { subject } before { subject }
@ -530,11 +595,11 @@ describe Users::DossiersController, type: :controller do
end end
end end
describe '#update' do describe '#update en_construction' do
before { sign_in(user) } before { sign_in(user) }
let(:procedure) { create(:procedure, :published, :with_type_de_champ, :with_piece_justificative) } let(:procedure) { create(:procedure, :published, types_de_champ_public: [{}, { type: :piece_justificative }]) }
let!(:dossier) { create(:dossier, :en_construction, user: user, procedure: procedure) } let!(:dossier) { create(:dossier, :en_construction, user:, procedure:) }
let(:first_champ) { dossier.champs_public.first } let(:first_champ) { dossier.champs_public.first }
let(:anchor_to_first_champ) { controller.helpers.link_to I18n.t('views.users.dossiers.fix_champ'), brouillon_dossier_path(anchor: first_champ.input_id) } let(:anchor_to_first_champ) { controller.helpers.link_to I18n.t('views.users.dossiers.fix_champ'), brouillon_dossier_path(anchor: first_champ.input_id) }
let(:piece_justificative_champ) { dossier.champs_public.last } let(:piece_justificative_champ) { dossier.champs_public.last }
@ -547,16 +612,16 @@ describe Users::DossiersController, type: :controller do
id: dossier.id, id: dossier.id,
dossier: { dossier: {
groupe_instructeur_id: dossier.groupe_instructeur_id, groupe_instructeur_id: dossier.groupe_instructeur_id,
champs_public_attributes: [ champs_public_attributes: {
{ first_champ.id => {
id: first_champ.id, id: first_champ.id,
value: value value: value
}, },
{ piece_justificative_champ.id => {
id: piece_justificative_champ.id, id: piece_justificative_champ.id,
piece_justificative_file: file piece_justificative_file: file
} }
] }
} }
} }
end end
@ -564,12 +629,12 @@ describe Users::DossiersController, type: :controller do
subject do subject do
Timecop.freeze(now) do Timecop.freeze(now) do
patch :update, params: payload patch :update, params: payload, format: :turbo_stream
end end
end end
context 'when the dossier cannot be updated by the user' do context 'when the dossier cannot be updated by the user' do
let!(:dossier) { create(:dossier, :en_instruction, user: user) } let!(:dossier) { create(:dossier, :en_instruction, user:, procedure:) }
it 'redirects to the dossiers list' do it 'redirects to the dossiers list' do
subject subject
@ -612,12 +677,12 @@ describe Users::DossiersController, type: :controller do
{ {
id: dossier.id, id: dossier.id,
dossier: { dossier: {
champs_public_attributes: [ champs_public_attributes: {
{ piece_justificative_champ.id => {
id: piece_justificative_champ.id, id: piece_justificative_champ.id,
piece_justificative_file: file piece_justificative_file: file
} }
] }
} }
} }
end end
@ -640,7 +705,7 @@ describe Users::DossiersController, type: :controller do
subject subject
end end
it { expect(response).to render_template(:modifier) } it { expect(response).to render_template(:update) }
it { expect(flash.alert).to eq(["Le champ « #{first_champ.libelle} » nop, #{anchor_to_first_champ}"]) } it { expect(flash.alert).to eq(["Le champ « #{first_champ.libelle} » nop, #{anchor_to_first_champ}"]) }
it 'does not update the dossier timestamps' do it 'does not update the dossier timestamps' do
@ -656,18 +721,6 @@ describe Users::DossiersController, type: :controller do
end end
end end
context 'when a mandatory champ is missing' do
let(:value) { nil }
before do
first_champ.type_de_champ.update(mandatory: true, libelle: 'l')
subject
end
it { expect(response).to render_template(:modifier) }
it { expect(flash.alert).to eq(["Le champ « l » doit être rempli, #{anchor_to_first_champ}"]) }
end
context 'when a champ validation fails' do context 'when a champ validation fails' do
let(:value) { 'abc' } let(:value) { 'abc' }
@ -682,8 +735,8 @@ describe Users::DossiersController, type: :controller do
end end
context 'when the user has an invitation but is not the owner' do context 'when the user has an invitation but is not the owner' do
let(:dossier) { create(:dossier, :en_construction) } let(:dossier) { create(:dossier, :en_construction, procedure:) }
let!(:invite) { create(:invite, dossier: dossier, user: user) } let!(:invite) { create(:invite, dossier:, user:) }
before { subject } before { subject }
@ -692,9 +745,9 @@ describe Users::DossiersController, type: :controller do
end end
context 'when the dossier is followed by an instructeur' do context 'when the dossier is followed by an instructeur' do
let(:dossier) { create(:dossier) } let(:dossier) { create(:dossier, procedure:) }
let(:instructeur) { create(:instructeur) } let(:instructeur) { create(:instructeur) }
let!(:invite) { create(:invite, dossier: dossier, user: user) } let!(:invite) { create(:invite, dossier:, user:) }
before do before do
instructeur.follow(dossier) instructeur.follow(dossier)
@ -708,8 +761,8 @@ describe Users::DossiersController, type: :controller do
end end
context 'when the champ is a phone number' do context 'when the champ is a phone number' do
let(:procedure) { create(:procedure, :published, :with_phone) } let(:procedure) { create(:procedure, :published, types_de_champ_public: [{ type: :phone }]) }
let!(:dossier) { create(:dossier, :en_construction, user: user, procedure: procedure) } let!(:dossier) { create(:dossier, :en_construction, user:, procedure:) }
let(:first_champ) { dossier.champs_public.first } let(:first_champ) { dossier.champs_public.first }
let(:now) { Time.zone.parse('01/01/2100') } let(:now) { Time.zone.parse('01/01/2100') }
@ -717,12 +770,12 @@ describe Users::DossiersController, type: :controller do
{ {
id: dossier.id, id: dossier.id,
dossier: { dossier: {
champs_public_attributes: [ champs_public_attributes: {
{ first_champ.id => {
id: first_champ.id, id: first_champ.id,
value: value value: value
} }
] }
} }
} }
end end

View file

@ -119,6 +119,8 @@ describe 'The routing', js: true do
fill_in litteraire_user.dossiers.first.champs_public.first.libelle, with: 'some value' fill_in litteraire_user.dossiers.first.champs_public.first.libelle, with: 'some value'
wait_for_autosave(false) wait_for_autosave(false)
click_on 'Déposer les modifications'
log_out log_out
# the litteraires instructeurs should have a notification # the litteraires instructeurs should have a notification
@ -217,6 +219,8 @@ describe 'The routing', js: true do
expect(page).to have_text(new_group) expect(page).to have_text(new_group)
click_on 'Déposer les modifications'
log_out log_out
end end

View file

@ -146,6 +146,8 @@ describe 'The routing with rules', js: true do
fill_in litteraire_user.dossiers.first.champs_public.first.libelle, with: 'some value' fill_in litteraire_user.dossiers.first.champs_public.first.libelle, with: 'some value'
wait_for_autosave(false) wait_for_autosave(false)
click_on 'Déposer les modifications'
log_out log_out
# the litteraires instructeurs should have a notification # the litteraires instructeurs should have a notification
@ -245,6 +247,8 @@ describe 'The routing with rules', js: true do
expect(page).to have_text(new_group) expect(page).to have_text(new_group)
click_on 'Déposer les modifications'
log_out log_out
end end

View file

@ -483,13 +483,13 @@ describe 'The user' do
fill_individual fill_individual
# Test autosave failure # Test autosave failure
allow_any_instance_of(Users::DossiersController).to receive(:update_brouillon).and_raise("Server is busy") allow_any_instance_of(Users::DossiersController).to receive(:update).and_raise("Server is busy")
fill_in('texte obligatoire', with: 'a valid user input') fill_in('texte obligatoire', with: 'a valid user input')
blur blur
expect(page).to have_css('span', text: 'Impossible denregistrer le brouillon', visible: true) expect(page).to have_css('span', text: 'Impossible denregistrer le brouillon', visible: true)
# Test that retrying after a failure works # Test that retrying after a failure works
allow_any_instance_of(Users::DossiersController).to receive(:update_brouillon).and_call_original allow_any_instance_of(Users::DossiersController).to receive(:update).and_call_original
click_on 'réessayer' click_on 'réessayer'
wait_for_autosave wait_for_autosave

View file

@ -12,6 +12,7 @@ RSpec.shared_examples 'the user can edit the submitted demande' do
fill_in('Texte obligatoire', with: 'Nouveau texte') fill_in('Texte obligatoire', with: 'Nouveau texte')
wait_for_autosave(false) wait_for_autosave(false)
click_on 'Déposer les modifications'
click_on 'Demande' click_on 'Demande'
expect(page).to have_current_path(demande_dossier_path(dossier)) expect(page).to have_current_path(demande_dossier_path(dossier))

View file

@ -8,7 +8,7 @@ describe "Dossier en_construction" do
} }
let(:champ) { let(:champ) {
dossier.champs_public.find { _1.type_de_champ_id == tdc.id } dossier.find_editing_fork(dossier.user).champs_public.find { _1.type_de_champ_id == tdc.id }
} }
scenario 'delete a non mandatory piece justificative', js: true do scenario 'delete a non mandatory piece justificative', js: true do
@ -28,7 +28,7 @@ describe "Dossier en_construction" do
scenario 'remplace a mandatory piece justificative', js: true do scenario 'remplace a mandatory piece justificative', js: true do
visit_dossier(dossier) visit_dossier(dossier)
click_on "Remplacer le fichier toto.txt" click_on "Supprimer le fichier toto.txt"
input_selector = "#attachment-multiple-empty-#{champ.id}" input_selector = "#attachment-multiple-empty-#{champ.id}"
expect(page).to have_selector(input_selector) expect(page).to have_selector(input_selector)
@ -51,9 +51,9 @@ describe "Dossier en_construction" do
scenario 'remplace a mandatory titre identite', js: true do scenario 'remplace a mandatory titre identite', js: true do
visit_dossier(dossier) visit_dossier(dossier)
click_on "Remplacer le fichier toto.png" click_on "Supprimer le fichier toto.png"
input_selector = ".attachment-input-#{champ.piece_justificative_file.attachments.first.id}" input_selector = "##{champ.input_id}"
expect(page).to have_selector(input_selector) expect(page).to have_selector(input_selector)
find(input_selector).attach_file(Rails.root.join('spec/fixtures/files/file.pdf')) find(input_selector).attach_file(Rails.root.join('spec/fixtures/files/file.pdf'))

View file

@ -115,8 +115,8 @@ describe 'shared/dossiers/edit', type: :view do
let(:dossier) { create(:dossier, :en_construction) } let(:dossier) { create(:dossier, :en_construction) }
before { dossier.champs_public << champ } before { dossier.champs_public << champ }
it 'cannot delete a piece justificative' do it 'can delete a piece justificative' do
expect(subject).not_to have_selector("[title='Supprimer le fichier #{champ.piece_justificative_file.attachments[0].filename}']") expect(subject).to have_selector("[title='Supprimer le fichier #{champ.piece_justificative_file.attachments[0].filename}']")
end end
end end