feat: fait vivre les filtres d'analyse dans l'URL
Les filtres des pages Dépenses et Recettes n'existaient que dans l'état du composant : recharger la page les perdait, et une vue filtrée ne pouvait ni se partager, ni se mettre en signet, ni servir de destination à un lien. Chaque page déclare desormais comment ses filtres se lisent et s'écrivent dans la query (utils/filtresUrl.js). Ce qui vaut sa valeur par défaut n'est pas écrit : l'URL ne porte que ce qui a été choisi, et reste lisible. Ce qui en arrive est validé — un identifiant qui n'est pas un entier ou une date au mauvais format est ignoré plutôt qu'affiché de travers. Le changement de filtre remplace l'entrée d'historique au lieu d'en empiler une : le bouton Retour du navigateur quitte la page, il ne défait pas les filtres un par un. Côté Dépenses, la requête API dérive de cette même écriture : les paramètres sont les mêmes des deux côtés, la vue et la requête ne peuvent plus diverger. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
99
frontend/tests/filtresUrl.test.js
Normal file
99
frontend/tests/filtresUrl.test.js
Normal file
@@ -0,0 +1,99 @@
|
||||
// Les filtres d'une page d'analyse transitent par son URL. Deux exigences :
|
||||
// ce qu'on relit doit etre ce qu'on a choisi, et une query fabriquee a la main
|
||||
// ne doit jamais produire une vue incoherente.
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import {
|
||||
SCHEMA_DEPENSES,
|
||||
SCHEMA_REVENUS,
|
||||
ecrireFiltres,
|
||||
lireFiltres,
|
||||
} from '../src/utils/filtresUrl.js'
|
||||
|
||||
describe('filtres de la page Depenses', () => {
|
||||
it('rend une URL vide quand rien n est filtre', () => {
|
||||
const filtres = lireFiltres({}, SCHEMA_DEPENSES)
|
||||
|
||||
expect(filtres).toEqual({
|
||||
immeuble_id: null,
|
||||
lot_id: null,
|
||||
categorie: null,
|
||||
tag_id: null,
|
||||
fournisseurs: [],
|
||||
date_debut: null,
|
||||
date_fin: null,
|
||||
})
|
||||
expect(ecrireFiltres(filtres, SCHEMA_DEPENSES)).toEqual({})
|
||||
})
|
||||
|
||||
it('retrouve a l identique les filtres qu il a ecrits', () => {
|
||||
const choisis = {
|
||||
immeuble_id: 3,
|
||||
lot_id: 12,
|
||||
categorie: 'TRAVAUX',
|
||||
tag_id: 7,
|
||||
fournisseurs: ['PPR', 'MAILLET'],
|
||||
date_debut: '2026-01-01',
|
||||
date_fin: '2026-06-30',
|
||||
}
|
||||
|
||||
const query = ecrireFiltres(choisis, SCHEMA_DEPENSES)
|
||||
|
||||
expect(query.fournisseur).toEqual(['PPR', 'MAILLET'])
|
||||
expect(lireFiltres(query, SCHEMA_DEPENSES)).toEqual(choisis)
|
||||
})
|
||||
|
||||
it('garde « sans tag » qui vaut zero, la ou l absence de filtre vaut null', () => {
|
||||
// Le piege du filtre tag : 0 est un choix, pas une case vide.
|
||||
expect(lireFiltres({ tag_id: '0' }, SCHEMA_DEPENSES).tag_id).toBe(0)
|
||||
expect(ecrireFiltres({ tag_id: 0 }, SCHEMA_DEPENSES)).toEqual({ tag_id: '0' })
|
||||
expect(ecrireFiltres({ tag_id: null }, SCHEMA_DEPENSES)).toEqual({})
|
||||
})
|
||||
|
||||
it('accepte un fournisseur seul, que vue-router rend comme une chaine', () => {
|
||||
expect(lireFiltres({ fournisseur: 'PPR' }, SCHEMA_DEPENSES).fournisseurs).toEqual(['PPR'])
|
||||
})
|
||||
|
||||
it('ignore une valeur qui n a pas de sens plutot que d afficher de travers', () => {
|
||||
const filtres = lireFiltres(
|
||||
{ immeuble_id: 'abc', tag_id: '3.5', date_debut: '01/02/2026', fournisseur: '' },
|
||||
SCHEMA_DEPENSES
|
||||
)
|
||||
|
||||
expect(filtres.immeuble_id).toBeNull()
|
||||
expect(filtres.tag_id).toBeNull()
|
||||
expect(filtres.date_debut).toBeNull()
|
||||
expect(filtres.fournisseurs).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('filtres de la page Recettes', () => {
|
||||
it('n ecrit pas l historique quand il vaut sa valeur par defaut', () => {
|
||||
expect(ecrireFiltres(lireFiltres({}, SCHEMA_REVENUS), SCHEMA_REVENUS)).toEqual({})
|
||||
expect(lireFiltres({}, SCHEMA_REVENUS).months).toBe(12)
|
||||
})
|
||||
|
||||
it('retrouve a l identique les filtres qu il a ecrits', () => {
|
||||
const choisis = {
|
||||
immeuble_id: 2,
|
||||
type_ligne: 'loyer',
|
||||
date_debut: '2026-01-01',
|
||||
date_fin: null,
|
||||
impayes_only: true,
|
||||
months: 24,
|
||||
}
|
||||
|
||||
expect(lireFiltres(ecrireFiltres(choisis, SCHEMA_REVENUS), SCHEMA_REVENUS)).toEqual(choisis)
|
||||
})
|
||||
|
||||
it('ramene un historique hors bornes a sa valeur par defaut', () => {
|
||||
expect(lireFiltres({ months: '999' }, SCHEMA_REVENUS).months).toBe(12)
|
||||
expect(lireFiltres({ months: '0' }, SCHEMA_REVENUS).months).toBe(12)
|
||||
})
|
||||
|
||||
it('ne retient « impayes uniquement » que sur un oui explicite', () => {
|
||||
expect(lireFiltres({ impayes_only: 'true' }, SCHEMA_REVENUS).impayes_only).toBe(true)
|
||||
expect(lireFiltres({ impayes_only: 'oui' }, SCHEMA_REVENUS).impayes_only).toBe(false)
|
||||
expect(ecrireFiltres({ impayes_only: false }, SCHEMA_REVENUS)).toEqual({})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user