From 6ac01149929d03f84d27976bd79fe87ebce1e396 Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Tue, 22 Nov 2022 17:12:16 +0100 Subject: [PATCH] test(attachments): more components tests & improvements --- .../edit_component/edit_component.html.haml | 10 +- .../attachment/multiple_component.rb | 20 ++-- .../multiple_component.html.haml | 2 +- .../progress_component.html.haml | 2 +- .../show_component/show_component.html.haml | 2 +- .../piece_justificative_component.html.haml | 5 +- .../attachment/edit_component_spec.rb | 22 ++++ .../attachment/multiple_component_spec.rb | 108 ++++++++++++++++++ 8 files changed, 152 insertions(+), 19 deletions(-) create mode 100644 spec/components/attachment/multiple_component_spec.rb diff --git a/app/components/attachment/edit_component/edit_component.html.haml b/app/components/attachment/edit_component/edit_component.html.haml index 1036fc9ce..7f9567200 100644 --- a/app/components/attachment/edit_component/edit_component.html.haml +++ b/app/components/attachment/edit_component/edit_component.html.haml @@ -5,11 +5,13 @@ - if user_can_destroy? = 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 - = link_to_if(downloadable?, attachment.filename.to_s, attachment.url, class: "attachment-filename", download: "") do - %span.attachment-filename= attachment.filename.to_s + .fr-py-1v + - if downloadable? + = 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) - if error? %p.fr-error-text= error_message diff --git a/app/components/attachment/multiple_component.rb b/app/components/attachment/multiple_component.rb index 73efac37f..4a1ad3341 100644 --- a/app/components/attachment/multiple_component.rb +++ b/app/components/attachment/multiple_component.rb @@ -1,27 +1,27 @@ # Display a widget for uploading, editing and deleting a file attachment class Attachment::MultipleComponent < ApplicationComponent + DEFAULT_MAX_ATTACHMENTS = 10 + renders_one :template - attr_reader :form + attr_reader :champ attr_reader :attached_file + attr_reader :user_can_download attr_reader :user_can_destroy attr_reader :max delegate :count, :empty?, to: :attachments, prefix: true - def initialize(form:, attached_file:, user_can_destroy: false, max: nil) - @form = form + def initialize(champ:, attached_file:, user_can_download: false, user_can_destroy: true, max: nil) + @champ = champ @attached_file = attached_file + @user_can_download = user_can_download @user_can_destroy = user_can_destroy - @max = max || 10 + @max = max || DEFAULT_MAX_ATTACHMENTS @attachments = attached_file.attachments || [] end - def champ - form.object - end - def each_attachment(&block) @attachments.each_with_index(&block) end @@ -31,7 +31,7 @@ class Attachment::MultipleComponent < ApplicationComponent end def empty_component_id - "attachment-multiple-empty-#{form.object.id}" + "attachment-multiple-empty-#{champ.id}" end def in_progress? @@ -54,7 +54,7 @@ class Attachment::MultipleComponent < ApplicationComponent end def auto_attach_url - helpers.auto_attach_url(form.object) + helpers.auto_attach_url(champ) end private diff --git a/app/components/attachment/multiple_component/multiple_component.html.haml b/app/components/attachment/multiple_component/multiple_component.html.haml index bc76eae52..128f6132b 100644 --- a/app/components/attachment/multiple_component/multiple_component.html.haml +++ b/app/components/attachment/multiple_component/multiple_component.html.haml @@ -3,7 +3,7 @@ - each_attachment do |attachment, index| %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?) } = render Attachment::EditComponent.new(champ:, attached_file:, attachment: nil, index: attachments_count, user_can_destroy:) diff --git a/app/components/attachment/progress_component/progress_component.html.haml b/app/components/attachment/progress_component/progress_component.html.haml index a244b35b3..cf6232821 100644 --- a/app/components/attachment/progress_component/progress_component.html.haml +++ b/app/components/attachment/progress_component/progress_component.html.haml @@ -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 diff --git a/app/components/attachment/show_component/show_component.html.haml b/app/components/attachment/show_component/show_component.html.haml index 66aaca6d8..8bdd23d97 100644 --- a/app/components/attachment/show_component/show_component.html.haml +++ b/app/components/attachment/show_component/show_component.html.haml @@ -6,7 +6,7 @@ (ce fichier n’a pas été analysé par notre antivirus, téléchargez-le avec précaution) - 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) diff --git a/app/components/editable_champ/piece_justificative_component/piece_justificative_component.html.haml b/app/components/editable_champ/piece_justificative_component/piece_justificative_component.html.haml index ecbe427d5..e5b0cb1ec 100644 --- a/app/components/editable_champ/piece_justificative_component/piece_justificative_component.html.haml +++ b/app/components/editable_champ/piece_justificative_component/piece_justificative_component.html.haml @@ -1,6 +1,7 @@ - user_can_destroy = !@champ.mandatory? || @champ.dossier.brouillon? -- max = [true, nil].include?(@champ.procedure&.piece_justificative_multiple?) ? 10 : 1 -= render Attachment::MultipleComponent.new(form: @form, attached_file: @champ.piece_justificative_file, user_can_destroy:, max:) do |c| +- user_can_download = !@champ.dossier.brouillon? +- 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? - c.with_template do = render Dsfr::DownloadComponent.new(attachment: @champ.type_de_champ.piece_justificative_template, name: "Modèle à télécharger") do |c| diff --git a/spec/components/attachment/edit_component_spec.rb b/spec/components/attachment/edit_component_spec.rb index dd914a8c9..d0387da98 100644 --- a/spec/components/attachment/edit_component_spec.rb +++ b/spec/components/attachment/edit_component_spec.rb @@ -117,6 +117,28 @@ RSpec.describe Attachment::EditComponent, type: :component do expect(subject).to have_no_link(text: filename) expect(subject).to have_text('Analyse antivirus en cours') 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 context 'when the file is scanned and safe' do diff --git a/spec/components/attachment/multiple_component_spec.rb b/spec/components/attachment/multiple_component_spec.rb new file mode 100644 index 000000000..1f4cfebed --- /dev/null +++ b/spec/components/attachment/multiple_component_spec.rb @@ -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