Modularisation / dé-duplication : - lib/util/text.js : `norm` canonique partagé (remplace 2 ré-implémentations : address-db, legacy-dispatch-sync). - lib/util/legacy-parse.js : parseurs/mapping PURS du pont (DEPT_JOBTYPE, DUR, jobType, prio, tzDate, startTime, coord) extraits hors I/O → testables en isolation, sans pg/mysql/erp. - legacy-dispatch-sync + address-db importent ces utils (pont vérifié en prod : preview OK, 0 erreur). Observabilité (sûr, additif, 1 seul point) : - erp.js create/update/remove : log de l'échec à la SOURCE quand HTTP≥400 → toutes les écritures ERPNext silencieuses des 50+ appelants sont désormais tracées, SANS changer aucun flux de contrôle. Tests (fondation) : - vitest + npm test ; test/util.test.js : 19 tests verts sur norm + coord(bornes QC)/prio/startTime/jobType/tzDate. Tournent sans installer les deps lourdes du hub (modules purs). Aligné docs/architecture/VISION.md (P0 hygiène). Suite : audit r.ok des appelants financiers (payments/contracts) en revue supervisée ; CI/CD minimal (Gitea Actions lint+test) ; décomposition des god-files (Phase 2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
43 lines
2.5 KiB
JavaScript
43 lines
2.5 KiB
JavaScript
// Tests des helpers PURS (Phase 1 : fondation de tests, zéro dépendance I/O).
|
|
// Couvre la logique critique du pipeline d'adresses/pont legacy que je ne veux plus voir régresser.
|
|
import { describe, it, expect } from 'vitest'
|
|
import { norm } from '../lib/util/text.js'
|
|
import { coord, prio, startTime, jobType, tzDate } from '../lib/util/legacy-parse.js'
|
|
|
|
describe('norm', () => {
|
|
it('minuscule + sans accents', () => expect(norm('RUE René-Vinet')).toBe('rue rene-vinet'))
|
|
it('compacte les espaces + trim', () => expect(norm(' Sainte Clotilde ')).toBe('sainte clotilde'))
|
|
it('ville accentuée', () => expect(norm('Sainte-Clotilde-de-Châteauguay')).toBe('sainte-clotilde-de-chateauguay'))
|
|
it('null/undefined → chaîne vide', () => { expect(norm(null)).toBe(''); expect(norm(undefined)).toBe('') })
|
|
})
|
|
|
|
describe('coord (bornes Québec)', () => {
|
|
it('coord QC valide (chaînes legacy)', () => expect(coord('45.2528570', '-73.5599440')).toEqual({ lat: 45.252857, lon: -73.559944 }))
|
|
it('0/0 rejeté', () => expect(coord(0, 0)).toBeNull())
|
|
it('hors bornes (Toronto lat 43.65) rejeté', () => expect(coord(43.65, -79.38)).toBeNull())
|
|
it('longitude hors bornes rejetée', () => expect(coord(45.5, -50)).toBeNull())
|
|
it('non-numérique rejeté', () => { expect(coord('abc', 'x')).toBeNull(); expect(coord(null, null)).toBeNull() })
|
|
})
|
|
|
|
describe('prio (priorité legacy → Dispatch)', () => {
|
|
it('≥3 → high', () => { expect(prio(3)).toBe('high'); expect(prio('5')).toBe('high') })
|
|
it('2 → medium', () => expect(prio(2)).toBe('medium'))
|
|
it('1/0/null → low', () => { expect(prio(1)).toBe('low'); expect(prio(0)).toBe('low'); expect(prio(null)).toBe('low') })
|
|
})
|
|
|
|
describe('startTime (due_time legacy → HH:MM:SS)', () => {
|
|
it('heure explicite', () => { expect(startTime('14:30')).toBe('14:30:00'); expect(startTime('9:05')).toBe('09:05:00') })
|
|
it('am/pm', () => { expect(startTime('am')).toBe('08:00:00'); expect(startTime('pm')).toBe('13:00:00') })
|
|
it('day / vide → null', () => { expect(startTime('day')).toBeNull(); expect(startTime('')).toBeNull() })
|
|
})
|
|
|
|
describe('jobType (dept_id → job_type)', () => {
|
|
it('mappings connus', () => { expect(jobType(27)).toBe('Installation'); expect(jobType(26)).toBe('Réparation'); expect(jobType(15)).toBe('Retrait') })
|
|
it('inconnu → Autre', () => expect(jobType(999)).toBe('Autre'))
|
|
})
|
|
|
|
describe('tzDate (epoch → date America/Toronto)', () => {
|
|
it('null → null', () => expect(tzDate(null)).toBeNull())
|
|
it('epoch → YYYY-MM-DD', () => expect(tzDate(1749182400)).toMatch(/^\d{4}-\d{2}-\d{2}$/))
|
|
})
|