clean(spec): speed, avoid using with_all_champs factory. takes too much time when not needed

This commit is contained in:
mfo 2024-05-31 09:41:31 +02:00
parent f98517852f
commit f14c88a54a
7 changed files with 209 additions and 313 deletions

View file

@ -1006,7 +1006,6 @@ class Dossier < ApplicationRecord
else
columns << ['Entreprise raison sociale', etablissement&.entreprise_raison_sociale]
end
if procedure.chorusable? && procedure.chorus_configuration.complete?
columns += [
['Domaine Fonctionnel', procedure.chorus_configuration.domaine_fonctionnel&.fetch("code") { '' }],

View file

@ -16,24 +16,28 @@ describe Administrateurs::ProceduresController, type: :controller do
let(:tags) { "[\"planete\",\"environnement\"]" }
describe '#apercu' do
render_views
let(:procedure) { create(:procedure, :with_all_champs) }
subject { get :apercu, params: { id: procedure.id } }
before do
sign_in(admin.user)
end
it do
subject
expect(response).to have_http_status(:ok)
expect(procedure.dossiers.visible_by_user).to be_empty
expect(procedure.dossiers.for_procedure_preview).not_to be_empty
context 'all tdc can be rendered' do
render_views
let(:procedure) { create(:procedure, :with_all_champs) }
it do
subject
expect(response).to have_http_status(:ok)
expect(procedure.dossiers.visible_by_user).to be_empty
expect(procedure.dossiers.for_procedure_preview).not_to be_empty
end
end
context 'when the draft is invalid' do
let(:procedure) { create(:procedure) }
before do
allow_any_instance_of(ProcedureRevision).to receive(:invalid?).and_return(true)
end

View file

@ -1489,15 +1489,18 @@ describe Users::DossiersController, type: :controller do
end
describe '#clone' do
let(:procedure) { create(:procedure, :with_all_champs) }
let(:dossier) { create(:dossier, procedure: procedure) }
subject { post :clone, params: { id: dossier.id } }
context 'not signed in' do
let(:procedure) { create(:procedure) }
it { expect(subject).to redirect_to(new_user_session_path) }
end
context 'signed with user dossier' do
let(:procedure) { create(:procedure, :with_all_champs) }
before { sign_in dossier.user }
it { expect(subject).to redirect_to(brouillon_dossier_path(Dossier.last)) }

View file

@ -1,22 +0,0 @@
describe '20220705164551_remove_unused_champs' do
let(:rake_task) { Rake::Task['after_party:remove_unused_champs'] }
let(:procedure) { create(:procedure, :with_all_champs) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure: procedure) }
let(:champ_repetition) { dossier.champs_public.find(&:repetition?) }
subject(:run_task) do
dossier
rake_task.invoke
end
before { champ_repetition.champs.first.update(type_de_champ: create(:type_de_champ)) }
after { rake_task.reenable }
describe 'remove_unused_champs' do
it "with bad champs" do
expect(Champ.where(dossier: dossier).count).to eq(44)
run_task
expect(Champ.where(dossier: dossier).count).to eq(43)
end
end
end

View file

@ -2112,25 +2112,19 @@ describe Dossier, type: :model do
create(:attestation, dossier: dossier)
end
it "can destroy dossier" do
it "can destroy dossier, reset demarche, logg context" do
json_message = nil
allow(Rails.logger).to receive(:info) { json_message ||= _1 }
expect(dossier.destroy).to be_truthy
expect { dossier.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
it "can reset demarche" do
expect { dossier.procedure.reset! }.not_to raise_error
expect { dossier.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
it "call logger with context" do
json_message = nil
allow(Rails.logger).to receive(:info) { json_message ||= _1 }
dossier.destroy
expect(JSON.parse(json_message)).to a_hash_including(
{ message: "Dossier destroyed", dossier_id: dossier.id, procedure_id: procedure.id }.stringify_keys
)
expect { dossier.procedure.reset! }.not_to raise_error
expect { dossier.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end

View file

@ -2,7 +2,6 @@ require 'csv'
describe ProcedureExportService do
let(:instructeur) { create(:instructeur) }
let(:procedure) { create(:procedure, :published, :for_individual, :with_all_champs) }
let(:service) { ProcedureExportService.new(procedure, procedure.dossiers, instructeur, export_template) }
let(:export_template) { nil }
@ -18,159 +17,166 @@ describe ProcedureExportService do
let(:avis_sheet) { subject.sheets.third }
let(:repetition_sheet) { subject.sheets.fourth }
before do
# change one tdc place to check if the header is ordered
tdc_first = procedure.active_revision.revision_types_de_champ_public.first
tdc_last = procedure.active_revision.revision_types_de_champ_public.last
tdc_first.update(position: tdc_last.position + 1)
procedure.reload
end
describe 'sheets' do
let(:procedure) { create(:procedure) }
it 'should have a sheet for each record type' do
expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis'])
end
end
describe 'Dossiers sheet' do
let!(:dossier) { create(:dossier, :en_instruction, :with_populated_champs, :with_individual, procedure: procedure) }
context 'with all data for individual' do
let(:procedure) { create(:procedure, :published, :for_individual, :with_all_champs) }
let!(:dossier) { create(:dossier, :en_instruction, :with_populated_champs, :with_individual, procedure: procedure) }
let(:nominal_headers) do
[
"ID",
"Email",
"FranceConnect ?",
"Civilité",
"Nom",
"Prénom",
"Dépôt pour un tiers",
"Nom du mandataire",
"Prénom du mandataire",
"Archivé",
"État du dossier",
"Dernière mise à jour le",
"Dernière mise à jour du dossier le",
"Déposé le",
"Passé en instruction le",
"Traité le",
"Motivation de la décision",
"Instructeurs",
"textarea",
"date",
"datetime",
"number",
"decimal_number",
"integer_number",
"checkbox",
"civilite",
"email",
"phone",
"address",
"yes_no",
"simple_drop_down_list",
"multiple_drop_down_list",
"linked_drop_down_list",
"communes",
"communes (Code INSEE)",
"communes (Département)",
"departements",
"departements (Code)",
"regions",
"regions (Code)",
"pays",
"pays (Code)",
"dossier_link",
"piece_justificative",
"rna",
"carte",
"titre_identite",
"iban",
"siret",
"annuaire_education",
"cnaf",
"dgfip",
"pole_emploi",
"mesri",
"text",
"epci",
"epci (Code)",
"epci (Département)",
"cojo",
"expression_reguliere",
"rnf",
"rnf (Nom)",
"rnf (Adresse)",
"rnf (Code INSEE Ville)",
"rnf (Département)",
"engagement_juridique"
]
end
# before do
# # change one tdc place to check if the header is ordered
# tdc_first = procedure.active_revision.revision_types_de_champ_public.first
# tdc_last = procedure.active_revision.revision_types_de_champ_public.last
it 'should have headers' do
expect(dossiers_sheet.headers).to match_array(nominal_headers)
end
# tdc_first.update(position: tdc_last.position + 1)
# procedure.reload
# end
it 'should have data' do
expect(dossiers_sheet.data.size).to eq(1)
expect(etablissements_sheet.data.size).to eq(1)
let(:nominal_headers) do
[
"ID",
"Email",
"FranceConnect ?",
"Civilité",
"Nom",
"Prénom",
"Dépôt pour un tiers",
"Nom du mandataire",
"Prénom du mandataire",
"Archivé",
"État du dossier",
"Dernière mise à jour le",
"Dernière mise à jour du dossier le",
"Déposé le",
"Passé en instruction le",
"Traité le",
"Motivation de la décision",
"Instructeurs",
"textarea",
"date",
"datetime",
"number",
"decimal_number",
"integer_number",
"checkbox",
"civilite",
"email",
"phone",
"address",
"simple_drop_down_list",
"multiple_drop_down_list",
"linked_drop_down_list",
"communes",
"communes (Code INSEE)",
"communes (Département)",
"departements",
"departements (Code)",
"regions",
"regions (Code)",
"pays",
"pays (Code)",
"dossier_link",
"piece_justificative",
"rna",
"carte",
"titre_identite",
"iban",
"siret",
"annuaire_education",
"cnaf",
"dgfip",
"pole_emploi",
"mesri",
"text",
"epci",
"epci (Code)",
"epci (Département)",
"cojo",
"expression_reguliere",
"rnf",
"rnf (Nom)",
"rnf (Adresse)",
"rnf (Code INSEE Ville)",
"rnf (Département)",
"engagement_juridique",
"yes_no"
]
end
# SimpleXlsxReader is transforming datetimes in utc... It is only used in test so we just hack around.
offset = dossier.depose_at.utc_offset
depose_at = Time.zone.at(dossiers_sheet.data[0][13] - offset.seconds)
en_instruction_at = Time.zone.at(dossiers_sheet.data[0][14] - offset.seconds)
expect(dossiers_sheet.data.first.size).to eq(nominal_headers.size)
expect(depose_at).to eq(dossier.depose_at.round)
expect(en_instruction_at).to eq(dossier.en_instruction_at.round)
it 'should have data' do
expect(dossiers_sheet.headers).to match_array(nominal_headers)
expect(dossiers_sheet.data.size).to eq(1)
expect(etablissements_sheet.data.size).to eq(1)
# SimpleXlsxReader is transforming datetimes in utc... It is only used in test so we just hack around.
offset = dossier.depose_at.utc_offset
depose_at = Time.zone.at(dossiers_sheet.data[0][13] - offset.seconds)
en_instruction_at = Time.zone.at(dossiers_sheet.data[0][14] - offset.seconds)
expect(dossiers_sheet.data.first.size).to eq(nominal_headers.size)
expect(depose_at).to eq(dossier.depose_at.round)
expect(en_instruction_at).to eq(dossier.en_instruction_at.round)
end
end
context 'with a birthdate' do
before { procedure.update(ask_birthday: true) }
let(:procedure) { create(:procedure, :published, :for_individual, ask_birthday: true) }
let!(:dossier) { create(:dossier, :en_instruction, :with_individual, procedure:) }
let(:birthdate_headers) { nominal_headers.insert(nominal_headers.index('Archivé'), 'Date de naissance') }
it { expect(dossiers_sheet.headers).to match_array(birthdate_headers) }
it { expect(dossiers_sheet.data[0][dossiers_sheet.headers.index('Date de naissance')]).to be_a(Date) }
it 'find date de naissance' do
expect(dossiers_sheet.headers).to include('Date de naissance')
expect(dossiers_sheet.data[0][dossiers_sheet.headers.index('Date de naissance')]).to be_a(Date)
end
end
context 'with a procedure routee' do
before { create(:groupe_instructeur, label: '2', procedure: procedure) }
let(:procedure) { create(:procedure, :published, :for_individual) }
let!(:dossier) { create(:dossier, :en_instruction, :with_individual, procedure:) }
before { create(:groupe_instructeur, label: '2', procedure:) }
let(:routee_headers) { nominal_headers.insert(nominal_headers.index('textarea'), 'Groupe instructeur') }
it { expect(dossiers_sheet.headers).to match_array(routee_headers) }
it { expect(dossiers_sheet.data[0][dossiers_sheet.headers.index('Groupe instructeur')]).to eq('défaut') }
it 'find groupe instructeur data' do
expect(dossiers_sheet.headers).to include('Groupe instructeur')
expect(dossiers_sheet.data[0][dossiers_sheet.headers.index('Groupe instructeur')]).to eq('défaut')
end
end
context 'with a dossier having multiple pjs' do
let!(:dossier_2) { create(:dossier, :en_instruction, :with_populated_champs, :with_individual, procedure: procedure) }
let(:procedure) { create(:procedure, :published, :for_individual, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :piece_justificative }] }
let!(:dossier) { create(:dossier, :en_instruction, :with_populated_champs, :with_individual, procedure:) }
let!(:dossier_2) { create(:dossier, :en_instruction, :with_populated_champs, :with_individual, procedure:) }
before do
dossier_2.champs_public
.find { _1.is_a? Champs::PieceJustificativeChamp }
.piece_justificative_file
.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain")
end
it { expect(dossiers_sheet.data.first.size).to eq(nominal_headers.size) }
it { expect(dossiers_sheet.data.first.size).to eq(19) } # default number of header when procedure has only one champ
end
context 'with procedure chorus' do
let(:procedure) { create(:procedure, :published, :for_individual, :filled_chorus, :with_all_champs) }
let!(:dossier) { create(:dossier, :en_instruction, :with_populated_champs, procedure: procedure) }
before { expect_any_instance_of(Procedure).to receive(:chorusable?).and_return(true) }
let(:procedure) { create(:procedure, :published, :for_individual, :filled_chorus) }
let!(:dossier) { create(:dossier, :en_instruction, procedure: procedure) }
it 'includes chorus headers' do
expected_headers = [
'Domaine Fonctionnel',
'Référentiel De Programmation',
'Centre De Coup'
]
expect(dossiers_sheet.headers).to match_array(nominal_headers)
expect(dossiers_sheet.headers).to include('Domaine Fonctionnel')
expect(dossiers_sheet.headers).to include('Référentiel De Programmation')
expect(dossiers_sheet.headers).to include('Centre De Coût')
end
end
end
describe 'Etablissement sheet' do
let(:procedure) { create(:procedure, :published, :with_all_champs) }
let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :siret, libelle: 'siret' }] }
let!(:dossier) { create(:dossier, :en_instruction, :with_populated_champs, :with_entreprise, procedure: procedure) }
let(:dossier_etablissement) { etablissements_sheet.data[1] }
@ -191,54 +197,7 @@ describe ProcedureExportService do
"Traité le",
"Motivation de la décision",
"Instructeurs",
"textarea",
"date",
"datetime",
"number",
"decimal_number",
"integer_number",
"checkbox",
"civilite",
"email",
"phone",
"address",
"yes_no",
"simple_drop_down_list",
"multiple_drop_down_list",
"linked_drop_down_list",
"communes",
"communes (Code INSEE)",
"communes (Département)",
"departements",
"departements (Code)",
"regions",
"regions (Code)",
"pays",
"pays (Code)",
"dossier_link",
"piece_justificative",
"rna",
"carte",
"titre_identite",
"iban",
"siret",
"annuaire_education",
"cnaf",
"dgfip",
"pole_emploi",
"mesri",
"text",
"epci",
"epci (Code)",
"epci (Département)",
"cojo",
"expression_reguliere",
"rnf",
"rnf (Nom)",
"rnf (Adresse)",
"rnf (Code INSEE Ville)",
"rnf (Département)",
"engagement_juridique"
'siret'
]
end
@ -294,54 +253,7 @@ describe ProcedureExportService do
"Traité le",
"Motivation de la décision",
"Instructeurs",
"textarea",
"date",
"datetime",
"number",
"decimal_number",
"integer_number",
"checkbox",
"civilite",
"email",
"phone",
"address",
"yes_no",
"simple_drop_down_list",
"multiple_drop_down_list",
"linked_drop_down_list",
"communes",
"communes (Code INSEE)",
"communes (Département)",
"departements",
"departements (Code)",
"regions",
"regions (Code)",
"pays",
"pays (Code)",
"dossier_link",
"piece_justificative",
"rna",
"carte",
"titre_identite",
"iban",
"siret",
"annuaire_education",
"cnaf",
"dgfip",
"pole_emploi",
"mesri",
"text",
"epci",
"epci (Code)",
"epci (Département)",
"cojo",
"expression_reguliere",
"rnf",
"rnf (Nom)",
"rnf (Adresse)",
"rnf (Code INSEE Ville)",
"rnf (Département)",
"engagement_juridique"
'siret'
]
end
@ -352,7 +264,7 @@ describe ProcedureExportService do
end
end
it 'should have headers' do
it 'should have headers and data' do
expect(dossiers_sheet.headers).to match_array(nominal_headers)
expect(etablissements_sheet.headers).to eq([
@ -391,9 +303,7 @@ describe ProcedureExportService do
"Association date de déclaration",
"Association date de publication"
])
end
it 'should have data' do
expect(etablissements_sheet.data.size).to eq(2)
expect(dossier_etablissement[1]).to eq("Dossier")
expect(champ_etablissement[1]).to eq("siret")
@ -401,10 +311,11 @@ describe ProcedureExportService do
end
describe 'Avis sheet' do
let(:procedure) { create(:procedure, :published, :for_individual) }
let!(:dossier) { create(:dossier, :en_instruction, :with_populated_champs, :with_individual, procedure: procedure) }
let!(:avis) { create(:avis, :with_answer, dossier: dossier) }
it 'should have headers' do
it 'should have headers and data' do
expect(avis_sheet.headers).to eq([
"Dossier ID",
"Introduction",
@ -416,14 +327,20 @@ describe ProcedureExportService do
"Instructeur",
"Expert"
])
end
it 'should have data' do
expect(avis_sheet.data.size).to eq(1)
end
end
describe 'Repetitions sheet' do
before do
# change one tdc place to check if the header is ordered
tdc_first = procedure.active_revision.revision_types_de_champ_public.first
tdc_last = procedure.active_revision.revision_types_de_champ_public.last
tdc_first.update(position: tdc_last.position + 1)
procedure.reload
end
let(:procedure) { create(:procedure, :published, :for_individual, types_de_champ_public: [{ type: :repetition, children: [{ libelle: 'Nom' }, { libelle: 'Age' }] }]) }
let!(:dossiers) do
[
@ -509,6 +426,9 @@ describe ProcedureExportService do
end
describe 'to_zip' do
let(:procedure) { create(:procedure, :published, :for_individual, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :piece_justificative, libelle: 'piece_justificative' }] }
subject { service.to_zip }
context 'without files' do
it 'does not raises in_batches' do
@ -588,6 +508,9 @@ describe ProcedureExportService do
end
describe 'to_geo_json' do
let(:procedure) { create(:procedure, :published, :for_individual, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :carte }] }
subject do
service
.to_geo_json

View file

@ -1,33 +1,25 @@
describe 'wcag rules for usager', js: true do
let(:procedure) { create(:procedure, :published, :with_all_champs, :with_service, :for_individual) }
let(:procedure) { create(:procedure, :published, :with_service, :for_individual) }
let(:password) { 'a very complicated password' }
let(:litteraire_user) { create(:user, password: password) }
before do
procedure.active_revision.types_de_champ_public.find { |tdc| tdc.type_champ == TypeDeChamp.type_champs.fetch(:carte) }.destroy
end
def test_external_links_have_title_says_it_opens_in_a_new_tab
links = page.all("a[target=_blank]")
expect(links.count).to be_positive
shared_examples "external links have title says it opens in a new tab" do
it do
links = page.all("a[target=_blank]")
expect(links.count).to be_positive
links.each do |link|
expect(link[:title]).to include("Nouvel onglet"), "link #{link[:href]} does not have title mentioning it opens in a new tab"
end
links.each do |link|
expect(link[:title]).to include("Nouvel onglet"), "link #{link[:href]} does not have title mentioning it opens in a new tab"
end
end
shared_examples "aria-label do not mix with title attribute" do
it do
elements = page.all("[aria-label][title]")
elements.each do |element|
expect(element[:title]).to be_blank, "path=#{path}, element title=\"#{element[:title]}\" mixes aria-label and title attributes"
end
def test_aria_label_do_not_mix_with_title_attribute
elements = page.all("[aria-label][title]")
elements.each do |element|
expect(element[:title]).to be_blank, "path=#{path}, element title=\"#{element[:title]}\" mixes aria-label and title attributes"
end
end
def expect_axe_clean_without_main_navigation
def test_expect_axe_clean_without_main_navigation
# On page without main navigation content (like anonymous home page),
# there are either a bug in axe, either dsfr markup is not conform to wcag2a.
# There is no issue on pages having a child navigation.
@ -35,10 +27,6 @@ describe 'wcag rules for usager', js: true do
expect(page).to be_axe_clean.within("#modal-header__menu").skipping("aria-prohibited-attr")
end
shared_examples "axe clean without main navigation" do
it { expect_axe_clean_without_main_navigation }
end
context 'pages without the need to be logged in' do
before do
visit path
@ -46,16 +34,20 @@ describe 'wcag rules for usager', js: true do
context 'homepage' do
let(:path) { root_path }
it_behaves_like "axe clean without main navigation"
it_behaves_like "external links have title says it opens in a new tab"
it_behaves_like "aria-label do not mix with title attribute"
it 'pass wcag tests' do
test_external_links_have_title_says_it_opens_in_a_new_tab
test_aria_label_do_not_mix_with_title_attribute
test_expect_axe_clean_without_main_navigation
end
end
context 'sign_up page' do
let(:path) { new_user_registration_path }
it_behaves_like "axe clean without main navigation"
it_behaves_like "external links have title says it opens in a new tab"
it_behaves_like "aria-label do not mix with title attribute"
it 'pass wcag tests' do
test_external_links_have_title_says_it_opens_in_a_new_tab
test_aria_label_do_not_mix_with_title_attribute
test_expect_axe_clean_without_main_navigation
end
end
scenario 'account confirmation page' do
@ -66,43 +58,51 @@ describe 'wcag rules for usager', js: true do
perform_enqueued_jobs do
click_button 'Créer un compte'
expect_axe_clean_without_main_navigation
test_expect_axe_clean_without_main_navigation
end
end
context 'sign_up confirmation' do
let(:path) { user_confirmation_path("user[email]" => "some@email.com") }
it_behaves_like "external links have title says it opens in a new tab"
it_behaves_like "aria-label do not mix with title attribute"
it 'pass wcag tests' do
test_external_links_have_title_says_it_opens_in_a_new_tab
test_aria_label_do_not_mix_with_title_attribute
end
end
context 'sign_in page' do
let(:path) { new_user_session_path }
it_behaves_like "axe clean without main navigation"
it_behaves_like "external links have title says it opens in a new tab"
it_behaves_like "aria-label do not mix with title attribute"
it 'pass wcag tests' do
test_external_links_have_title_says_it_opens_in_a_new_tab
test_aria_label_do_not_mix_with_title_attribute
test_expect_axe_clean_without_main_navigation
end
end
context 'contact page' do
let(:path) { contact_path }
it_behaves_like "axe clean without main navigation"
it_behaves_like "external links have title says it opens in a new tab"
it_behaves_like "aria-label do not mix with title attribute"
it 'pass wcag tests' do
test_external_links_have_title_says_it_opens_in_a_new_tab
test_aria_label_do_not_mix_with_title_attribute
test_expect_axe_clean_without_main_navigation
end
end
context 'commencer page' do
let(:path) { commencer_path(path: procedure.path) }
it_behaves_like "axe clean without main navigation"
it_behaves_like "external links have title says it opens in a new tab"
it_behaves_like "aria-label do not mix with title attribute"
it 'pass wcag tests' do
test_external_links_have_title_says_it_opens_in_a_new_tab
test_aria_label_do_not_mix_with_title_attribute
test_expect_axe_clean_without_main_navigation
end
end
scenario 'commencer page, help dropdown' do
visit commencer_path(path: procedure.reload.path)
page.find("#help-menu_button").click
expect_axe_clean_without_main_navigation
test_expect_axe_clean_without_main_navigation
end
end
@ -135,7 +135,7 @@ describe 'wcag rules for usager', js: true do
end
context "logged in, depot d'un dossier entreprise" do
let(:procedure) { create(:procedure, :with_all_champs, :with_service, :published) }
let(:procedure) { create(:procedure, :with_service, :published) }
before do
login_as litteraire_user, scope: :user
@ -163,11 +163,6 @@ describe 'wcag rules for usager', js: true do
dossier
visit dossiers_path
expect(page).to be_axe_clean
end
scenario 'liste des dossiers et actions sur le dossier' do
dossier
visit dossiers_path
page.find("#actions_menu_dossier_#{dossier.id}_button").click
expect(page).to be_axe_clean
end