test(attachments): more components tests & improvements
This commit is contained in:
parent
fefc326e6b
commit
6ac0114992
8 changed files with 152 additions and 19 deletions
|
@ -6,8 +6,10 @@
|
||||||
= link_to('Supprimer', destroy_attachment_path, **remove_button_options, class: "fr-btn fr-btn--tertiary fr-btn--sm fr-icon-delete-line", title: "Supprimer le fichier #{attachment.filename}")
|
= link_to('Supprimer', destroy_attachment_path, **remove_button_options, class: "fr-btn fr-btn--tertiary fr-btn--sm fr-icon-delete-line", title: "Supprimer le fichier #{attachment.filename}")
|
||||||
|
|
||||||
.fr-py-1v
|
.fr-py-1v
|
||||||
= link_to_if(downloadable?, attachment.filename.to_s, attachment.url, class: "attachment-filename", download: "") do
|
- if downloadable?
|
||||||
%span.attachment-filename= attachment.filename.to_s
|
= render Dsfr::DownloadComponent.new(attachment:)
|
||||||
|
- else
|
||||||
|
%span.attachment-filename.fr-mr-1w-= attachment.filename.to_s
|
||||||
|
|
||||||
= render Attachment::ProgressComponent.new(attachment: attachment)
|
= render Attachment::ProgressComponent.new(attachment: attachment)
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
# Display a widget for uploading, editing and deleting a file attachment
|
# Display a widget for uploading, editing and deleting a file attachment
|
||||||
class Attachment::MultipleComponent < ApplicationComponent
|
class Attachment::MultipleComponent < ApplicationComponent
|
||||||
|
DEFAULT_MAX_ATTACHMENTS = 10
|
||||||
|
|
||||||
renders_one :template
|
renders_one :template
|
||||||
|
|
||||||
attr_reader :form
|
attr_reader :champ
|
||||||
attr_reader :attached_file
|
attr_reader :attached_file
|
||||||
|
attr_reader :user_can_download
|
||||||
attr_reader :user_can_destroy
|
attr_reader :user_can_destroy
|
||||||
attr_reader :max
|
attr_reader :max
|
||||||
|
|
||||||
delegate :count, :empty?, to: :attachments, prefix: true
|
delegate :count, :empty?, to: :attachments, prefix: true
|
||||||
|
|
||||||
def initialize(form:, attached_file:, user_can_destroy: false, max: nil)
|
def initialize(champ:, attached_file:, user_can_download: false, user_can_destroy: true, max: nil)
|
||||||
@form = form
|
@champ = champ
|
||||||
@attached_file = attached_file
|
@attached_file = attached_file
|
||||||
|
@user_can_download = user_can_download
|
||||||
@user_can_destroy = user_can_destroy
|
@user_can_destroy = user_can_destroy
|
||||||
@max = max || 10
|
@max = max || DEFAULT_MAX_ATTACHMENTS
|
||||||
|
|
||||||
@attachments = attached_file.attachments || []
|
@attachments = attached_file.attachments || []
|
||||||
end
|
end
|
||||||
|
|
||||||
def champ
|
|
||||||
form.object
|
|
||||||
end
|
|
||||||
|
|
||||||
def each_attachment(&block)
|
def each_attachment(&block)
|
||||||
@attachments.each_with_index(&block)
|
@attachments.each_with_index(&block)
|
||||||
end
|
end
|
||||||
|
@ -31,7 +31,7 @@ class Attachment::MultipleComponent < ApplicationComponent
|
||||||
end
|
end
|
||||||
|
|
||||||
def empty_component_id
|
def empty_component_id
|
||||||
"attachment-multiple-empty-#{form.object.id}"
|
"attachment-multiple-empty-#{champ.id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def in_progress?
|
def in_progress?
|
||||||
|
@ -54,7 +54,7 @@ class Attachment::MultipleComponent < ApplicationComponent
|
||||||
end
|
end
|
||||||
|
|
||||||
def auto_attach_url
|
def auto_attach_url
|
||||||
helpers.auto_attach_url(form.object)
|
helpers.auto_attach_url(champ)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
- each_attachment do |attachment, index|
|
- each_attachment do |attachment, index|
|
||||||
%div{ id: dom_id(attachment) }
|
%div{ id: dom_id(attachment) }
|
||||||
= render Attachment::EditComponent.new(champ:, attached_file:, attachment:, index:, as_multiple: true, user_can_destroy:)
|
= render Attachment::EditComponent.new(champ:, attached_file:, attachment:, index:, as_multiple: true, user_can_destroy:, user_can_download:)
|
||||||
|
|
||||||
%div{ id: empty_component_id, class: class_names("hidden": !can_attach_next?) }
|
%div{ id: empty_component_id, class: class_names("hidden": !can_attach_next?) }
|
||||||
= render Attachment::EditComponent.new(champ:, attached_file:, attachment: nil, index: attachments_count, user_can_destroy:)
|
= render Attachment::EditComponent.new(champ:, attached_file:, attachment: nil, index: attachments_count, user_can_destroy:)
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
%p.fr-badge.fr-badge--info.fr-badge--sm.fr-badge--no-icon.fr-ml-1w
|
%p.fr-badge.fr-badge--info.fr-badge--sm.fr-badge--no-icon
|
||||||
= progress_label
|
= progress_label
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
(ce fichier n’a pas été analysé par notre antivirus, téléchargez-le avec précaution)
|
(ce fichier n’a pas été analysé par notre antivirus, téléchargez-le avec précaution)
|
||||||
|
|
||||||
- else
|
- else
|
||||||
.attachment-filename.fr-mb-1w= attachment.filename.to_s
|
.attachment-filename.fr-mb-1w.fr-mr-1w= attachment.filename.to_s
|
||||||
|
|
||||||
= render Attachment::ProgressComponent.new(attachment: attachment)
|
= render Attachment::ProgressComponent.new(attachment: attachment)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
- user_can_destroy = !@champ.mandatory? || @champ.dossier.brouillon?
|
- user_can_destroy = !@champ.mandatory? || @champ.dossier.brouillon?
|
||||||
- max = [true, nil].include?(@champ.procedure&.piece_justificative_multiple?) ? 10 : 1
|
- user_can_download = !@champ.dossier.brouillon?
|
||||||
= render Attachment::MultipleComponent.new(form: @form, attached_file: @champ.piece_justificative_file, user_can_destroy:, max:) do |c|
|
- max = [true, nil].include?(@champ.procedure&.piece_justificative_multiple?) ? Attachment::MultipleComponent::DEFAULT_MAX_ATTACHMENTS : 1
|
||||||
|
= render Attachment::MultipleComponent.new(champ: @champ, attached_file: @champ.piece_justificative_file, user_can_destroy:, user_can_download:, max:) do |c|
|
||||||
- if @champ.type_de_champ.piece_justificative_template&.attached?
|
- if @champ.type_de_champ.piece_justificative_template&.attached?
|
||||||
- c.with_template do
|
- c.with_template do
|
||||||
= render Dsfr::DownloadComponent.new(attachment: @champ.type_de_champ.piece_justificative_template, name: "Modèle à télécharger") do |c|
|
= render Dsfr::DownloadComponent.new(attachment: @champ.type_de_champ.piece_justificative_template, name: "Modèle à télécharger") do |c|
|
||||||
|
|
|
@ -117,6 +117,28 @@ RSpec.describe Attachment::EditComponent, type: :component do
|
||||||
expect(subject).to have_no_link(text: filename)
|
expect(subject).to have_no_link(text: filename)
|
||||||
expect(subject).to have_text('Analyse antivirus en cours')
|
expect(subject).to have_text('Analyse antivirus en cours')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'setup polling' do
|
||||||
|
expect(subject).to have_selector('[data-controller=turbo-poll]')
|
||||||
|
end
|
||||||
|
|
||||||
|
context "process is taking longer than expected" do
|
||||||
|
before do
|
||||||
|
champ.piece_justificative_file.attachments[0].update!(created_at: 5.minutes.ago)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders a refresh button' do
|
||||||
|
expect(subject).to have_button("Rafraîchir")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when used as multiple context" do
|
||||||
|
let(:kwargs) { { as_multiple: true } }
|
||||||
|
|
||||||
|
it 'does not setup polling' do
|
||||||
|
expect(subject).to have_no_selector('[data-controller=turbo-poll]')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the file is scanned and safe' do
|
context 'when the file is scanned and safe' do
|
||||||
|
|
108
spec/components/attachment/multiple_component_spec.rb
Normal file
108
spec/components/attachment/multiple_component_spec.rb
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
RSpec.describe Attachment::MultipleComponent, type: :component do
|
||||||
|
let(:champ) { create(:champ_titre_identite) }
|
||||||
|
let(:attached_file) { champ.piece_justificative_file }
|
||||||
|
let(:kwargs) { {} }
|
||||||
|
|
||||||
|
let(:component) do
|
||||||
|
described_class.new(
|
||||||
|
champ:,
|
||||||
|
attached_file:,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { render_inline(component).to_html }
|
||||||
|
|
||||||
|
context 'when there is no attachment yet' do
|
||||||
|
let(:champ) { create(:champ_titre_identite, skip_default_attachment: true) }
|
||||||
|
|
||||||
|
it 'renders a form field for uploading a file' do
|
||||||
|
expect(subject).to have_no_selector('.hidden input[type=file]')
|
||||||
|
expect(subject).to have_selector('input[type=file]:not(.hidden)')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders max size' do
|
||||||
|
expect(subject).to have_content(/Taille maximale :\s+20 Mo/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there is a template' do
|
||||||
|
before do
|
||||||
|
component.with_template { "the template to render" }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders the template' do
|
||||||
|
expect(subject).to have_text("the template to render")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when there is an attachment' do
|
||||||
|
before do
|
||||||
|
attached_file.attach(
|
||||||
|
io: StringIO.new("x" * 2),
|
||||||
|
filename: "me.jpg",
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
|
||||||
|
)
|
||||||
|
champ.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders the filenames' do
|
||||||
|
expect(subject).to have_content(attached_file.attachments[0].filename.to_s)
|
||||||
|
expect(subject).to have_content(attached_file.attachments[1].filename.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows the Delete button by default' do
|
||||||
|
expect(subject).to have_link(title: "Supprimer le fichier #{attached_file.attachments[0].filename}")
|
||||||
|
expect(subject).to have_link(title: "Supprimer le fichier #{attached_file.attachments[1].filename}")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'renders a form field for uploading a new file' do
|
||||||
|
expect(subject).to have_selector('input[type=file]:not(.hidden)')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not renders max size anymore' do
|
||||||
|
expect(subject).to have_no_content(/Taille maximale/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the user cannot destroy the attachment' do
|
||||||
|
let(:kwargs) { { user_can_destroy: false } }
|
||||||
|
|
||||||
|
it 'hides the Delete button' do
|
||||||
|
expect(subject).to have_no_link(title: "Supprimer le fichier #{attached_file.attachments[0].filename}")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'still renders the filename' do
|
||||||
|
expect(subject).to have_content(attached_file.attachments[0].filename.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'max attachments' do
|
||||||
|
let(:kwargs) { { max: 1 } }
|
||||||
|
|
||||||
|
it 'does not render visible input file where max attachments has been reached' do
|
||||||
|
expect(subject).to have_selector('.hidden input[type=file]')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'attachment process in progress' do
|
||||||
|
let(:created_at) { 1.second.ago }
|
||||||
|
|
||||||
|
before do
|
||||||
|
attached_file.attachments[0].blob.update(metadata: { virus_scan_result: ActiveStorage::VirusScanner::PENDING })
|
||||||
|
attached_file.attachments[0].update!(created_at:)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'setup polling' do
|
||||||
|
expect(subject).to have_selector('[data-controller=turbo-poll]')
|
||||||
|
end
|
||||||
|
|
||||||
|
context "process is taking longer than expected" do
|
||||||
|
let(:created_at) { 5.minutes.ago }
|
||||||
|
it 'renders a refresh button' do
|
||||||
|
expect(subject).to have_button("Rafraîchir")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue