Skip to content

fix(test): profondeur d'assertion + trous de coverage ciblés - #113

Merged
julesbonnard merged 4 commits into
devfrom
fix/tests-assertion-depth
Aug 29, 2026
Merged

fix(test): profondeur d'assertion + trous de coverage ciblés#113
julesbonnard merged 4 commits into
devfrom
fix/tests-assertion-depth

Conversation

@julesbonnard

Copy link
Copy Markdown
Owner

Ce qui compte vraiment ici

authorizationBasicHeaders (utilisé pour l'auth par credentials et le refresh) tournait déjà à 100% de couverture de lignes, mais aucun test n'assertait la valeur réellement produite — les deux tests censés le couvrir ("should accept apiKey"/"should accept clientId and clientSecret") ne vérifiaient que authUrl, invariant quels que soient les credentials passés. Un mauvais encodage du header serait passé inaperçu. Remplacés par des assertions sur le header Basic <...> réellement construit, plus une assertion sur le header effectivement envoyé par requestAuthenticatedToken.

Le reste (coverage 97.87%→98.81% lignes, 89.75%→91.3% branches) est secondaire — la vraie amélioration est la profondeur d'assertion, pas le pourcentage.

Détail

  • docs.test.ts : suppression des describe('notificationCenter')/('filterCenter') (typeof x === 'function'), déjà couverts comportementalement par notification.test.ts/filter.test.ts
  • index.test.ts : fusion de deux tests redondants
  • QueryBuilder.test.ts : 19 tests répétitifs (should return this for chaining × 11, should not set X when undefined × 8) remplacés par 2 blocs it.each
  • request.test.ts : nouveau test pour fetchText's status≥300 (chemin atteignable, non testé avant)
  • parseDocument.test.ts : deux tests qui figent des comportements existants — genre en tableau non-vide, et signal: 'cwarn' seul → undefined (intentionnel : AfpDocumentSignal ne modélise que 'correction'|'update')
  • shotlist.test.ts : le repli citation-sans-guillemets (description de SOUNDBITE qui commence elle-même par "SOUNDBITE")
  • @vitest/coverage-v8 repin exact sur 4.1.10 (matche vitest@4.1.10, fait disparaître l'avertissement de version mixte) + script test:coverage

Trouvaille non corrigée ici

request.ts:80 est du code mort confirmé : fetchText ne peut jamais détecter un payload d'erreur AFP sur HTTP 200, car elle parse errorSchema (un z.object) contre une string brute (response.text()) au lieu du JSON parsé comme le fait fetchJson. Impact réel potentiel sur getStoryHtml/feed. Tenu à l'écart de cette PR pour ne pas mélanger changement de comportement runtime et travail sur les tests → #112.

Closes #110

🤖 Generated with Claude Code

julesbonnard and others added 4 commits August 28, 2026 15:11
…overage ciblés

- auth.test.ts : les tests "should accept apiKey"/"should accept clientId
  and clientSecret" n'assertaient que authUrl (invariant quels que soient
  les credentials). Remplacés par des assertions sur la valeur réelle du
  header authorizationBasicHeaders (Basic <apiKey> / Basic <base64(id:secret)>).
  Le code s'exécutait déjà à 100% de couverture ; un mauvais encodage du
  header serait passé inaperçu jusqu'ici. Ajout aussi de l'assertion sur le
  header Authorization effectivement envoyé par requestAuthenticatedToken.
- docs.test.ts : suppression des describe('notificationCenter')/('filterCenter')
  qui ne vérifiaient que typeof x === 'function' — comportement déjà
  couvert par notification.test.ts et filter.test.ts.
- index.test.ts : fusion des deux tests "should export ApiCore class" /
  "should allow creating an ApiCore instance", le second rendait le
  premier redondant.
- QueryBuilder.test.ts : les 19 tests "should return this for chaining"
  (x11) et "should not set X when undefined" (x8), un par describe de
  setter, remplacés par deux blocs it.each paramétrés.
- request.test.ts : nouveau test pour le chemin status>=300 de fetchText
  (get(url, {}, 'text')), jusqu'ici non exercé.
- parseDocument.test.ts : deux nouveaux tests figeant des comportements
  non testés — genre en tableau non-vide (garde le premier élément), et
  signal: 'cwarn' seul -> undefined (AfpDocumentSignal ne modélise que
  'correction'|'update', cwarn en est délibérément exclu).
- shotlist.test.ts : nouveau test pour le repli citation-sans-guillemets
  (une description de SOUNDBITE qui commence elle-même par "SOUNDBITE").
- @vitest/coverage-v8 repin sur 4.1.10 (exact) pour matcher vitest@4.1.10
  et faire disparaître l'avertissement "mixed versions"; ajout du script
  test:coverage.

Trouvaille non corrigée ici (issue séparée #112) : request.ts:80 est du
code mort confirmé — fetchText ne peut jamais détecter un payload
d'erreur AFP sur HTTP 200 car elle parse errorSchema (z.object) contre
une string brute. Changement de comportement runtime volontairement
tenu à l'écart de cette PR de tests.

Coverage : 97.87% -> 98.81% lignes, 89.75% -> 91.3% branches, 99.28% ->
100% fonctions — secondaire par rapport à la profondeur d'assertion
ci-dessus.

Réf: #110

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…aphes

parseParagraphBlocks (sous-titre/liste/paragraphe) et numberParagraphs
([¶n], 1-based) étaient dupliqués dans afpnews-deck. Les rendre
disponibles ici permet à afpnews-mcp-server de produire un Markdown
structuré et numéroté cohérent avec les deep-links ?p=n du deck.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…OURCES

extractBase() typait son retour en Omit<AfpDocument, ...> : Omit sur un type
union n'est pas distributif, donc `class` s'aplatissait en l'union complète
des 8 littéraux au lieu de rester lié à la variante narrowed par le switch.
Chaque case assignait alors un `class` trop large à AfpDocument (union
discriminée) -> erreurs tsc. extractBase() retourne maintenant
Omit<AfpDocumentCommon, ...> (type non discriminé, sans `class`) et chaque
branche du switch pose elle-même `class: doc.class`, correctement narrowed
à cet endroit. AfpDocumentCommon exporté pour être référencé.

FIELD_SOURCES.paragraphs et .caption listaient des dépendances brutes
incomplètes par rapport à parseDocument() : paragraphs peut retirer la 1re
ligne de `news` comme titre replié quand `headline` est absent (urgency < 4),
et caption retombe sur bagItem[0].caption pour picture/graphic. Sans ces
champs bruts dans la liste, toApiFields() omettait de les demander à l'API
quand seul le champ dérivé était requêté, cassant ces replis silencieusement.
tsdown ne fait pas de vérification de type sémantique (transpilation à la
esbuild + .d.ts syntaxique) : lint/build/test ne détectaient donc pas les
erreurs de type du commit précédent. Ajoute `npm run typecheck` (tsc
--noEmit), branché dans `prepare` et dans la CI.
@julesbonnard
julesbonnard merged commit f020dea into dev Aug 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant