demarches-normaliennes/spec/models/procedure_spec.rb

1159 lines
42 KiB
Ruby
Raw Normal View History

describe Procedure do
describe 'mail templates' do
subject { create(:procedure) }
it { expect(subject.initiated_mail_template).to be_a(Mails::InitiatedMail) }
it { expect(subject.received_mail_template).to be_a(Mails::ReceivedMail) }
it { expect(subject.closed_mail_template).to be_a(Mails::ClosedMail) }
it { expect(subject.refused_mail_template).to be_a(Mails::RefusedMail) }
it { expect(subject.without_continuation_mail_template).to be_a(Mails::WithoutContinuationMail) }
2017-03-06 15:00:05 +01:00
end
describe 'initiated_mail' do
let(:procedure) { create(:procedure) }
subject { procedure }
context 'when initiated_mail is not customize' do
it { expect(subject.initiated_mail_template.body).to eq(Mails::InitiatedMail.default_for_procedure(procedure).body) }
end
context 'when initiated_mail is customize' do
before :each do
2017-03-06 22:37:37 +01:00
subject.initiated_mail = Mails::InitiatedMail.new(body: 'sisi')
subject.save
subject.reload
end
it { expect(subject.initiated_mail_template.body).to eq('sisi') }
end
context 'when initiated_mail is customize ... again' do
before :each do
2017-03-06 22:37:37 +01:00
subject.initiated_mail = Mails::InitiatedMail.new(body: 'toto')
subject.save
subject.reload
end
it { expect(subject.initiated_mail_template.body).to eq('toto') }
2017-03-06 22:37:37 +01:00
it { expect(Mails::InitiatedMail.count).to eq(1) }
end
end
describe 'closed mail template body' do
let(:procedure) { create(:procedure) }
subject { procedure.closed_mail_template.rich_body.body.to_html }
context 'for procedures without an attestation' do
it { is_expected.not_to include('lien attestation') }
end
context 'for procedures with an attestation' do
before { create(:attestation_template, procedure: procedure, activated: activated) }
context 'when the attestation is inactive' do
let(:activated) { false }
it { is_expected.not_to include('lien attestation') }
end
context 'when the attestation is inactive' do
let(:activated) { true }
it { is_expected.to include('lien attestation') }
end
end
end
describe '#closed_mail_template_attestation_inconsistency_state' do
let(:procedure_without_attestation) { create(:procedure, closed_mail: closed_mail) }
let(:procedure_with_active_attestation) do
procedure = create(:procedure, closed_mail: closed_mail)
create(:attestation_template, procedure: procedure, activated: true)
procedure
end
let(:procedure_with_inactive_attestation) do
procedure = create(:procedure, closed_mail: closed_mail)
create(:attestation_template, procedure: procedure, activated: false)
procedure
end
subject { procedure.closed_mail_template_attestation_inconsistency_state }
context 'with a custom mail template' do
context 'that contains a lien attestation tag' do
let(:closed_mail) { build(:closed_mail, body: '--lien attestation--') }
context 'when the procedure doesnt have an attestation' do
let(:procedure) { procedure_without_attestation }
it { is_expected.to eq(:extraneous_tag) }
end
context 'when the procedure has an active attestation' do
let(:procedure) { procedure_with_active_attestation }
it { is_expected.to be(nil) }
end
context 'when the procedure has an inactive attestation' do
let(:procedure) { procedure_with_inactive_attestation }
it { is_expected.to eq(:extraneous_tag) }
end
end
context 'that doesnt contain a lien attestation tag' do
let(:closed_mail) { build(:closed_mail) }
context 'when the procedure doesnt have an attestation' do
let(:procedure) { procedure_without_attestation }
it { is_expected.to be(nil) }
end
context 'when the procedure has an active attestation' do
let(:procedure) { procedure_with_active_attestation }
it { is_expected.to eq(:missing_tag) }
end
context 'when the procedure has an inactive attestation' do
let(:procedure) { procedure_with_inactive_attestation }
it { is_expected.to be(nil) }
end
end
end
context 'with the default mail template' do
let(:closed_mail) { nil }
context 'when the procedure doesnt have an attestation' do
let(:procedure) { procedure_without_attestation }
it { is_expected.to be(nil) }
end
context 'when the procedure has an active attestation' do
let(:procedure) { procedure_with_active_attestation }
it { is_expected.to be(nil) }
end
context 'when the procedure has an inactive attestation' do
let(:procedure) { procedure_with_inactive_attestation }
it { is_expected.to be(nil) }
end
end
end
describe 'scopes' do
let!(:procedure) { create(:procedure) }
2020-02-05 16:09:03 +01:00
let!(:discarded_procedure) { create(:procedure, :discarded) }
describe 'default_scope' do
subject { Procedure.all }
it { is_expected.to match_array([procedure]) }
end
end
describe 'validation' do
context 'libelle' do
it { is_expected.not_to allow_value(nil).for(:libelle) }
it { is_expected.not_to allow_value('').for(:libelle) }
it { is_expected.to allow_value('Demande de subvention').for(:libelle) }
end
context 'description' do
it { is_expected.not_to allow_value(nil).for(:description) }
it { is_expected.not_to allow_value('').for(:description) }
it { is_expected.to allow_value('Description Demande de subvention').for(:description) }
end
context 'organisation' do
it { is_expected.to allow_value('URRSAF').for(:organisation) }
end
2018-05-31 10:59:38 +02:00
context 'administrateurs' do
it { is_expected.not_to allow_value([]).for(:administrateurs) }
end
2018-05-31 10:59:38 +02:00
context 'juridique' do
it { is_expected.not_to allow_value(nil).for(:cadre_juridique) }
it { is_expected.to allow_value('text').for(:cadre_juridique) }
context 'with deliberation' do
let(:procedure) { build(:procedure, cadre_juridique: nil) }
it { expect(procedure.valid?).to eq(false) }
context 'when the deliberation is uploaded ' do
before do
procedure.deliberation = fixture_file_upload('spec/fixtures/files/file.pdf', 'application/pdf')
2018-05-31 10:59:38 +02:00
end
it { expect(procedure.valid?).to eq(true) }
end
2020-03-16 17:55:16 +01:00
context 'when the deliberation is uploaded with an unauthorized format' do
before do
procedure.deliberation = fixture_file_upload('spec/fixtures/files/french-flag.gif', 'image/gif')
2020-03-16 17:55:16 +01:00
end
it { expect(procedure.valid?).to eq(false) }
end
2018-05-31 10:59:38 +02:00
end
2020-07-08 17:00:21 +02:00
context 'api_entreprise_token' do
let(:valid_token) { "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" }
let(:invalid_token) { 'plouf' }
it { is_expected.to allow_value(valid_token).for(:api_entreprise_token) }
it { is_expected.not_to allow_value(invalid_token).for(:api_entreprise_token) }
end
2018-05-31 10:59:38 +02:00
end
context 'when juridique_required is false' do
let(:procedure) { build(:procedure, juridique_required: false, cadre_juridique: nil) }
it { expect(procedure.valid?).to eq(true) }
end
2019-07-17 15:12:07 +02:00
context 'monavis' do
context 'nil is allowed' do
2019-07-17 15:34:10 +02:00
it { is_expected.to allow_value(nil).for(:monavis_embed) }
it { is_expected.to allow_value('').for(:monavis_embed) }
2019-07-17 15:12:07 +02:00
end
context 'random string is not allowed' do
2019-07-17 15:34:10 +02:00
let(:procedure) { build(:procedure, monavis_embed: "plop") }
2019-07-17 15:12:07 +02:00
it { expect(procedure.valid?).to eq(false) }
end
context 'random html is not allowed' do
2019-07-17 15:34:10 +02:00
let(:procedure) { build(:procedure, monavis_embed: '<img src="http://some.analytics/hello.gif">') }
2019-07-17 15:12:07 +02:00
it { expect(procedure.valid?).to eq(false) }
end
context 'Monavis embed code with white button is allowed' do
monavis_blanc = <<-MSG
2019-07-17 15:34:10 +02:00
<a href="https://monavis.numerique.gouv.fr/Demarches/123?&view-mode=formulaire-avis&nd_mode=en-ligne-enti%C3%A8rement&nd_source=button&key=cd4a872d475e4045666057f">
<img src="https://monavis.numerique.gouv.fr/monavis-static/bouton-blanc.png" alt="Je donne mon avis" title="Je donne mon avis sur cette démarche" />
</a>
MSG
let(:procedure) { build(:procedure, monavis_embed: monavis_blanc) }
2019-07-17 15:12:07 +02:00
it { expect(procedure.valid?).to eq(true) }
end
context 'Monavis embed code with blue button is allowed' do
2019-07-17 15:34:10 +02:00
monavis_bleu = <<-MSG
<a href="https://monavis.numerique.gouv.fr/Demarches/123?&view-mode=formulaire-avis&nd_mode=en-ligne-enti%C3%A8rement&nd_source=button&key=cd4a872d475e4045666057f">
<img src="https://monavis.numerique.gouv.fr/monavis-static/bouton-bleu.png" alt="Je donne mon avis" title="Je donne mon avis sur cette démarche" />
</a>
MSG
let(:procedure) { build(:procedure, monavis_embed: monavis_bleu) }
2019-07-17 15:12:07 +02:00
it { expect(procedure.valid?).to eq(true) }
end
end
shared_examples 'duree de conservation' do
context 'duree_conservation_required it true, the field gets validated' do
it { is_expected.not_to allow_value(nil).for(field_name) }
it { is_expected.not_to allow_value('').for(field_name) }
it { is_expected.not_to allow_value('trois').for(field_name) }
it { is_expected.to allow_value(3).for(field_name) }
end
end
describe 'duree de conservation dans ds' do
let(:field_name) { :duree_conservation_dossiers_dans_ds }
it_behaves_like 'duree de conservation'
end
describe 'duree de conservation hors ds' do
let(:field_name) { :duree_conservation_dossiers_hors_ds }
it_behaves_like 'duree de conservation'
end
end
describe 'active' do
2018-05-16 17:21:12 +02:00
let(:procedure) { create(:procedure) }
subject { Procedure.active(procedure.id) }
context 'when procedure is in draft status and not closed' do
it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
end
context 'when procedure is published and not closed' do
2018-05-16 17:21:12 +02:00
let(:procedure) { create(:procedure, :published) }
it { is_expected.to be_truthy }
end
context 'when procedure is published and closed' do
let(:procedure) { create(:procedure, :closed) }
it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
end
end
2016-06-15 11:34:05 +02:00
describe 'api_entreprise_token_expired?' do
2020-07-08 17:00:21 +02:00
let(:token) { "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" }
let(:procedure) { create(:procedure, api_entreprise_token: token) }
let(:payload) {
[
{ "exp" => expiration_time }
]
}
let(:subject) { procedure.api_entreprise_token_expired? }
before do
allow(JWT).to receive(:decode).with(token, nil, false).and_return(payload)
end
context "with token expired" do
let(:expiration_time) { (Time.zone.now - 1.day).to_i }
it { is_expected.to be_truthy }
end
context "with token not expired" do
let(:expiration_time) { (Time.zone.now + 1.day).to_i }
it { is_expected.to be_falsey }
end
end
2016-06-15 11:34:05 +02:00
describe 'clone' do
2020-08-27 19:56:19 +02:00
let(:service) { create(:service) }
let(:procedure) { create(:procedure, received_mail: received_mail, service: service, types_de_champ: [type_de_champ_0, type_de_champ_1, type_de_champ_2, type_de_champ_pj], types_de_champ_private: [type_de_champ_private_0, type_de_champ_private_1, type_de_champ_private_2]) }
let(:type_de_champ_0) { build(:type_de_champ, position: 0) }
let(:type_de_champ_1) { build(:type_de_champ, position: 1) }
let(:type_de_champ_2) { build(:type_de_champ_drop_down_list, position: 2) }
let(:type_de_champ_pj) { build(:type_de_champ_piece_justificative, position: 3, old_pj: { stable_id: 2713 }) }
let(:type_de_champ_private_0) { build(:type_de_champ, :private, position: 0) }
let(:type_de_champ_private_1) { build(:type_de_champ, :private, position: 1) }
let(:type_de_champ_private_2) { build(:type_de_champ_drop_down_list, :private, position: 2) }
let(:received_mail) { build(:received_mail) }
let(:from_library) { false }
let(:administrateur) { procedure.administrateurs.first }
2020-08-27 19:56:19 +02:00
let(:groupe_instructeur_1) { create(:groupe_instructeur, procedure: procedure, label: "groupe_1") }
let(:instructeur_1) { create(:instructeur) }
let(:instructeur_2) { create(:instructeur) }
2020-03-11 19:49:04 +01:00
let!(:assign_to_1) { create(:assign_to, procedure: procedure, groupe_instructeur: groupe_instructeur_1, instructeur: instructeur_1) }
let!(:assign_to_2) { create(:assign_to, procedure: procedure, groupe_instructeur: groupe_instructeur_1, instructeur: instructeur_2) }
before do
2020-01-28 12:02:06 +01:00
@logo = Rack::Test::UploadedFile.new('spec/fixtures/files/white.png', 'image/png')
@signature = Rack::Test::UploadedFile.new('spec/fixtures/files/black.png', 'image/png')
@attestation_template = create(:attestation_template, procedure: procedure, logo: @logo, signature: @signature)
@procedure = procedure.clone(administrateur, from_library)
@procedure.save
end
subject { @procedure }
2016-06-15 11:34:05 +02:00
2018-04-24 15:23:07 +02:00
it { expect(subject.parent_procedure).to eq(procedure) }
2020-03-11 19:49:04 +01:00
describe "should keep groupe instructeurs " do
it "should clone groupe instructeurs" do
expect(subject.groupe_instructeurs.size).to eq(2)
expect(subject.groupe_instructeurs.size).to eq(procedure.groupe_instructeurs.size)
expect(subject.groupe_instructeurs.where(label: "groupe_1").first).not_to be nil
end
it "should clone instructeurs in the groupe" do
expect(subject.groupe_instructeurs.where(label: "groupe_1").first.instructeurs.map(&:email)).to eq(procedure.groupe_instructeurs.where(label: "groupe_1").first.instructeurs.map(&:email))
end
end
2018-04-24 15:23:07 +02:00
2016-06-15 11:34:05 +02:00
it 'should duplicate specific objects with different id' do
expect(subject.id).not_to eq(procedure.id)
2020-08-27 19:56:19 +02:00
expect(subject.draft_types_de_champ.size).to eq(procedure.draft_types_de_champ.size)
expect(subject.draft_types_de_champ_private.size).to eq(procedure.draft_types_de_champ_private.size)
2020-08-27 19:56:19 +02:00
procedure.draft_types_de_champ.zip(subject.draft_types_de_champ).each do |ptc, stc|
2020-07-28 16:39:32 +02:00
expect(stc).to have_same_attributes_as(ptc, except: ["revision_id"])
expect(stc.revision).to eq(subject.draft_revision)
2016-06-15 11:34:05 +02:00
end
2020-08-27 19:56:19 +02:00
procedure.draft_types_de_champ_private.zip(subject.draft_types_de_champ_private).each do |ptc, stc|
2020-07-28 16:39:32 +02:00
expect(stc).to have_same_attributes_as(ptc, except: ["revision_id"])
expect(stc.revision).to eq(subject.draft_revision)
2016-09-09 17:39:56 +02:00
end
expect(subject.attestation_template.title).to eq(procedure.attestation_template.title)
expect(subject.cloned_from_library).to be(false)
2018-04-24 15:23:07 +02:00
cloned_procedure = subject
cloned_procedure.parent_procedure_id = nil
2020-06-26 12:00:21 +02:00
expect(cloned_procedure).to have_same_attributes_as(procedure, except: ["path", "draft_revision_id"])
end
context 'when the procedure is cloned from the library' do
let(:from_library) { true }
it 'should set cloned_from_library to true' do
expect(subject.cloned_from_library).to be(true)
end
it 'should set service_id to nil' do
expect(subject.service).to eq(nil)
end
it 'should discard old pj information' do
2020-08-27 19:56:19 +02:00
subject.draft_types_de_champ.each do |stc|
expect(stc.old_pj).to be_nil
end
end
it 'should have one administrateur' do
expect(subject.administrateurs).to eq([administrateur])
end
it 'should set ask_birthday to false' do
expect(subject.ask_birthday?).to eq(false)
end
end
context 'when the procedure is cloned from the library' do
let(:procedure) { create(:procedure, received_mail: received_mail, service: service, ask_birthday: true) }
it 'should set ask_birthday to false' do
expect(subject.ask_birthday?).to eq(false)
end
2017-03-07 18:19:48 +01:00
end
it 'should keep service_id' do
expect(subject.service).to eq(service)
end
context 'when the procedure is cloned to another administrateur' do
let(:administrateur) { create(:administrateur) }
it 'should clone service' do
expect(subject.service.id).not_to eq(service.id)
expect(subject.service.administrateur_id).not_to eq(service.administrateur_id)
expect(subject.service.attributes.except("id", "administrateur_id", "created_at", "updated_at")).to eq(service.attributes.except("id", "administrateur_id", "created_at", "updated_at"))
end
it 'should discard old pj information' do
2020-08-27 19:56:19 +02:00
subject.draft_types_de_champ.each do |stc|
expect(stc.old_pj).to be_nil
end
end
it 'should discard specific api_entreprise_token' do
expect(subject.read_attribute(:api_entreprise_token)).to be_nil
end
it 'should have one administrateur' do
expect(subject.administrateurs).to eq([administrateur])
end
it "should discard the existing groupe instructeurs" do
expect(subject.groupe_instructeurs.size).not_to eq(procedure.groupe_instructeurs.size)
expect(subject.groupe_instructeurs.where(label: "groupe_1").first).to be nil
end
it 'should have a default groupe instructeur' do
expect(subject.groupe_instructeurs.size).to eq(1)
expect(subject.groupe_instructeurs.first.label).to eq(GroupeInstructeur::DEFAULT_LABEL)
expect(subject.groupe_instructeurs.first.instructeurs.size).to eq(0)
end
end
2017-03-07 18:19:48 +01:00
it 'should duplicate existing mail_templates' do
expect(subject.received_mail.attributes.except("id", "procedure_id", "created_at", "updated_at")).to eq procedure.received_mail.attributes.except("id", "procedure_id", "created_at", "updated_at")
expect(subject.received_mail.id).not_to eq procedure.received_mail.id
expect(subject.received_mail.id).not_to be nil
expect(subject.received_mail.procedure_id).not_to eq procedure.received_mail.procedure_id
expect(subject.received_mail.procedure_id).not_to be nil
end
it 'should not duplicate default mail_template' do
expect(subject.initiated_mail_template.attributes).to eq Mails::InitiatedMail.default_for_procedure(subject).attributes
2016-06-15 11:34:05 +02:00
end
it 'should not duplicate specific related objects' do
expect(subject.dossiers).to eq([])
end
describe 'should not duplicate lien_notice' do
let(:procedure) { create(:procedure, lien_notice: "http://toto.com") }
it { expect(subject.lien_notice).to be_nil }
end
2016-06-15 11:34:05 +02:00
describe 'procedure status is reset' do
let(:procedure) { create(:procedure, :closed, received_mail: received_mail, service: service) }
2018-05-28 14:58:40 +02:00
it 'Not published nor closed' do
expect(subject.closed_at).to be_nil
expect(subject.published_at).to be_nil
2019-12-04 15:45:06 +01:00
expect(subject.unpublished_at).to be_nil
2018-05-28 14:58:40 +02:00
expect(subject.aasm_state).to eq "brouillon"
2019-03-06 14:42:27 +01:00
expect(subject.path).not_to be_nil
2016-06-15 11:34:05 +02:00
end
end
it 'should keep types_de_champ ids stable' do
2020-08-27 19:56:19 +02:00
expect(subject.draft_types_de_champ.first.id).not_to eq(procedure.draft_types_de_champ.first.id)
expect(subject.draft_types_de_champ.first.stable_id).to eq(procedure.draft_types_de_champ.first.id)
end
it 'should duplicate piece_justificative_template on a type_de_champ' do
2020-08-27 19:56:19 +02:00
expect(subject.draft_types_de_champ.where(type_champ: "piece_justificative").first.piece_justificative_template.attached?).to be true
end
context 'with a notice attached' do
let(:procedure) { create(:procedure, :with_notice, received_mail: received_mail, service: service) }
it 'should duplicate notice' do
expect(subject.notice.attached?).to be true
end
end
context 'with a deliberation attached' do
let(:procedure) { create(:procedure, :with_deliberation, received_mail: received_mail, service: service) }
it 'should duplicate deliberation' do
expect(subject.deliberation.attached?).to be true
end
end
context 'with canonical procedure' do
let(:canonical_procedure) { create(:procedure) }
let(:procedure) { create(:procedure, canonical_procedure: canonical_procedure, received_mail: received_mail, service: service) }
it 'do not clone canonical procedure' do
expect(subject.canonical_procedure).to be_nil
end
end
2016-06-15 11:34:05 +02:00
end
describe '#publish!' do
let(:procedure) { create(:procedure, path: 'example-path') }
2018-10-25 15:11:12 +02:00
let(:now) { Time.zone.now.beginning_of_minute }
context 'when publishing a new procedure' do
2019-12-04 15:45:06 +01:00
before do
Timecop.freeze(now) do
procedure.publish!
end
2019-12-04 15:45:06 +01:00
end
it 'no reference to the canonical procedure on the published procedure' do
expect(procedure.canonical_procedure).to be_nil
end
it 'changes the procedure state to published' do
2019-12-04 15:45:06 +01:00
expect(procedure.closed_at).to be_nil
expect(procedure.published_at).to eq(now)
expect(Procedure.find_by(path: "example-path")).to eq(procedure)
expect(Procedure.find_by(path: "example-path").administrateurs).to eq(procedure.administrateurs)
end
2020-07-08 19:11:03 +02:00
it 'creates a new draft revision' do
expect(procedure.published_revision).not_to be_nil
expect(procedure.draft_revision).not_to be_nil
expect(procedure.revisions.count).to eq(2)
expect(procedure.revisions).to eq([procedure.published_revision, procedure.draft_revision])
end
2019-12-04 15:45:06 +01:00
end
context 'when publishing over a previous canonical procedure' do
let(:canonical_procedure) { create(:procedure, :published) }
before do
Timecop.freeze(now) do
procedure.publish!(canonical_procedure)
end
end
it 'references the canonical procedure on the published procedure' do
expect(procedure.canonical_procedure).to eq(canonical_procedure)
end
it 'changes the procedure state to published' do
expect(procedure.closed_at).to be_nil
expect(procedure.published_at).to eq(now)
end
end
2019-12-04 15:45:06 +01:00
end
describe "#publish_or_reopen!" do
let(:canonical_procedure) { create(:procedure, :published) }
let(:administrateur) { canonical_procedure.administrateurs.first }
2019-12-04 15:45:06 +01:00
let(:procedure) { create(:procedure, administrateurs: [administrateur]) }
let(:now) { Time.zone.now.beginning_of_minute }
context 'when publishing over a previous canonical procedure' do
before do
procedure.path = canonical_procedure.path
Timecop.freeze(now) do
procedure.publish_or_reopen!(administrateur)
end
canonical_procedure.reload
end
it 'references the canonical procedure on the published procedure' do
expect(procedure.canonical_procedure).to eq(canonical_procedure)
end
it 'changes the procedure state to published' do
expect(procedure.closed_at).to be_nil
expect(procedure.published_at).to eq(now)
end
it 'unpublishes the canonical procedure' do
expect(canonical_procedure.unpublished_at).to eq(now)
end
2020-07-08 19:11:03 +02:00
it 'creates a new draft revision' do
expect(procedure.published_revision).not_to be_nil
expect(procedure.draft_revision).not_to be_nil
expect(procedure.revisions.count).to eq(2)
expect(procedure.revisions).to eq([procedure.published_revision, procedure.draft_revision])
end
end
context 'when publishing over a previous procedure with canonical procedure' do
let(:canonical_procedure) { create(:procedure, :closed) }
let(:parent_procedure) { create(:procedure, :published, administrateurs: [administrateur]) }
2019-12-04 15:45:06 +01:00
before do
parent_procedure.update!(path: canonical_procedure.path, canonical_procedure: canonical_procedure)
procedure.path = canonical_procedure.path
Timecop.freeze(now) do
procedure.publish_or_reopen!(administrateur)
end
parent_procedure.reload
2019-12-04 15:45:06 +01:00
end
it 'references the canonical procedure on the published procedure' do
expect(procedure.canonical_procedure).to eq(canonical_procedure)
end
it 'changes the procedure state to published' do
expect(procedure.canonical_procedure).to eq(canonical_procedure)
2019-12-04 15:45:06 +01:00
expect(procedure.closed_at).to be_nil
expect(procedure.published_at).to eq(now)
end
it 'unpublishes parent procedure' do
expect(parent_procedure.unpublished_at).to eq(now)
2019-12-04 15:45:06 +01:00
end
end
end
describe "#unpublish!" do
let(:procedure) { create(:procedure, :published) }
let(:now) { Time.zone.now.beginning_of_minute }
before do
Timecop.freeze(now) do
procedure.unpublish!
end
end
2019-12-04 15:45:06 +01:00
it {
expect(procedure.closed_at).to eq(nil)
expect(procedure.published_at).not_to be_nil
expect(procedure.unpublished_at).to eq(now)
}
2020-07-08 19:11:03 +02:00
it 'sets published revision' do
expect(procedure.published_revision).not_to be_nil
expect(procedure.draft_revision).not_to be_nil
expect(procedure.revisions.count).to eq(2)
2020-07-22 11:56:19 +02:00
expect(procedure.revisions).to eq([procedure.published_revision, procedure.draft_revision])
2020-07-08 19:11:03 +02:00
end
end
2017-07-13 15:21:52 +02:00
describe "#brouillon?" do
2019-12-04 15:45:06 +01:00
let(:procedure_brouillon) { build(:procedure) }
let(:procedure_publiee) { build(:procedure, :published) }
let(:procedure_close) { build(:procedure, :closed) }
let(:procedure_depubliee) { build(:procedure, :unpublished) }
2017-07-13 15:21:52 +02:00
it { expect(procedure_brouillon.brouillon?).to be_truthy }
it { expect(procedure_publiee.brouillon?).to be_falsey }
it { expect(procedure_close.brouillon?).to be_falsey }
2019-12-04 15:45:06 +01:00
it { expect(procedure_depubliee.brouillon?).to be_falsey }
2017-07-13 15:21:52 +02:00
end
2017-07-13 15:14:28 +02:00
describe "#publiee?" do
2019-12-04 15:45:06 +01:00
let(:procedure_brouillon) { build(:procedure) }
let(:procedure_publiee) { build(:procedure, :published) }
let(:procedure_close) { build(:procedure, :closed) }
let(:procedure_depubliee) { build(:procedure, :unpublished) }
2017-07-13 15:14:28 +02:00
it { expect(procedure_brouillon.publiee?).to be_falsey }
it { expect(procedure_publiee.publiee?).to be_truthy }
it { expect(procedure_close.publiee?).to be_falsey }
2019-12-04 15:45:06 +01:00
it { expect(procedure_depubliee.publiee?).to be_falsey }
2017-07-13 15:14:28 +02:00
end
describe "#close?" do
2019-12-04 15:45:06 +01:00
let(:procedure_brouillon) { build(:procedure) }
let(:procedure_publiee) { build(:procedure, :published) }
let(:procedure_close) { build(:procedure, :closed) }
let(:procedure_depubliee) { build(:procedure, :unpublished) }
it { expect(procedure_brouillon.close?).to be_falsey }
it { expect(procedure_publiee.close?).to be_falsey }
it { expect(procedure_close.close?).to be_truthy }
2019-12-04 15:45:06 +01:00
it { expect(procedure_depubliee.close?).to be_falsey }
end
describe "#depubliee?" do
let(:procedure_brouillon) { build(:procedure) }
let(:procedure_publiee) { build(:procedure, :published) }
let(:procedure_close) { build(:procedure, :closed) }
let(:procedure_depubliee) { build(:procedure, :unpublished) }
it { expect(procedure_brouillon.depubliee?).to be_falsey }
it { expect(procedure_publiee.depubliee?).to be_falsey }
it { expect(procedure_close.depubliee?).to be_falsey }
it { expect(procedure_depubliee.depubliee?).to be_truthy }
2017-07-13 15:20:24 +02:00
end
2019-12-04 15:45:06 +01:00
describe "#locked?" do
let(:procedure_brouillon) { build(:procedure) }
let(:procedure_publiee) { build(:procedure, :published) }
let(:procedure_close) { build(:procedure, :closed) }
let(:procedure_depubliee) { build(:procedure, :unpublished) }
2017-07-13 15:20:24 +02:00
2019-12-04 15:45:06 +01:00
it { expect(procedure_brouillon.locked?).to be_falsey }
it { expect(procedure_publiee.locked?).to be_truthy }
it { expect(procedure_close.locked?).to be_truthy }
it { expect(procedure_depubliee.locked?).to be_truthy }
end
2019-12-04 15:45:06 +01:00
describe 'close' do
let(:procedure) { create(:procedure, :published) }
2018-10-25 15:11:12 +02:00
let(:now) { Time.zone.now.beginning_of_minute }
before do
Timecop.freeze(now) do
procedure.close!
end
procedure.reload
end
it { expect(procedure.close?).to be_truthy }
it { expect(procedure.closed_at).to eq(now) }
2020-07-08 19:11:03 +02:00
it 'sets published revision' do
expect(procedure.published_revision).not_to be_nil
expect(procedure.draft_revision).not_to be_nil
expect(procedure.revisions.count).to eq(2)
2020-07-22 11:56:19 +02:00
expect(procedure.revisions).to eq([procedure.published_revision, procedure.draft_revision])
2020-07-08 19:11:03 +02:00
end
end
2019-07-05 14:38:20 +02:00
describe 'path_customized?' do
let(:procedure) { create :procedure }
subject { procedure.path_customized? }
context 'when the path is still the default' do
it { is_expected.to be_falsey }
end
context 'when the path has been changed' do
before { procedure.path = 'custom_path' }
it { is_expected.to be_truthy }
end
end
describe 'total_dossier' do
let(:procedure) { create :procedure }
before do
create :dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction)
create :dossier, procedure: procedure, state: Dossier.states.fetch(:brouillon)
create :dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction)
end
subject { procedure.total_dossier }
it { is_expected.to eq 2 }
end
2019-07-05 14:38:20 +02:00
describe 'suggested_path' do
2020-08-27 19:56:19 +02:00
let(:procedure) { create(:procedure, aasm_state: :publiee, libelle: 'Inscription au Collège') }
2019-07-05 14:38:20 +02:00
subject { procedure.suggested_path(procedure.administrateurs.first) }
context 'when the path has been customized' do
before { procedure.path = 'custom_path' }
it { is_expected.to eq 'custom_path' }
end
2019-07-05 14:38:20 +02:00
context 'when the suggestion does not conflict' do
it { is_expected.to eq 'inscription-au-college' }
end
context 'when the suggestion conflicts with one procedure' do
before do
2020-08-27 19:56:19 +02:00
create(:procedure, aasm_state: :publiee, path: 'inscription-au-college')
2019-07-05 14:38:20 +02:00
end
it { is_expected.to eq 'inscription-au-college-2' }
end
context 'when the suggestion conflicts with several procedures' do
before do
2020-08-27 19:56:19 +02:00
create(:procedure, aasm_state: :publiee, path: 'inscription-au-college')
create(:procedure, aasm_state: :publiee, path: 'inscription-au-college-2')
2019-07-05 14:38:20 +02:00
end
it { is_expected.to eq 'inscription-au-college-3' }
end
context 'when the suggestion conflicts with another procedure of the same admin' do
before do
2020-08-27 19:56:19 +02:00
create(:procedure, aasm_state: :publiee, path: 'inscription-au-college', administrateurs: procedure.administrateurs)
2019-07-05 14:38:20 +02:00
end
it { is_expected.to eq 'inscription-au-college' }
end
end
2017-06-27 14:22:43 +02:00
describe ".default_scope" do
let!(:procedure) { create(:procedure, hidden_at: hidden_at) }
context "when hidden_at is nil" do
let(:hidden_at) { nil }
it { expect(Procedure.count).to eq(1) }
it { expect(Procedure.all).to include(procedure) }
end
context "when hidden_at is not nil" do
let(:hidden_at) { 2.days.ago }
it { expect(Procedure.count).to eq(0) }
it { expect { Procedure.find(procedure.id) }.to raise_error(ActiveRecord::RecordNotFound) }
end
end
2020-03-26 09:08:52 +01:00
describe "#discard_and_keep_track!" do
let(:administration) { create(:administration) }
let(:procedure) { create(:procedure) }
let!(:dossier) { create(:dossier, procedure: procedure) }
let!(:dossier2) { create(:dossier, procedure: procedure) }
let(:instructeur) { create(:instructeur) }
it { expect(Dossier.count).to eq(2) }
it { expect(Dossier.all).to include(dossier, dossier2) }
2020-03-26 09:08:52 +01:00
context "when discarding procedure" do
before do
instructeur.followed_dossiers << dossier
2020-03-26 09:08:52 +01:00
procedure.discard_and_keep_track!(administration)
instructeur.reload
end
it { expect(procedure.dossiers.count).to eq(0) }
it { expect(Dossier.count).to eq(0) }
it { expect(instructeur.followed_dossiers).not_to include(dossier) }
end
end
2017-09-27 15:16:07 +02:00
describe ".default_sort" do
2018-09-20 17:02:28 +02:00
it { expect(Procedure.default_sort).to eq({ "table" => "self", "column" => "id", "order" => "desc" }) }
2017-09-27 15:16:07 +02:00
end
describe "#export_filename" do
2018-10-25 15:21:06 +02:00
before { Timecop.freeze(Time.zone.local(2018, 1, 2, 23, 11, 14)) }
after { Timecop.return }
subject { procedure.export_filename(:csv) }
let(:procedure) { create(:procedure, :published) }
it { is_expected.to eq("dossiers_#{procedure.path}_2018-01-02_23-11.csv") }
end
describe '#new_dossier' do
let(:procedure) do
2020-08-27 19:56:19 +02:00
create(:procedure,
types_de_champ: [
build(:type_de_champ_text, position: 0),
build(:type_de_champ_number, position: 1)
],
types_de_champ_private: [
build(:type_de_champ_textarea, :private)
])
end
let(:dossier) { procedure.new_dossier }
it { expect(dossier.procedure).to eq(procedure) }
it { expect(dossier.champs.size).to eq(2) }
it { expect(dossier.champs[0].type).to eq("Champs::TextChamp") }
it { expect(dossier.champs_private.size).to eq(1) }
it { expect(dossier.champs_private[0].type).to eq("Champs::TextareaChamp") }
it { expect(Champ.count).to eq(0) }
end
describe "#organisation_name" do
subject { procedure.organisation_name }
context 'when the procedure has a service (and no organization)' do
let(:procedure) { create(:procedure, :with_service, organisation: nil) }
it { is_expected.to eq procedure.service.nom }
end
context 'when the procedure has an organization (and no service)' do
let(:procedure) { create(:procedure, organisation: 'DDT des Vosges', service: nil) }
it { is_expected.to eq procedure.organisation }
end
end
describe '#juridique_required' do
it 'automatically jumps to true once cadre_juridique or deliberation have been set' do
p = create(
:procedure,
juridique_required: false,
2018-10-01 14:08:12 +02:00
cadre_juridique: nil
)
expect(p.juridique_required).to be_falsey
p.update(cadre_juridique: 'cadre')
expect(p.juridique_required).to be_truthy
p.update(cadre_juridique: nil)
expect(p.juridique_required).to be_truthy
p.update_columns(cadre_juridique: nil, juridique_required: false)
p.reload
expect(p.juridique_required).to be_falsey
@deliberation = fixture_file_upload('spec/fixtures/files/file.pdf', 'application/pdf')
2020-03-16 17:55:16 +01:00
p.update(deliberation: @deliberation)
p.reload
expect(p.juridique_required).to be_truthy
end
end
describe '#usual_traitement_time' do
let(:procedure) { create(:procedure) }
def create_dossier(construction_date:, instruction_date:, processed_date:)
dossier = create(:dossier, :accepte, procedure: procedure, en_construction_at: construction_date, en_instruction_at: instruction_date, processed_at: processed_date)
end
before do
Timecop.freeze(Time.utc(2019, 6, 1, 12, 0))
delays.each do |delay|
create_dossier(construction_date: 1.week.ago - delay, instruction_date: 1.week.ago - delay + 12.hours, processed_date: 1.week.ago)
end
end
after { Timecop.return }
context 'when there are several processed dossiers' do
let(:delays) { [1.day, 2.days, 2.days, 2.days, 2.days, 3.days, 3.days, 3.days, 3.days, 12.days] }
2020-07-15 11:08:15 +02:00
it 'returns a time representative of the dossier instruction delay' do
expect(procedure.usual_traitement_time).to be_between(3.days, 4.days)
end
end
context 'when there are very old dossiers' do
let(:delays) { [2.days, 2.days] }
let!(:old_dossier) { create_dossier(construction_date: 3.months.ago, instruction_date: 2.months.ago, processed_date: 2.months.ago) }
2020-07-15 11:08:15 +02:00
it 'ignores dossiers older than 1 month' do
expect(procedure.usual_traitement_time).to be_within(1.hour).of(2.days)
end
end
context 'when there is a dossier with bad data' do
let(:delays) { [2.days, 2.days] }
let!(:bad_dossier) { create_dossier(construction_date: nil, instruction_date: nil, processed_date: 10.days.ago) }
2020-07-15 11:08:15 +02:00
it 'ignores bad dossiers' do
expect(procedure.usual_traitement_time).to be_within(1.hour).of(2.days)
end
end
2020-07-15 11:08:15 +02:00
context 'when there is only one processed dossier' do
let(:delays) { [1.day] }
it { expect(procedure.usual_traitement_time).to be_within(1.hour).of(1.day) }
end
2020-07-15 11:08:15 +02:00
context 'where there is no processed dossier' do
let(:delays) { [] }
it { expect(procedure.usual_traitement_time).to be_nil }
end
end
2019-03-20 14:27:30 +01:00
describe '.ensure_a_groupe_instructeur_exists' do
let!(:procedure) { create(:procedure) }
it { expect(procedure.groupe_instructeurs.count).to eq(1) }
it { expect(procedure.groupe_instructeurs.first.label).to eq(GroupeInstructeur::DEFAULT_LABEL) }
end
2019-08-21 13:53:53 +02:00
describe '.missing_instructeurs?' do
let!(:procedure) { create(:procedure) }
subject { procedure.missing_instructeurs? }
it { is_expected.to be true }
context 'when an instructeur is assign to this procedure' do
let!(:instructeur) { create(:instructeur) }
before { instructeur.assign_to_procedure(procedure) }
it { is_expected.to be false }
end
end
describe "#dossiers_count_for_instructeur" do
let(:instructeur) { create(:instructeur) }
let(:procedure) { create(:procedure, instructeurs: [instructeur]) }
let(:gi_2) { procedure.groupe_instructeurs.create(label: '2') }
let(:gi_3) { procedure.groupe_instructeurs.create(label: '3') }
subject do
procedure.dossiers_count_for_instructeur(instructeur)
end
context "when logged in, and belonging to gi_1, gi_2" do
before do
instructeur.groupe_instructeurs << gi_2
end
context "without any dossier" do
it { expect(subject['a_suivre']).to eq(0) }
it { expect(subject['suivis']).to eq(0) }
it { expect(subject['termines']).to eq(0) }
it { expect(subject['total']).to eq(0) }
it { expect(subject['archived']).to eq(0) }
end
context 'with a new brouillon dossier' do
let!(:brouillon_dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:brouillon)) }
it { expect(subject['a_suivre']).to eq(0) }
it { expect(subject['suivis']).to eq(0) }
it { expect(subject['termines']).to eq(0) }
it { expect(subject['total']).to eq(0) }
it { expect(subject['archived']).to eq(0) }
end
context 'with a new dossier without follower' do
let!(:new_unfollow_dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) }
it { expect(subject['a_suivre']).to eq(1) }
it { expect(subject['suivis']).to eq(0) }
it { expect(subject['termines']).to eq(0) }
it { expect(subject['total']).to eq(1) }
it { expect(subject['archived']).to eq(0) }
context 'and dossiers without follower on each of the others groups' do
let!(:new_unfollow_dossier_on_gi_2) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:en_instruction)) }
let!(:new_unfollow_dossier_on_gi_3) { create(:dossier, groupe_instructeur: gi_3, state: Dossier.states.fetch(:en_instruction)) }
before { subject }
it { expect(subject['a_suivre']).to eq(2) }
it { expect(subject['total']).to eq(2) }
end
end
context 'with a new dossier with a follower' do
let!(:new_followed_dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) }
before do
instructeur.followed_dossiers << new_followed_dossier
end
it { expect(subject['a_suivre']).to eq(0) }
it { expect(subject['suivis']).to eq(1) }
it { expect(subject['termines']).to eq(0) }
it { expect(subject['total']).to eq(1) }
it { expect(subject['archived']).to eq(0) }
context 'and dossier with a follower on each of the others groups' do
let!(:new_follow_dossier_on_gi_2) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:en_instruction)) }
let!(:new_follow_dossier_on_gi_3) { create(:dossier, groupe_instructeur: gi_3, state: Dossier.states.fetch(:en_instruction)) }
before do
instructeur.followed_dossiers << new_follow_dossier_on_gi_2 << new_follow_dossier_on_gi_3
end
# followed dossiers on another groupe should not be displayed
it { expect(subject['suivis']).to eq(2) }
it { expect(subject['total']).to eq(2) }
end
context 'and dossier with a follower is unfollowed' do
before do
instructeur.unfollow(new_followed_dossier)
end
it { expect(subject['a_suivre']).to eq(1) }
it { expect(subject['suivis']).to eq(0) }
it { expect(subject['total']).to eq(1) }
end
end
context 'with a termine dossier' do
let!(:termine_dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:accepte)) }
it { expect(subject['a_suivre']).to eq(0) }
it { expect(subject['suivis']).to eq(0) }
it { expect(subject['termines']).to eq(1) }
it { expect(subject['total']).to eq(1) }
it { expect(subject['archived']).to eq(0) }
context 'and terminer dossiers on each of the others groups' do
let!(:termine_dossier_on_gi_2) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:accepte)) }
let!(:termine_dossier_on_gi_3) { create(:dossier, groupe_instructeur: gi_3, state: Dossier.states.fetch(:accepte)) }
before { subject }
it { expect(subject['a_suivre']).to eq(0) }
it { expect(subject['suivis']).to eq(0) }
it { expect(subject['termines']).to eq(2) }
it { expect(subject['total']).to eq(2) }
it { expect(subject['archived']).to eq(0) }
end
end
context 'with an archived dossier' do
let!(:archived_dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction), archived: true) }
it { expect(subject['a_suivre']).to eq(0) }
it { expect(subject['suivis']).to eq(0) }
it { expect(subject['termines']).to eq(0) }
it { expect(subject['total']).to eq(0) }
it { expect(subject['archived']).to eq(1) }
context 'and terminer dossiers on each of the others groups' do
let!(:archived_dossier_on_gi_2) { create(:dossier, groupe_instructeur: gi_2, state: Dossier.states.fetch(:en_instruction), archived: true) }
let!(:archived_dossier_on_gi_3) { create(:dossier, groupe_instructeur: gi_3, state: Dossier.states.fetch(:en_instruction), archived: true) }
it { expect(subject['archived']).to eq(2) }
end
end
end
end
end