require 'spec_helper' describe Instructeurs::DossiersController, type: :controller do render_views let(:instructeur) { create(:instructeur) } let(:administrateur) { create(:administrateur) } let(:administration) { create(:administration) } let(:instructeurs) { [instructeur] } let(:procedure) { create(:procedure, :published, instructeurs: instructeurs) } let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } let(:fake_justificatif) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') } before { sign_in(instructeur.user) } describe '#attestation' do context 'when a dossier has an attestation' do let(:dossier) { create(:dossier, :accepte, attestation: create(:attestation, :with_pdf), procedure: procedure) } it 'redirects to attestation pdf' do get :attestation, params: { procedure_id: procedure.id, dossier_id: dossier.id } expect(response).to redirect_to(dossier.attestation.pdf_url.gsub('http://localhost:3000', '')) end end end describe '#send_to_instructeurs' do let(:recipient) { create(:instructeur) } let(:instructeurs) { [instructeur, recipient] } let(:mail) { double("mail") } before do expect(mail).to receive(:deliver_later) expect(InstructeurMailer) .to receive(:send_dossier) .with(instructeur, dossier, recipient) .and_return(mail) post( :send_to_instructeurs, params: { recipients: [recipient], procedure_id: procedure.id, dossier_id: dossier.id } ) end it { expect(response).to redirect_to(personnes_impliquees_instructeur_dossier_url) } end describe '#follow' do before do patch :follow, params: { procedure_id: procedure.id, dossier_id: dossier.id } end it { expect(instructeur.followed_dossiers).to match([dossier]) } it { expect(flash.notice).to eq('Dossier suivi') } it { expect(response).to redirect_to(instructeur_procedures_url) } end describe '#unfollow' do before do instructeur.followed_dossiers << dossier patch :unfollow, params: { procedure_id: procedure.id, dossier_id: dossier.id } instructeur.reload end it { expect(instructeur.followed_dossiers).to match([]) } it { expect(flash.notice).to eq("Vous ne suivez plus le dossier nº #{dossier.id}") } it { expect(response).to redirect_to(instructeur_procedures_url) } end describe '#archive' do before do instructeur.follow(dossier) patch :archive, params: { procedure_id: procedure.id, dossier_id: dossier.id } dossier.reload instructeur.reload end it { expect(dossier.archived).to be true } it { expect(response).to redirect_to(instructeur_procedures_url) } end describe '#unarchive' do before do dossier.update(archived: true) patch :unarchive, params: { procedure_id: procedure.id, dossier_id: dossier.id } dossier.reload end it { expect(dossier.archived).to be false } it { expect(response).to redirect_to(instructeur_procedures_url) } end describe '#passer_en_instruction' do let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } before do sign_in(instructeur.user) post :passer_en_instruction, params: { procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' end it { expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) } it { expect(instructeur.follow?(dossier)).to be true } it { expect(response).to have_http_status(:ok) } it { expect(response.body).to include('.header-actions') } context 'when the dossier has already been put en_instruction' do let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) } it 'warns about the error, but doesn’t raise' do expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) expect(response).to have_http_status(:ok) end end end describe '#repasser_en_construction' do let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) } before do sign_in(instructeur.user) post :repasser_en_construction, params: { procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' end it { expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_construction)) } it { expect(response).to have_http_status(:ok) } it { expect(response.body).to include('.header-actions') } context 'when the dossier has already been put en_construction' do let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } it 'warns about the error, but doesn’t raise' do expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_construction)) expect(response).to have_http_status(:ok) end end end describe '#repasser_en_instruction' do let(:dossier) { create(:dossier, :refuse, procedure: procedure) } let(:current_user) { instructeur.user } before do sign_in current_user post :repasser_en_instruction, params: { procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' end it { expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) } it { expect(response).to have_http_status(:ok) } it { expect(response.body).to include('.header-actions') } context 'when the dossier has already been put en_instruction' do let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) } it 'warns about the error, but doesn’t raise' do expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) expect(response).to have_http_status(:ok) end end context 'when the dossier is accepte' do let(:dossier) { create(:dossier, :accepte, procedure: procedure) } it 'it is not possible to go back to en_instruction as instructeur' do expect(dossier.reload.state).to eq(Dossier.states.fetch(:accepte)) expect(response).to have_http_status(:ok) end context 'as superadmin' do let (:current_user) { administration } it 'it is not possible to go back to en_instruction' do expect(dossier.reload.state).to eq(Dossier.states.fetch(:accepte)) expect(response).to have_http_status(:ok) end end end end describe '#terminer' do context "with refuser" do before do dossier.en_instruction! sign_in(instructeur.user) end context 'simple refusal' do subject { post :terminer, params: { process_action: "refuser", procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' } it 'change state to refuse' do subject dossier.reload expect(dossier.state).to eq(Dossier.states.fetch(:refuse)) expect(dossier.justificatif_motivation).to_not be_attached end it 'Notification email is sent' do expect(NotificationMailer).to receive(:send_refused_notification) .with(dossier).and_return(NotificationMailer) expect(NotificationMailer).to receive(:deliver_later) subject end end context 'refusal with a justificatif' do subject { post :terminer, params: { process_action: "refuser", procedure_id: procedure.id, dossier_id: dossier.id, dossier: { justificatif_motivation: fake_justificatif } }, format: 'js' } it 'attachs a justificatif' do subject dossier.reload expect(dossier.state).to eq(Dossier.states.fetch(:refuse)) expect(dossier.justificatif_motivation).to be_attached end it { expect(subject.body).to include('.header-actions') } end end context "with classer_sans_suite" do before do dossier.en_instruction! sign_in(instructeur.user) end context 'without attachment' do subject { post :terminer, params: { process_action: "classer_sans_suite", procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' } it 'change state to sans_suite' do subject dossier.reload expect(dossier.state).to eq(Dossier.states.fetch(:sans_suite)) expect(dossier.justificatif_motivation).to_not be_attached end it 'Notification email is sent' do expect(NotificationMailer).to receive(:send_without_continuation_notification) .with(dossier).and_return(NotificationMailer) expect(NotificationMailer).to receive(:deliver_later) subject end it { expect(subject.body).to include('.header-actions') } end context 'with attachment' do subject { post :terminer, params: { process_action: "classer_sans_suite", procedure_id: procedure.id, dossier_id: dossier.id, dossier: { justificatif_motivation: fake_justificatif } }, format: 'js' } it 'change state to sans_suite' do subject dossier.reload expect(dossier.state).to eq(Dossier.states.fetch(:sans_suite)) expect(dossier.justificatif_motivation).to be_attached end it { expect(subject.body).to include('.header-actions') } end end context "with accepter" do before do dossier.en_instruction! sign_in(instructeur.user) expect(NotificationMailer).to receive(:send_closed_notification) .with(dossier) .and_return(NotificationMailer) expect(NotificationMailer).to receive(:deliver_later) end subject { post :terminer, params: { process_action: "accepter", procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' } it 'change state to accepte' do subject dossier.reload expect(dossier.state).to eq(Dossier.states.fetch(:accepte)) expect(dossier.justificatif_motivation).to_not be_attached end context 'when the dossier does not have any attestation' do it 'Notification email is sent' do subject end end context 'when the dossier has an attestation' do before do attestation = Attestation.new allow(attestation).to receive(:pdf).and_return(double(read: 'pdf', size: 2.megabytes)) allow_any_instance_of(Dossier).to receive(:build_attestation).and_return(attestation) end it 'The instructeur is sent back to the dossier page' do expect(subject.body).to include('.header-actions') end context 'and the dossier has already an attestation' do it 'should not crash' do dossier.attestation = Attestation.new dossier.save expect(subject.body).to include('.header-actions') end end end context 'when the attestation template uses the motivation field' do let(:emailable) { false } let(:template) { create(:attestation_template) } let(:procedure) { create(:procedure, :published, attestation_template: template, instructeurs: [instructeur]) } subject do post :terminer, params: { process_action: "accepter", procedure_id: procedure.id, dossier_id: dossier.id, dossier: { motivation: "Yallah" } }, format: 'js' end before do Timecop.freeze(Time.zone.now) expect_any_instance_of(AttestationTemplate) .to receive(:attestation_for) .with(have_attributes(motivation: "Yallah", processed_at: Time.zone.now)) end after { Timecop.return } it { subject } end context 'with an attachment' do subject { post :terminer, params: { process_action: "accepter", procedure_id: procedure.id, dossier_id: dossier.id, dossier: { justificatif_motivation: fake_justificatif } }, format: 'js' } it 'change state to accepte' do subject dossier.reload expect(dossier.state).to eq(Dossier.states.fetch(:accepte)) expect(dossier.justificatif_motivation).to be_attached end it { expect(subject.body).to include('.header-actions') } end end context 'when a dossier is already closed' do let(:dossier) { create(:dossier, :accepte, procedure: procedure) } before { allow(dossier).to receive(:accepter!) } subject { post :terminer, params: { process_action: "accepter", procedure_id: procedure.id, dossier_id: dossier.id, dossier: { justificatif_motivation: fake_justificatif } }, format: 'js' } it 'does not close it again' do subject expect(dossier).not_to have_received(:accepter!) expect(response).to have_http_status(:ok) end end end describe "#create_commentaire" do let(:saved_commentaire) { dossier.commentaires.first } let(:body) { "avant\napres" } let(:file) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') } let(:scan_result) { true } subject { post :create_commentaire, params: { procedure_id: procedure.id, dossier_id: dossier.id, commentaire: { body: body, file: file } } } before do allow(ClamavService).to receive(:safe_file?).and_return(scan_result) end it "creates a commentaire" do expect { subject }.to change(Commentaire, :count).by(1) expect(instructeur.followed_dossiers).to include(dossier) expect(response).to redirect_to(messagerie_instructeur_dossier_path(dossier.procedure, dossier)) expect(flash.notice).to be_present end context "when the commentaire created with virus file" do let(:scan_result) { false } it "creates a commentaire (shows message that file have a virus)" do expect { subject }.to change(Commentaire, :count).by(1) expect(instructeur.followed_dossiers).to include(dossier) expect(response).to redirect_to(messagerie_instructeur_dossier_path(dossier.procedure, dossier)) expect(flash.notice).to be_present end end end describe "#create_avis" do let(:saved_avis) { dossier.avis.first } let!(:old_avis_count) { Avis.count } subject do post :create_avis, params: { procedure_id: procedure.id, dossier_id: dossier.id, avis: { emails: emails, introduction: 'intro', confidentiel: true } } end before do subject end let(:emails) { ['email@a.com'] } it { expect(saved_avis.email).to eq('email@a.com') } it { expect(saved_avis.introduction).to eq('intro') } it { expect(saved_avis.confidentiel).to eq(true) } it { expect(saved_avis.dossier).to eq(dossier) } it { expect(saved_avis.claimant).to eq(instructeur) } it { expect(response).to redirect_to(avis_instructeur_dossier_path(dossier.procedure, dossier)) } context "with an invalid email" do let(:emails) { ['emaila.com'] } it { expect(response).to render_template :avis } it { expect(flash.alert).to eq(["emaila.com : Email n'est pas valide"]) } it { expect { subject }.not_to change(Avis, :count) } end context 'with multiple emails' do let(:emails) { ["toto.fr,titi@titimail.com"] } it { expect(response).to render_template :avis } it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) } it { expect(flash.notice).to eq("Une demande d'avis a été envoyée à titi@titimail.com") } it { expect(Avis.count).to eq(old_avis_count + 1) } it { expect(saved_avis.email).to eq("titi@titimail.com") } end end describe "#update_annotations" do let(:champ_multiple_drop_down_list) do create(:type_de_champ_multiple_drop_down_list, :private, libelle: 'libelle').champ.create end let(:champ_linked_drop_down_list) do create(:type_de_champ_linked_drop_down_list, :private, libelle: 'libelle').champ.create end let(:champ_datetime) do create(:type_de_champ_datetime, :private, libelle: 'libelle').champ.create end let(:champ_repetition) do tdc = create(:type_de_champ_repetition, :private, libelle: 'libelle') tdc.types_de_champ << create(:type_de_champ_text, libelle: 'libelle') champ = tdc.champ.create champ.add_row champ end let(:dossier) do create(:dossier, :en_construction, procedure: procedure, champs_private: [champ_multiple_drop_down_list, champ_linked_drop_down_list, champ_datetime, champ_repetition]) end before do patch :update_annotations, params: { procedure_id: procedure.id, dossier_id: dossier.id, dossier: { champs_private_attributes: { '0': { id: champ_multiple_drop_down_list.id, value: ['', 'un', 'deux'] }, '1': { id: champ_datetime.id, 'value(1i)': 2019, 'value(2i)': 12, 'value(3i)': 21, 'value(4i)': 13, 'value(5i)': 17 }, '2': { id: champ_linked_drop_down_list.id, primary_value: 'primary', secondary_value: 'secondary' }, '3': { id: champ_repetition.id, champs_attributes: { id: champ_repetition.champs.first.id, value: 'text' } } } } } champ_multiple_drop_down_list.reload champ_linked_drop_down_list.reload champ_datetime.reload champ_repetition.reload end it { expect(champ_multiple_drop_down_list.value).to eq('["un", "deux"]') } it { expect(champ_linked_drop_down_list.primary_value).to eq('primary') } it { expect(champ_linked_drop_down_list.secondary_value).to eq('secondary') } it { expect(champ_datetime.value).to eq('21/12/2019 13:17') } it { expect(champ_repetition.champs.first.value).to eq('text') } it { expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier)) } end describe "#telecharger_pjs" do subject do get :telecharger_pjs, params: { procedure_id: procedure.id, dossier_id: dossier.id } end context 'when zip download is disabled through flipflop' do it 'is forbidden' do subject expect(response).to have_http_status(:forbidden) end end end end