Extensions optionnelles du composant partagé, sans effet sur / et /agences : tri 'ordre' (ordre du tableau d'entrée) avec config.triDefaut et libellesTri, prop libellesVue (Graphe au lieu de Carte, Voir dans le graphe), adaptateur toMiniMot (kind 'mot'). 22 cas ajoutés à test-vue-fiches (80/80). Co-Authored-By: Claude Sonnet <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0136n5xMLHuaBDLcPJYCDjRW
248 lines
21 KiB
JavaScript
248 lines
21 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* Tests de la vue fiches (B11-M1) : logique pure de utils/vueFiches.ts et
|
||
* adaptateurs de composables/useFicheAdapter.ts, chargés tels quels via jiti
|
||
* (même patron que test-echelles-nav.mjs).
|
||
* Usage : node scripts/test-vue-fiches.mjs
|
||
*/
|
||
|
||
import { createJiti } from 'jiti'
|
||
import { fileURLToPath } from 'node:url'
|
||
import { dirname, join } from 'node:path'
|
||
|
||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||
const jiti = createJiti(import.meta.url)
|
||
const V = await jiti.import(join(__dirname, '..', 'utils', 'vueFiches.ts'))
|
||
const A = await jiti.import(join(__dirname, '..', 'composables', 'useFicheAdapter.ts'))
|
||
|
||
let n = 0
|
||
let fail = 0
|
||
function ok(cond, libelle, detail = '') {
|
||
n++
|
||
if (!cond) fail++
|
||
console.log(`${cond ? 'OK ' : 'FAIL'} ${libelle}${!cond && detail ? ` → ${detail}` : ''}`)
|
||
}
|
||
const trie = (o) => (o && typeof o === "object" && !Array.isArray(o) ? Object.fromEntries(Object.keys(o).sort().map((k) => [k, trie(o[k])])) : o)
|
||
const eq = (a, b) => JSON.stringify(trie(a)) === JSON.stringify(trie(b))
|
||
|
||
// ── Données : configuration Entraide, fiches adaptées depuis de vrais Org ──
|
||
const FONCTIONS = ['Juridique', 'Technique', 'Formation', 'Santé mentale']
|
||
const cfg = {
|
||
dimensions: [
|
||
{ cle: 'fonctions', libelle: 'Fonction', variante: 'fonction', valeurs: FONCTIONS.map((v) => ({ valeur: v, libelle: v })) },
|
||
{ cle: 'echelle', libelle: 'Échelle', variante: 'echelle', valeurs: ['National', 'Régional', 'Local'].map((v) => ({ valeur: v, libelle: v })) },
|
||
],
|
||
tris: ['pertinence', 'nom', 'recent'],
|
||
groupes: [
|
||
{ cle: 'fonction', libelle: 'Fonction', dimension: 'fonctions', sans: 'Sans fonction' },
|
||
{ cle: 'echelle', libelle: 'Échelle', dimension: 'echelle', sans: 'Sans échelle' },
|
||
{ cle: 'territoire', libelle: 'Territoire', dimension: 'territoire', sans: 'Sans territoire' },
|
||
],
|
||
etats: ['carte', 'mixte', 'fiches'],
|
||
sousVues: { parametre: 'mode', defaut: 'metropole', valeurs: [{ valeur: 'metropole', libelle: 'Métropole' }, { valeur: 'outremer', libelle: 'Outre-mer' }] },
|
||
}
|
||
|
||
const orgs = [
|
||
{ Id: 1, nom: 'CNOA', echelle: 'National', tags_fonction: 'Juridique', localisation_ville: 'Paris', latitude: 48.8, longitude: 2.3, description: "Ordre des architectes. Deuxième phrase." },
|
||
{ Id: 2, nom: 'Collectif Fil', echelle: 'Régional', tags_fonction: 'Formation,Juridique', localisation_ville: 'Nantes', latitude: 47.2, longitude: -1.5, description: 'Recherche-action en architecture.' },
|
||
{ Id: 3, nom: 'Écoute Archi', echelle: 'Local', tags_fonction: 'Santé mentale', localisation_ville: 'Fort-de-France', territoire: 'Martinique', latitude: null, longitude: null, description: 'Soutien psychologique.' },
|
||
{ Id: 4, nom: 'Bureau Technique', echelle: 'Régional', tags_fonction: 'Technique', localisation_ville: 'Lyon', latitude: 45.7, longitude: 4.8, submitted_at: '2026-09-01T10:00:00Z' },
|
||
{ Id: 5, nom: 'Atelier sans tag', localisation_ville: 'Rennes', latitude: 48.1, longitude: -1.6 },
|
||
]
|
||
const fiches = orgs.map(A.toMini)
|
||
|
||
const etat0 = (over = {}) => ({ ...V.lireQuery({}, cfg), ...over })
|
||
const ids = (fs) => fs.map((f) => f.id)
|
||
|
||
// ── Adaptateurs (M2) ──
|
||
ok(eq(fiches[1].etiquettes, { fonctions: ['Formation', 'Juridique'], echelle: ['Régional'], territoire: ['Métropole'] }), 'org → etiquettes par dimension (fonctions complètes, échelle, territoire)')
|
||
ok(fiches[2].etiquettes.territoire[0] === 'Martinique' && fiches[2].geoloc === false && fiches[2].coords === undefined, 'org DOM sans coordonnées → territoire Martinique, geoloc false, coords absentes')
|
||
ok(eq(fiches[0].coords, [48.8, 2.3]) && fiches[0].resume === 'Ordre des architectes.', 'org → coords et résumé (première phrase) inchangé')
|
||
ok(eq(fiches[1].chips, ['Formation', 'Juridique']) && fiches[1].chipsDimension === 'fonctions' && fiches[1].echelle === 'Régional', 'org → chips et echelle d’affichage inchangés')
|
||
const structure = A.toMini({
|
||
id: 'f1-rotor', nom: 'Rotor', url: '', pays: 'BE', ville: 'Bruxelles', famille_principale: 1, familles_secondaires: [3],
|
||
hashtags: ['#reemploi-structurel', '#plateforme-materiaux'], type_principal: 'Coopérative',
|
||
badges: { centre_ressources: true, mouvement_manifeste: false, contre_pouvoir_spatial: false, f6_recherche_politique: true },
|
||
description_courte: 'Réemploi des matériaux de construction.', description_longue: '', pensees: [], sources: [], already_in_v1: false, eligible_v2: true,
|
||
latitude: 50.8, longitude: 4.3,
|
||
})
|
||
ok(eq(structure.etiquettes, { tags: ['reemploi-structurel', 'plateforme-materiaux'], famille: ['1', '3', '6'], pays: ['BE'] }), 'structure → tags sans #, familles principale + secondaires + 6 (badge), pays')
|
||
ok(eq(structure.chips, ['#reemploi-structurel', '#plateforme-materiaux']) && structure.chipsDimension === 'tags', 'structure → chips d’affichage avec # inchangés')
|
||
|
||
// ── URL ↔ état ──
|
||
const q1 = { vue: 'fiches', q: 'ordre', fonctions: 'Juridique,Formation', echelle: 'Régional', tri: 'nom', groupe: 'fonction', mode: 'outremer', adresse: 'sans' }
|
||
const e1 = V.lireQuery(q1, cfg)
|
||
ok(e1.vue === 'fiches' && e1.q === 'ordre' && eq(e1.filtres, { fonctions: ['Juridique', 'Formation'], echelle: ['Régional'] }) && e1.tri === 'nom' && e1.groupe === 'fonction' && e1.sousVue === 'outremer' && e1.sansAdresse, 'lecture : tous les paramètres de la SPEC §5')
|
||
ok(eq(V.ecrireQuery(e1, cfg), q1), 'aller-retour URL → état → URL identique')
|
||
const e2 = etat0({ vue: 'mixte', filtres: { fonctions: ['Technique'], echelle: [] }, groupe: 'echelle' })
|
||
ok(eq(V.lireQuery(V.ecrireQuery(e2, cfg), cfg), e2), 'aller-retour état → URL → état identique')
|
||
ok(eq(V.ecrireQuery(etat0(), cfg), {}), 'état par défaut → URL vide (sous-vue par défaut non écrite)')
|
||
ok(eq(V.ecrireQuery(etat0({ q: 'x' }), cfg, { territoire: 'Guyane', random: '1', vue: 'carte', q: 'ancien' }), { territoire: 'Guyane', random: '1', q: 'x' }), 'paramètres non gérés (territoire, random) conservés, gérés remplacés')
|
||
|
||
// Rétrocompatibilité et paramètres invalides
|
||
ok(V.lireQuery({ vue: 'fiches' }, cfg).vue === 'fiches', 'rétrocompat : ?vue=fiches (lien B3 diffusé) → état Fiches')
|
||
ok(V.lireQuery({ mode: 'outremer' }, cfg).sousVue === 'outremer', 'rétrocompat : ?mode=outremer → sous-vue Outre-mer')
|
||
ok(V.lireQuery({}, cfg).vue === null, 'sans vue= → null (défaut par largeur)')
|
||
const inv = V.lireQuery({ vue: 'plein-ecran', tri: 'distance', groupe: 'couleur', mode: 'lune', adresse: 'oui', zzz: '1' }, cfg)
|
||
ok(inv.vue === null && inv.tri === null && inv.groupe === null && inv.sousVue === 'metropole' && inv.sansAdresse === false, 'paramètres invalides ignorés sans erreur (vue, tri, groupe, mode, adresse)')
|
||
ok(eq(V.filtresValides({ fonctions: ['Juridique', 'Astrologie'], echelle: ['Mondial'] }, cfg), { fonctions: ['Juridique'], echelle: [] }), 'valeurs de filtre inconnues ignorées')
|
||
const cfgVide = { ...cfg, dimensions: [{ ...cfg.dimensions[0], valeurs: [] }] }
|
||
ok(eq(V.filtresValides({ fonctions: ['Astrologie'] }, cfgVide), { fonctions: ['Astrologie'] }), 'dimension pas encore chargée : valeurs gardées (lien partagé non perdu)')
|
||
ok(eq(V.lireQuery({ fonctions: ['Juridique,Formation', 'x'], q: ['a', 'b'] }, cfg).filtres.fonctions, ['Juridique', 'Formation']), 'paramètre répété : seule la première occurrence est lue')
|
||
ok(eq(V.lireQuery({ fonctions: ' Juridique ,,Juridique' }, cfg).filtres.fonctions, ['Juridique']), 'espaces, vides et doublons nettoyés')
|
||
|
||
// ── Filtrage : OU dans une dimension, ET entre ──
|
||
const filtre = (over) => ids(V.filtrerFiches(fiches, etat0(over), cfg))
|
||
ok(eq(filtre({ filtres: { fonctions: ['Juridique', 'Technique'], echelle: [] } }), [1, 2, 4]), 'OU dans une dimension : Juridique OU Technique')
|
||
ok(eq(filtre({ filtres: { fonctions: ['Juridique', 'Technique'], echelle: ['Régional'] } }), [2, 4]), 'ET entre dimensions : (Juridique OU Technique) ET Régional')
|
||
ok(eq(filtre({ filtres: { fonctions: [], echelle: ['National', 'Local'] } }), [1, 3]), 'OU sur la dimension secondaire')
|
||
ok(eq(filtre({ q: 'ecoute' }), [3]), 'recherche insensible aux accents et à la casse (« ecoute » → Écoute)')
|
||
ok(eq(filtre({ q: 'NANTES' }), [2]), 'recherche sur la ville')
|
||
ok(eq(filtre({ q: 'psychologique' }), [3]), 'recherche sur le résumé')
|
||
ok(eq(filtre({ sansAdresse: true }), [3]), 'adresse=sans → seulement les fiches non localisées')
|
||
|
||
// ── Compteurs ──
|
||
const c = V.compterEtiquettes(fiches, etat0({ filtres: { fonctions: ['Juridique'], echelle: ['Régional'] } }), cfg)
|
||
ok(c.fonctions.Juridique === 1 && c.fonctions.Technique === 1 && c.fonctions.Formation === 1 && c.fonctions['Santé mentale'] === 0, 'compteurs fonction : dans le résultat des AUTRES dimensions (Régional)', JSON.stringify(c.fonctions))
|
||
ok(c.echelle.National === 1 && c.echelle.Régional === 1 && c.echelle.Local === 0, 'compteurs échelle : dans le résultat des autres dimensions (Juridique)', JSON.stringify(c.echelle))
|
||
const cq = V.compterEtiquettes(fiches, etat0({ q: 'paris' }), cfg)
|
||
ok(cq.fonctions.Juridique === 1 && cq.fonctions.Formation === 0, 'compteurs : la recherche s’applique')
|
||
ok(V.nbFiltresActifs(etat0({ filtres: { fonctions: ['A', 'B'], echelle: ['C'] }, sansAdresse: true })) === 4, 'nombre de filtres actifs (pour « Filtrer · n »)')
|
||
|
||
// ── Tri ──
|
||
ok(V.triEffectif(etat0(), cfg) === 'nom', 'tri par défaut sans filtre : nom')
|
||
ok(V.triEffectif(etat0({ filtres: { fonctions: ['Juridique'], echelle: [] } }), cfg) === 'pertinence', 'tri par défaut avec filtre : pertinence')
|
||
ok(V.triEffectif(etat0({ tri: 'recent', filtres: { fonctions: ['Juridique'], echelle: [] } }), cfg) === 'recent', 'tri explicite prioritaire')
|
||
ok(eq(ids(V.trierFiches(fiches, 'nom', etat0())), [5, 4, 1, 2, 3]), 'tri nom A → Z (« Écoute » rangé à E)')
|
||
const ePert = etat0({ filtres: { fonctions: ['Juridique', 'Formation'], echelle: [] } })
|
||
ok(eq(ids(V.trierFiches(V.filtrerFiches(fiches, ePert, cfg), 'pertinence', ePert)), [2, 1]), 'pertinence : la fiche qui coche le plus d’étiquettes d’abord')
|
||
ok(eq(ids(V.trierFiches(fiches, 'recent', etat0())), [4, 5, 3, 2, 1]), 'récent : date d’abord, puis Id décroissant')
|
||
ok(V.triEffectif(etat0(), { ...cfg, tris: ['pertinence', 'nom'] }) === 'nom', 'Réseaux AEP (sans récent) : défaut nom')
|
||
|
||
// ── Regroupement ──
|
||
const g = V.regrouper(V.trierFiches(fiches, 'nom', etat0()), cfg.groupes[0], cfg)
|
||
ok(eq(g.map((x) => `${x.libelle}:${ids(x.fiches).join('+')}`), ['Juridique:1', 'Technique:4', 'Formation:2', 'Santé mentale:3', 'Sans fonction:5']), 'groupe fonction : première étiquette, ordre de la dimension, « sans » en dernier', JSON.stringify(g.map((x) => x.libelle)))
|
||
ok(g.reduce((s, x) => s + x.fiches.length, 0) === fiches.length, 'regroupement : chaque fiche une seule fois (compteurs justes)')
|
||
const gt = V.regrouper(fiches, cfg.groupes[2], cfg)
|
||
ok(eq(gt.map((x) => x.libelle), ['Martinique', 'Métropole']), 'groupe territoire (dimension sans chips) : ordre A → Z')
|
||
ok(V.regrouper(fiches, null, cfg).length === 1, 'sans regroupement : un seul bloc')
|
||
ok(eq(ids(V.ordreFiches(g)), [1, 4, 2, 3, 5]), 'ordre fiche à fiche = ordre affiché des groupes (B12)')
|
||
|
||
// ── Fiche ouverte : URL, fiche à fiche, historique (B12-M2/M3) ──
|
||
ok(V.lireFiche({ fiche: '412' }) === '412' && V.lireFiche({ fiche: 'f1-rotor' }) === 'f1-rotor', 'ouverture par URL : fiche= lu (id numérique ou texte)')
|
||
ok(V.lireFiche({}) === null && V.lireFiche({ fiche: '' }) === null && V.lireFiche({ fiche: ' ' }) === null, 'fiche= absent ou vide → pas de fiche')
|
||
ok(V.lireFiche({ fiche: ['7', '8'] }) === '7', 'fiche= répété → la première valeur')
|
||
const qListe = { vue: 'fiches', fonctions: 'Juridique,Formation', tri: 'nom' }
|
||
ok(eq(V.queryAvecFiche(qListe, 412), { ...qListe, fiche: '412' }), 'queryAvecFiche pose fiche= et garde filtres, tri, vue')
|
||
ok(eq(V.queryAvecFiche({ ...qListe, fiche: '412' }, null), qListe), 'queryAvecFiche(null) retire fiche= et rien d’autre')
|
||
const qEcrite = V.ecrireQuery({ ...V.lireQuery({ ...qListe, fiche: '412' }, cfg), tri: 'pertinence' }, cfg, { ...qListe, fiche: '412' })
|
||
ok(qEcrite.fiche === '412' && qEcrite.tri === 'pertinence', 'un changement de tri garde la fiche ouverte')
|
||
ok(V.empreinteListe({ ...qListe, fiche: '1' }) === V.empreinteListe({ fiche: '9', tri: 'nom', fonctions: 'Juridique,Formation', vue: 'fiches' }), 'empreinte de la liste : indépendante de fiche= et de l’ordre des clés')
|
||
|
||
const ordre = V.ordreFiches(g) // [1, 4, 2, 3, 5]
|
||
const p = V.positionFiche(ordre, '2')
|
||
ok(p && p.rang === 3 && p.total === 5 && p.precedente.id === 4 && p.suivante.id === 3, '« 3 / 5 » : précédente et suivante dans l’ordre courant')
|
||
ok(V.positionFiche(ordre, 1).precedente === null && V.positionFiche(ordre, 5).suivante === null, 'pas de bouclage aux extrémités')
|
||
const ordreFiltre = V.ordreFiches(V.regrouper(V.filtrerFiches(fiches, etat0({ filtres: { fonctions: ['Juridique'], echelle: [] } }), cfg), null, cfg))
|
||
ok(V.positionFiche(ordreFiltre, '4') === null, 'fiche hors filtres → position null (« hors de vos filtres », sans précédente/suivante)')
|
||
ok(V.positionFiche(ordre, null) === null && V.positionFiche(ordre, '999') === null, 'pas de fiche ou id inconnu → null')
|
||
|
||
// Historique simulé, avec les mêmes décisions que composables/useVueFiches.ts
|
||
function navigateur(depart) {
|
||
const pile = [depart]
|
||
let i = 0
|
||
let liste = null // listeALOuverture
|
||
const cur = () => pile[i]
|
||
return {
|
||
cur,
|
||
longueur: () => i + 1,
|
||
ouvrir(id) {
|
||
const mode = V.modeOuverture(V.lireFiche(cur()))
|
||
if (mode === 'push') { liste = V.empreinteListe(cur()); pile.splice(i + 1); pile.push(V.queryAvecFiche(cur(), id)); i++ }
|
||
else pile[i] = V.queryAvecFiche(cur(), id)
|
||
},
|
||
filtrer(q) { pile[i] = q },
|
||
fermer() {
|
||
const mode = V.modeFermeture(liste != null, liste === V.empreinteListe(cur()))
|
||
liste = null
|
||
if (mode === 'back') i--
|
||
else pile[i] = V.queryAvecFiche(cur(), null)
|
||
},
|
||
retour() { i--; if (V.lireFiche(cur()) == null) liste = null },
|
||
}
|
||
}
|
||
let nav = navigateur(qListe)
|
||
nav.ouvrir(1); nav.ouvrir(4); nav.ouvrir(2)
|
||
ok(nav.longueur() === 2 && nav.cur().fiche === '2', 'ouvrir puis deux fois « suivante » : une seule entrée d’historique ajoutée')
|
||
nav.retour()
|
||
ok(nav.longueur() === 1 && V.lireFiche(nav.cur()) === null && eq(nav.cur(), qListe), 'retour arrière (téléphone) : la fiche se ferme, la liste et ses filtres restent')
|
||
nav = navigateur(qListe)
|
||
nav.ouvrir(1); nav.fermer()
|
||
ok(nav.longueur() === 1 && eq(nav.cur(), qListe), 'fermer une fiche ouverte depuis la liste : retour en arrière, historique propre')
|
||
nav = navigateur({ ...qListe, fiche: '412' })
|
||
nav.fermer()
|
||
ok(nav.longueur() === 1 && eq(nav.cur(), qListe), 'lien partagé : fermer retire fiche= sur place, sans quitter la page')
|
||
nav = navigateur(qListe)
|
||
nav.ouvrir(1); nav.filtrer({ ...nav.cur(), echelle: 'National' }); nav.fermer()
|
||
ok(nav.cur().echelle === 'National' && V.lireFiche(nav.cur()) === null, 'filtre changé fiche ouverte : fermer garde le nouveau filtre (pas de retour arrière)')
|
||
|
||
// ── Partir de soi : sept mots, ordre de la slide (B6-M2) ──
|
||
const MOTS = [
|
||
{ id: 'quete-de-sens', mot: 'quête de sens', resume: 'Bifurquer, donner du sens à son métier.' },
|
||
{ id: 'gagner-sa-vie', mot: 'gagner sa vie', resume: 'Créer son activité et en vivre.', vide: 'Rien encore.' },
|
||
{ id: 'sante-mentale', mot: 'santé mentale', resume: 'Repérer, comprendre, se faire accompagner.' },
|
||
{ id: 'naviguer-avec-soi', mot: 'naviguer avec soi', resume: 'Méditation et pratiques d’introspection.' },
|
||
]
|
||
const RESS = [
|
||
{ id: 'film', titre: 'En quête de sens', format: 'film', acces: 'don libre', pourquoi: 'Le film nommé dans le deck.', fiches: ['quete-de-sens'] },
|
||
{ id: 'ofqa', titre: 'OFQA', format: 'vidéo', acces: 'libre', pourquoi: 'Diplômés qui ont bifurqué.', fiches: ['quete-de-sens'] },
|
||
{ id: 'psc', titre: 'Premiers secours en santé mentale', format: 'formation', acces: 'financé selon région', pourquoi: 'Repérer les signes.', fiches: ['sante-mentale'] },
|
||
{ id: 'vipassana', titre: 'Vipassana', format: 'retraite', acces: 'don libre', pourquoi: 'Dix jours de silence.', fiches: ['naviguer-avec-soi'] },
|
||
{ id: 'insight', titre: 'Insight Timer', format: 'appli', acces: 'gratuit avec inscription', pourquoi: 'Méditations guidées.', fiches: ['naviguer-avec-soi', 'sante-mentale'] },
|
||
]
|
||
const parMot = (id) => RESS.filter((r) => r.fiches.includes(id))
|
||
const mots = MOTS.map((m) => A.toMiniMot(m, parMot(m.id)))
|
||
const cfgMots = {
|
||
dimensions: [
|
||
{ cle: 'format', libelle: 'Format', variante: 'fonction', valeurs: A.valeursRessources(RESS, 'format') },
|
||
{ cle: 'acces', libelle: 'Accès', variante: 'echelle', valeurs: A.valeursRessources(RESS, 'acces') },
|
||
],
|
||
tris: ['ordre', 'pertinence', 'nom'],
|
||
triDefaut: 'ordre',
|
||
libellesTri: { ordre: 'Ordre de la slide' },
|
||
groupes: [],
|
||
etats: ['carte', 'mixte', 'fiches'],
|
||
}
|
||
const etatM = (query = {}, over = {}) => ({ ...V.lireQuery(query, cfgMots), ...over })
|
||
const sansDefaut = { ...cfgMots, triDefaut: undefined, tris: ['pertinence', 'nom'] }
|
||
|
||
ok(mots[0].kind === 'mot' && mots[0].nom === 'quête de sens' && eq(mots[0].chips, ['film', 'vidéo']) && mots[0].chipsDimension === 'format' && mots[0].geoloc === true, 'mot → kind mot, nom = le mot, chips = formats, geoloc true (pas de carte géographique)')
|
||
ok(eq(mots[0].etiquettes, { format: ['film', 'video'], acces: ['don-libre', 'libre'] }), 'mot → étiquettes en slug (sans accent, sans espace) pour l’URL', JSON.stringify(mots[0].etiquettes))
|
||
ok(eq(mots[3].etiquettes.acces, ['don-libre', 'gratuit-avec-inscription']) && mots[3].chips.length === 2, 'mot → union des formats et des accès de ses ressources')
|
||
ok(mots[1].resume === 'Créer son activité et en vivre.' && eq(mots[1].etiquettes, { format: [], acces: [] }), 'mot sans ressource (gagner sa vie) → résumé gardé, aucune étiquette')
|
||
ok(A.toMiniMot({ id: 'x', mot: 'x', resume: '', vide: 'Rien encore. Propose.' }, []).resume === 'Rien encore.', 'mot sans résumé → texte « vide » (première phrase)')
|
||
ok(eq(A.valeursRessources(RESS, 'acces').map((v) => v.libelle), ['don libre', 'libre', 'financé selon région', 'gratuit avec inscription']) && A.slugEtiquette('financé selon région') === 'finance-selon-region', 'valeurs de dimension : libellé lisible, valeur en slug, ordre de première apparition')
|
||
const idsM = (q, tri) => ids(V.trierFiches(V.filtrerFiches(mots, etatM(q), cfgMots), tri ?? V.triEffectif(etatM(q), cfgMots), etatM(q)))
|
||
ok(eq(idsM({}), ['quete-de-sens', 'gagner-sa-vie', 'sante-mentale', 'naviguer-avec-soi']), 'tri ordre : l’ordre du tableau d’entrée, pas A → Z')
|
||
ok(eq(ids(V.trierFiches([...mots].reverse(), 'ordre', etatM())), ['naviguer-avec-soi', 'sante-mentale', 'gagner-sa-vie', 'quete-de-sens']), 'tri ordre : stable, suit l’entrée quelle qu’elle soit')
|
||
ok(V.triEffectif(etatM(), cfgMots) === 'ordre', 'triDefaut respecté sans filtre')
|
||
ok(V.triEffectif(etatM({ q: 'vipassana' }), cfgMots) === 'ordre', 'triDefaut respecté avec une recherche seule (pas de filtre d’étiquette)')
|
||
ok(V.triEffectif(etatM({ acces: 'don-libre' }), cfgMots) === 'pertinence', 'pertinence prioritaire dès qu’un filtre est actif, même avec triDefaut')
|
||
ok(V.triEffectif(etatM({ acces: 'don-libre', tri: 'ordre' }), cfgMots) === 'ordre', 'tri explicite (tri=ordre dans l’URL) prioritaire')
|
||
ok(V.lireQuery({ tri: 'ordre' }, cfgMots).tri === 'ordre', 'tri=ordre lu dans l’URL quand la page l’offre')
|
||
ok(V.lireQuery({ tri: 'ordre' }, cfg).tri === null && V.lireQuery({ tri: 'ordre' }, sansDefaut).tri === null, 'tri=ordre ignoré quand la page ne l’offre pas (/ et /agences)')
|
||
ok(V.triEffectif(etatM(), sansDefaut) === 'nom' && V.triEffectif(etat0(), cfg) === 'nom', 'sans triDefaut : comportement inchangé (nom)')
|
||
ok(V.triEffectif(etatM(), { ...cfgMots, triDefaut: 'recent' }) === 'nom', 'triDefaut absent de tris → ignoré')
|
||
ok(eq(idsM({ acces: 'don-libre' }), ['naviguer-avec-soi', 'quete-de-sens']), 'filtre Accès « don libre » : pertinence (ex æquo → A → Z), pas l’ordre de la slide', JSON.stringify(idsM({ acces: 'don-libre' })))
|
||
ok(eq(idsM({ q: 'vipassana' }), ['naviguer-avec-soi']), 'recherche « Vipassana » (titre d’une ressource) → le mot « naviguer avec soi »')
|
||
ok(eq(idsM({ q: 'VIPASSANA' }), ['naviguer-avec-soi']) && eq(idsM({ q: 'quete' }), ['quete-de-sens']), 'recherche insensible à la casse et aux accents')
|
||
const cm = V.compterEtiquettes(mots, etatM({ acces: 'don-libre' }), cfgMots)
|
||
ok(cm.format.film === 1 && cm.format.retraite === 1 && cm.format.formation === 0 && cm.acces['don-libre'] === 2 && cm.acces.libre === 1, 'compteurs : format dans le résultat du filtre Accès, accès dans celui des formats', JSON.stringify(cm))
|
||
const eMot = V.lireQuery({ tab: 'partir-de-soi', acces: 'don-libre', format: 'film,retraite', fiche: 'quete-de-sens' }, cfgMots)
|
||
const qMot = V.ecrireQuery(eMot, cfgMots, { tab: 'partir-de-soi', acces: 'don-libre', fiche: 'quete-de-sens' })
|
||
ok(qMot.tab === 'partir-de-soi' && qMot.fiche === 'quete-de-sens' && qMot.acces === 'don-libre' && qMot.format === 'film,retraite', 'tab= et fiche= survivent à l’écriture des filtres')
|
||
ok(V.queryAvecFiche({ tab: 'partir-de-soi', vue: 'carte' }, 'sante-mentale').tab === 'partir-de-soi' && V.queryAvecFiche({ tab: 'partir-de-soi', fiche: 'x' }, null).tab === 'partir-de-soi', 'tab= survit à l’ouverture et à la fermeture d’une fiche')
|
||
|
||
console.log(`\n${n - fail}/${n}`)
|
||
process.exit(fail ? 1 : 0)
|