2019-11-27-01 (#4581)

2019-11-27-01
This commit is contained in:
Pierre de La Morinerie 2019-11-27 12:20:54 +01:00 committed by GitHub
commit 5e3edb1233
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 141 additions and 91 deletions

View file

@ -163,8 +163,8 @@ class StatsController < ApplicationController
def contact_percentage def contact_percentage
number_of_months = 13 number_of_months = 13
from = Date.today.prev_month(number_of_months) from = Time.zone.today.prev_month(number_of_months)
to = Date.today.prev_month to = Time.zone.today.prev_month
adapter = Helpscout::UserConversationsAdapter.new(from, to) adapter = Helpscout::UserConversationsAdapter.new(from, to)
if !adapter.can_fetch_reports? if !adapter.can_fetch_reports?

View file

@ -155,7 +155,7 @@ module Users
respond_to do |format| respond_to do |format|
format.html { render :brouillon } format.html { render :brouillon }
format.json { head :ok } format.json { render json: {}, status: :ok }
end end
end end

View file

@ -18,7 +18,7 @@ module CommentaireHelper
end end
def commentaire_date(commentaire) def commentaire_date(commentaire)
is_current_year = (commentaire.created_at.year == Date.current.year) is_current_year = (commentaire.created_at.year == Time.zone.today.year)
template = is_current_year ? :message_date : :message_date_with_year template = is_current_year ? :message_date : :message_date_with_year
I18n.l(commentaire.created_at, format: template) I18n.l(commentaire.created_at, format: template)
end end

View file

@ -12,12 +12,7 @@ function TypeDeChamps({ state: rootState, typeDeChamps }) {
typeDeChamps typeDeChamps
}); });
if (state.typeDeChamps.length === 0) { const hasUnsavedChamps = state.typeDeChamps.some(tdc => tdc.id == undefined);
dispatch({
type: 'addFirstTypeDeChamp',
done: () => dispatch({ type: 'refresh' })
});
}
return ( return (
<div className="champs-editor"> <div className="champs-editor">
@ -39,10 +34,18 @@ function TypeDeChamps({ state: rootState, typeDeChamps }) {
/> />
))} ))}
</SortableContainer> </SortableContainer>
{state.typeDeChamps.length === 0 && (
<h2>
<FontAwesomeIcon icon="arrow-circle-down" />
&nbsp;&nbsp;Cliquez sur le bouton «&nbsp;Ajouter un champ&nbsp;» pour
créer votre premier champ.
</h2>
)}
<div className="footer">&nbsp;</div> <div className="footer">&nbsp;</div>
<div className="buttons"> <div className="buttons">
<button <button
className="button" className="button"
disabled={hasUnsavedChamps}
onClick={() => onClick={() =>
dispatch({ dispatch({
type: 'addNewTypeDeChamp', type: 'addNewTypeDeChamp',

View file

@ -5,6 +5,7 @@ import {
faArrowDown, faArrowDown,
faArrowsAltV, faArrowsAltV,
faArrowUp, faArrowUp,
faArrowCircleDown,
faPlus, faPlus,
faTrash faTrash
} from '@fortawesome/free-solid-svg-icons'; } from '@fortawesome/free-solid-svg-icons';
@ -13,7 +14,14 @@ import Flash from './Flash';
import OperationsQueue from './OperationsQueue'; import OperationsQueue from './OperationsQueue';
import TypeDeChamps from './components/TypeDeChamps'; import TypeDeChamps from './components/TypeDeChamps';
library.add(faArrowDown, faArrowsAltV, faArrowUp, faPlus, faTrash); library.add(
faArrowDown,
faArrowsAltV,
faArrowUp,
faArrowCircleDown,
faPlus,
faTrash
);
class TypesDeChampEditor extends Component { class TypesDeChampEditor extends Component {
constructor(props) { constructor(props) {

View file

@ -11,8 +11,6 @@ export default function typeDeChampsReducer(state, { type, params, done }) {
switch (type) { switch (type) {
case 'addNewTypeDeChamp': case 'addNewTypeDeChamp':
return addNewTypeDeChamp(state, state.typeDeChamps, done); return addNewTypeDeChamp(state, state.typeDeChamps, done);
case 'addFirstTypeDeChamp':
return addFirstTypeDeChamp(state, state.typeDeChamps, done);
case 'addNewRepetitionTypeDeChamp': case 'addNewRepetitionTypeDeChamp':
return addNewRepetitionTypeDeChamp( return addNewRepetitionTypeDeChamp(
state, state,
@ -98,19 +96,6 @@ function addNewRepetitionTypeDeChamp(state, typeDeChamps, typeDeChamp, done) {
); );
} }
function addFirstTypeDeChamp(state, typeDeChamps, done) {
const typeDeChamp = { ...state.defaultTypeDeChampAttributes, order_place: 0 };
createTypeDeChampOperation(typeDeChamp, state.queue)
.then(() => done())
.catch(message => state.flash.error(message));
return {
...state,
typeDeChamps: [...typeDeChamps, typeDeChamp]
};
}
function updateTypeDeChamp( function updateTypeDeChamp(
state, state,
typeDeChamps, typeDeChamps,
@ -223,10 +208,14 @@ function getUpdateHandler(typeDeChamp, { queue, flash }) {
function findItemToInsertAfter() { function findItemToInsertAfter() {
const target = getLastVisibleTypeDeChamp(); const target = getLastVisibleTypeDeChamp();
return { if (target) {
target, return {
index: parseInt(target.dataset.index) + 1 target,
}; index: parseInt(target.dataset.index) + 1
};
} else {
return null;
}
} }
function getLastVisibleTypeDeChamp() { function getLastVisibleTypeDeChamp() {

View file

@ -37,6 +37,7 @@ export default class AutosaveController {
const fetchOptions = { const fetchOptions = {
method: form.method, method: form.method,
body: formData, body: formData,
credentials: 'same-origin',
headers: { Accept: 'application/json' } headers: { Accept: 'application/json' }
}; };
@ -61,7 +62,7 @@ export default class AutosaveController {
// exclude them from the draft (by disabling them). // exclude them from the draft (by disabling them).
// (Also Safari has issue with FormData containing empty file inputs) // (Also Safari has issue with FormData containing empty file inputs)
const fileInputs = form.querySelectorAll( const fileInputs = form.querySelectorAll(
'input[type="file"]:not([disabled])' 'input[type="file"]:not([disabled]), .editable-champ-piece_justificative input:not([disabled])'
); );
fileInputs.forEach(fileInput => (fileInput.disabled = true)); fileInputs.forEach(fileInput => (fileInput.disabled = true));

View file

@ -19,7 +19,7 @@ const autosaveController = new AutosaveController();
// Whenever a 'change' event is triggered on one of the form inputs, try to autosave. // Whenever a 'change' event is triggered on one of the form inputs, try to autosave.
const formSelector = 'form#dossier-edit-form.autosave-enabled'; const formSelector = 'form#dossier-edit-form.autosave-enabled';
const formInputsSelector = `${formSelector} input, ${formSelector} select, ${formSelector} textarea`; const formInputsSelector = `${formSelector} input:not([type=input]), ${formSelector} select, ${formSelector} textarea`;
delegate( delegate(
'change', 'change',

View file

@ -3,6 +3,7 @@ import Turbolinks from 'turbolinks';
import Rails from '@rails/ujs'; import Rails from '@rails/ujs';
import * as ActiveStorage from '@rails/activestorage'; import * as ActiveStorage from '@rails/activestorage';
import '@rails/actiontext'; import '@rails/actiontext';
import 'whatwg-fetch'; // window.fetch polyfill
import Chartkick from 'chartkick'; import Chartkick from 'chartkick';
import Highcharts from 'highcharts'; import Highcharts from 'highcharts';

View file

@ -2,7 +2,7 @@ class AutoArchiveProcedureJob < ApplicationJob
queue_as :cron queue_as :cron
def perform(*args) def perform(*args)
Procedure.publiees.where("auto_archive_on <= ?", Date.today).each do |procedure| Procedure.publiees.where("auto_archive_on <= ?", Time.zone.today).each do |procedure|
procedure procedure
.dossiers .dossiers
.state_en_construction .state_en_construction

View file

@ -35,7 +35,7 @@ class Helpscout::UserConversationsAdapter
end end
def fetch_productivity_report(year, month) def fetch_productivity_report(year, month)
if year == Date.today.year && month == Date.today.month if year == Time.zone.today.year && month == Time.zone.today.month
raise ArgumentError, 'The report for the current month will change in the future, and cannot be cached.' raise ArgumentError, 'The report for the current month will change in the future, and cannot be cached.'
end end

View file

@ -6,11 +6,11 @@ class Champs::DateChamp < Champ
end end
def to_s def to_s
value.present? ? I18n.l(Date.parse(value)) : "" value.present? ? I18n.l(Time.zone.parse(value), format: '%d %B %Y') : ""
end end
def for_tag def for_tag
value.present? ? I18n.l(Date.parse(value)) : "" value.present? ? I18n.l(Time.zone.parse(value), format: '%d %B %Y') : ""
end end
private private
@ -18,7 +18,7 @@ class Champs::DateChamp < Champ
def format_before_save def format_before_save
self.value = self.value =
begin begin
Date.parse(value).iso8601 Time.zone.parse(value).to_date.iso8601
rescue rescue
nil nil
end end

View file

@ -32,7 +32,8 @@
"react_ujs": "^2.6.0", "react_ujs": "^2.6.0",
"select2": "^4.0.11", "select2": "^4.0.11",
"trix": "^1.2.1", "trix": "^1.2.1",
"turbolinks": "^5.2.0" "turbolinks": "^5.2.0",
"whatwg-fetch": "^3.0.0"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^10.0.3", "babel-eslint": "^10.0.3",

View file

@ -107,7 +107,7 @@ describe FranceConnect::ParticulierController, type: :controller do
before { subject } before { subject }
it { expect(stored_fci).to have_attributes(user_info.merge(birthdate: Date.parse(birthdate))) } it { expect(stored_fci).to have_attributes(user_info.merge(birthdate: Time.zone.parse(birthdate).to_datetime)) }
end end
it { is_expected.to redirect_to(root_path) } it { is_expected.to redirect_to(root_path) }

View file

@ -69,14 +69,12 @@ feature 'As an administrateur I wanna create a new procedure', js: true do
page.refresh page.refresh
expect(page).to have_current_path(champs_procedure_path(Procedure.last)) expect(page).to have_current_path(champs_procedure_path(Procedure.last))
expect(page).to have_selector('#champ-0-libelle') add_champ(remove_flash_message: true)
fill_in 'champ-0-libelle', with: 'libelle de champ' fill_in 'champ-0-libelle', with: 'libelle de champ'
blur blur
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')
within '.buttons' do add_champ
click_on 'Ajouter un champ'
end
expect(page).to have_selector('#champ-1-libelle') expect(page).to have_selector('#champ-1-libelle')
click_on Procedure.last.libelle click_on Procedure.last.libelle
@ -91,6 +89,7 @@ feature 'As an administrateur I wanna create a new procedure', js: true do
scenario 'After adding champ and file, make publication' do scenario 'After adding champ and file, make publication' do
page.refresh page.refresh
add_champ(remove_flash_message: true)
fill_in 'champ-0-libelle', with: 'libelle de champ' fill_in 'champ-0-libelle', with: 'libelle de champ'
blur blur
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')

View file

@ -10,14 +10,8 @@ feature 'As an administrateur I can edit types de champ', js: true do
end end
it "Add a new champ" do it "Add a new champ" do
page.accept_alert do add_champ
click_on 'Supprimer'
end
within '.buttons' do
click_on 'Ajouter un champ'
end
expect(page).to have_selector('#champ-0-libelle')
fill_in 'champ-0-libelle', with: 'libellé de champ' fill_in 'champ-0-libelle', with: 'libellé de champ'
blur blur
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')
@ -26,65 +20,64 @@ feature 'As an administrateur I can edit types de champ', js: true do
within '.buttons' do within '.buttons' do
click_on 'Enregistrer' click_on 'Enregistrer'
end end
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')
end end
it "Add multiple champs" do it "Add multiple champs" do
within '.buttons' do # Champs are created when clicking the 'Add field' button
click_on 'Ajouter un champ' add_champs(count: 3)
click_on 'Ajouter un champ'
click_on 'Ajouter un champ'
end
page.refresh
# Champs are automatically saved
expect(page).to have_button('Ajouter un champ', disabled: false)
page.refresh
expect(page).to have_selector('.type-de-champ', count: 3)
# Multiple champs can be edited
fill_in 'champ-0-libelle', with: 'libellé de champ 0' fill_in 'champ-0-libelle', with: 'libellé de champ 0'
fill_in 'champ-1-libelle', with: 'libellé de champ 1' fill_in 'champ-1-libelle', with: 'libellé de champ 1'
blur blur
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')
expect(page).to have_selector('#champ-0-libelle') # Champs can be deleted
expect(page).to have_selector('#champ-1-libelle')
expect(page).to have_selector('#champ-2-libelle')
expect(page).to have_selector('#champ-3-libelle')
within '.type-de-champ[data-index="2"]' do within '.type-de-champ[data-index="2"]' do
page.accept_alert do page.accept_alert do
click_on 'Supprimer' click_on 'Supprimer'
end end
end end
expect(page).not_to have_selector('#champ-2-libelle')
expect(page).not_to have_selector('#champ-3-libelle') fill_in 'champ-1-libelle', with: 'edited libellé de champ 1'
fill_in 'champ-2-libelle', with: 'libellé de champ 2'
blur blur
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')
expect(page).to have_content('Supprimer', count: 2)
expect(page).to have_content('Supprimer', count: 3)
page.refresh page.refresh
expect(page).to have_content('Supprimer', count: 2)
expect(page).to have_content('Supprimer', count: 3)
end end
it "Remove champs" do it "Remove champs" do
add_champ(remove_flash_message: true)
fill_in 'champ-0-libelle', with: 'libellé de champ' fill_in 'champ-0-libelle', with: 'libellé de champ'
blur blur
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')
page.refresh page.refresh
page.accept_alert do page.accept_alert do
click_on 'Supprimer' click_on 'Supprimer'
end end
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')
expect(page).to have_content('Supprimer', count: 1) expect(page).to have_content('Supprimer', count: 0)
page.refresh page.refresh
expect(page).to have_content('Supprimer', count: 1) expect(page).to have_content('Supprimer', count: 0)
end end
it "Only add valid champs" do it "Only add valid champs" do
expect(page).to have_selector('#champ-0-description') add_champ(remove_flash_message: true)
fill_in 'champ-0-libelle', with: '' fill_in 'champ-0-libelle', with: ''
fill_in 'champ-0-description', with: 'déscription du champ' fill_in 'champ-0-description', with: 'description du champ'
blur blur
expect(page).not_to have_content('Formulaire enregistré') expect(page).not_to have_content('Formulaire enregistré')
@ -94,7 +87,8 @@ feature 'As an administrateur I can edit types de champ', js: true do
end end
it "Add repetition champ" do it "Add repetition champ" do
expect(page).to have_selector('#champ-0-libelle') add_champ(remove_flash_message: true)
select('Bloc répétable', from: 'champ-0-type_champ') select('Bloc répétable', from: 'champ-0-type_champ')
fill_in 'champ-0-libelle', with: 'libellé de champ' fill_in 'champ-0-libelle', with: 'libellé de champ'
blur blur
@ -124,6 +118,8 @@ feature 'As an administrateur I can edit types de champ', js: true do
end end
it "Add carte champ" do it "Add carte champ" do
add_champ
select('Carte', from: 'champ-0-type_champ') select('Carte', from: 'champ-0-type_champ')
fill_in 'champ-0-libelle', with: 'Libellé de champ carte', fill_options: { clear: :backspace } fill_in 'champ-0-libelle', with: 'Libellé de champ carte', fill_options: { clear: :backspace }
check 'Quartiers prioritaires' check 'Quartiers prioritaires'
@ -140,6 +136,8 @@ feature 'As an administrateur I can edit types de champ', js: true do
end end
it "Add dropdown champ" do it "Add dropdown champ" do
add_champ
select('Menu déroulant', from: 'champ-0-type_champ') select('Menu déroulant', from: 'champ-0-type_champ')
fill_in 'champ-0-libelle', with: 'Libellé de champ menu déroulant', fill_options: { clear: :backspace } fill_in 'champ-0-libelle', with: 'Libellé de champ menu déroulant', fill_options: { clear: :backspace }
fill_in 'champ-0-drop_down_list_value', with: 'Un menu', fill_options: { clear: :backspace } fill_in 'champ-0-drop_down_list_value', with: 'Un menu', fill_options: { clear: :backspace }

View file

@ -34,7 +34,7 @@ feature 'Signin in:' do
scenario 'an existing user can sign-in and fill the procedure' do scenario 'an existing user can sign-in and fill the procedure' do
click_on 'Jai déjà un compte' click_on 'Jai déjà un compte'
expect(page).to have_current_path new_user_session_path expect(page).to have_current_path new_user_session_path
expect_page_to_have_procedure_description(procedure) expect(page).to have_procedure_description(procedure)
sign_in_with user.email, password sign_in_with user.email, password
@ -42,7 +42,7 @@ feature 'Signin in:' do
click_on 'Commencer la démarche' click_on 'Commencer la démarche'
expect(page).to have_current_path identite_dossier_path(user.reload.dossiers.last) expect(page).to have_current_path identite_dossier_path(user.reload.dossiers.last)
expect_page_to_have_procedure_description(procedure) expect(page).to have_procedure_description(procedure)
expect(page).to have_content "Données d'identité" expect(page).to have_content "Données d'identité"
end end
end end

View file

@ -20,7 +20,7 @@ feature 'Creating a new dossier:' do
click_on 'Commencer la démarche' click_on 'Commencer la démarche'
expect(page).to have_current_path identite_dossier_path(user.reload.dossiers.last) expect(page).to have_current_path identite_dossier_path(user.reload.dossiers.last)
expect_page_to_have_procedure_description(procedure) expect(page).to have_procedure_description(procedure)
fill_in 'individual_nom', with: 'Nom' fill_in 'individual_nom', with: 'Nom'
fill_in 'individual_prenom', with: 'Prenom' fill_in 'individual_prenom', with: 'Prenom'
@ -82,7 +82,7 @@ feature 'Creating a new dossier:' do
click_on 'Commencer la démarche' click_on 'Commencer la démarche'
expect(page).to have_current_path siret_dossier_path(dossier) expect(page).to have_current_path siret_dossier_path(dossier)
expect_page_to_have_procedure_description(procedure) expect(page).to have_procedure_description(procedure)
fill_in 'Numéro SIRET', with: siret fill_in 'Numéro SIRET', with: siret
click_on 'Valider' click_on 'Valider'
@ -99,7 +99,7 @@ feature 'Creating a new dossier:' do
click_on 'Commencer la démarche' click_on 'Commencer la démarche'
expect(page).to have_current_path(siret_dossier_path(dossier)) expect(page).to have_current_path(siret_dossier_path(dossier))
expect_page_to_have_procedure_description(procedure) expect(page).to have_procedure_description(procedure)
fill_in 'Numéro SIRET', with: '0000' fill_in 'Numéro SIRET', with: '0000'
click_on 'Valider' click_on 'Valider'

View file

@ -42,7 +42,7 @@ feature 'Signing up:' do
scenario 'a new user can sign-up and fill the procedure' do scenario 'a new user can sign-up and fill the procedure' do
click_on 'Créer un compte' click_on 'Créer un compte'
expect(page).to have_current_path new_user_registration_path expect(page).to have_current_path new_user_registration_path
expect_page_to_have_procedure_description(procedure) expect(page).to have_procedure_description(procedure)
sign_up_with user_email, user_password sign_up_with user_email, user_password
expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}" expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}"
@ -54,7 +54,7 @@ feature 'Signing up:' do
click_on 'Commencer la démarche' click_on 'Commencer la démarche'
expect(page).to have_current_path identite_dossier_path(procedure.reload.dossiers.last) expect(page).to have_current_path identite_dossier_path(procedure.reload.dossiers.last)
expect_page_to_have_procedure_description(procedure) expect(page).to have_procedure_description(procedure)
end end
end end

View file

@ -3,7 +3,7 @@ require 'rails_helper'
RSpec.describe AutoArchiveProcedureJob, type: :job do RSpec.describe AutoArchiveProcedureJob, type: :job do
let!(:procedure) { create(:procedure, :published, :with_instructeur, auto_archive_on: nil) } let!(:procedure) { create(:procedure, :published, :with_instructeur, auto_archive_on: nil) }
let!(:procedure_hier) { create(:procedure, :published, :with_instructeur, auto_archive_on: 1.day.ago) } let!(:procedure_hier) { create(:procedure, :published, :with_instructeur, auto_archive_on: 1.day.ago) }
let!(:procedure_aujourdhui) { create(:procedure, :published, :with_instructeur, auto_archive_on: Date.today) } let!(:procedure_aujourdhui) { create(:procedure, :published, :with_instructeur, auto_archive_on: Time.zone.today) }
let!(:procedure_demain) { create(:procedure, :published, :with_instructeur, auto_archive_on: 1.day.from_now) } let!(:procedure_demain) { create(:procedure, :published, :with_instructeur, auto_archive_on: 1.day.from_now) }
subject { AutoArchiveProcedureJob.new.perform } subject { AutoArchiveProcedureJob.new.perform }

View file

@ -4,7 +4,7 @@ describe BillSignatureService do
describe ".grouped_unsigned_operation_until" do describe ".grouped_unsigned_operation_until" do
subject { BillSignatureService.grouped_unsigned_operation_until(date).length } subject { BillSignatureService.grouped_unsigned_operation_until(date).length }
let(:date) { Date.today } let(:date) { Time.zone.today }
context "when operations of several days need to be signed" do context "when operations of several days need to be signed" do
before do before do

View file

@ -33,7 +33,7 @@ describe FranceConnectService do
expect(subject).to have_attributes({ expect(subject).to have_attributes({
given_name: given_name, given_name: given_name,
family_name: family_name, family_name: family_name,
birthdate: Date.parse(birthdate), birthdate: Time.zone.parse(birthdate).to_date,
birthplace: birthplace, birthplace: birthplace,
gender: gender, gender: gender,
email_france_connect: email, email_france_connect: email,

View file

@ -55,14 +55,6 @@ module FeatureHelpers
visit "/users/confirmation?#{token_params}" visit "/users/confirmation?#{token_params}"
end end
def expect_page_to_have_procedure_description(procedure)
# Procedure context on the page
expect(page).to have_content(procedure.libelle)
expect(page).to have_content(procedure.description)
# Procedure contact infos in the footer
expect(page).to have_content(procedure.service.email)
end
def click_reset_password_link_for(email) def click_reset_password_link_for(email)
reset_password_email = open_email(email) reset_password_email = open_email(email)
token_params = reset_password_email.body.match(/reset_password_token=[^"]+/) token_params = reset_password_email.body.match(/reset_password_token=[^"]+/)
@ -70,6 +62,24 @@ module FeatureHelpers
visit "/users/password/edit?#{token_params}" visit "/users/password/edit?#{token_params}"
end end
# Add a new type de champ in the procedure editor
def add_champ(options = {})
add_champs(options)
end
# Add several new type de champ in the procedure editor
def add_champs(count: 1, remove_flash_message: false)
within '.buttons' do
count.times { click_on 'Ajouter un champ' }
end
if remove_flash_message
expect(page).to have_button('Ajouter un champ', disabled: false)
expect(page).to have_content('Formulaire enregistré')
execute_script("document.querySelector('#flash_message').remove();")
end
end
def blur def blur
page.find('body').click page.find('body').click
end end
@ -85,6 +95,32 @@ module FeatureHelpers
value value
end end
end end
# Keep the brower window open after a test success of failure, to
# allow inspecting the page or the console.
#
# Usage:
# 1. Disable the 'headless' mode in `spec_helper.rb`
# 2. Call `leave_browser_open` at the beginning of your scenario
def leave_browser_open
Selenium::WebDriver::Chrome::Service.class_eval do
def stop
STDOUT.puts "#{self.class}#stop is a no-op, because leave_browser_open is enabled"
end
end
Selenium::WebDriver::Driver.class_eval do
def quit
STDOUT.puts "#{self.class}#quit is a no-op, because leave_browser_open is enabled"
end
end
Capybara::Selenium::Driver.class_eval do
def reset!
STDOUT.puts "#{self.class}#reset! is a no-op, because leave_browser_open is enabled"
end
end
end
end end
RSpec.configure do |config| RSpec.configure do |config|

View file

@ -0,0 +1,9 @@
module Capybara
class Session
# Find the description of a procedure on the page
# Usage: expect(page).to have_procedure_description(procedure)
def has_procedure_description?(procedure)
has_content?(procedure.libelle) && has_content?(procedure.description) && has_content?(procedure.service.email)
end
end
end

View file

@ -8931,6 +8931,11 @@ websocket-extensions@>=0.1.1:
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29"
integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==
whatwg-fetch@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==
which-module@^1.0.0: which-module@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"