[{"data":1,"prerenderedAt":5321},["ShallowReactive",2],{"search-api":-1,"listing-tag-resilience-page-1":3},[4],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"id":11,"date":12,"listed":13,"nocomments":7,"hidden":13,"categories":14,"tags":15,"cover":21,"readingTime":22,"body":27,"_type":5315,"_id":5316,"_source":5317,"_file":5318,"_stem":5319,"_extension":5320},"/fr/intelligence-artificielle/code-claude-tests-passent-plante-prod","intelligence-artificielle",false,"","Tous les tests sont verts, et 3 jours plus tard ça plante en prod","Pourquoi les tests Claude couvrent le happy path mais ratent les pannes réelles. Les 4 tests manquants et le wrapper anti-fragile à exiger.",64,"2026-05-10",true,[6],[16,17,18,19,20],"tests","resilience","claude-code","ci-cd","ia","covers/articles/code-claude-tests-passent-plante-prod.jpg",{"text":23,"minutes":24,"time":25,"words":26},"14 min read",13.74,824400,2748,{"type":28,"children":29,"toc":5300},"root",[30,42,47,51,58,82,96,126,146,149,155,160,768,797,825,830,843,846,859,862,868,873,880,900,1630,1647,1653,1658,2260,2265,2271,2276,2816,2821,2827,2832,3321,3326,3329,3335,3347,3370,3375,4852,4871,4874,4880,4892,4909,4927,4937,4949,4952,4958,4963,5068,5080,5083,5089,5094,5099,5104,5118,5130,5133,5139,5154,5167,5219,5232,5252,5279,5282,5294],{"type":31,"tag":32,"props":33,"children":34},"element","p",{},[35],{"type":31,"tag":36,"props":37,"children":38},"strong",{},[39],{"type":40,"value":41},"text","Un mardi matin de janvier 2026, je reçois une alerte sur crmcoaching, mon SaaS pour coachs professionnels que je développe seul avec Claude. La notification de confirmation de séance avait planté toute la nuit. La CI était verte. Les tests passaient. Je ne comprenais pas. Trois heures plus tard, j'identifie le problème : plusieurs confirmations envoyées en parallèle au même moment, Brevo (mon provider d'emails transactionnels) avait appliqué son rate limit avec un 429, et le code que Claude avait généré n'avait jamais été testé sous cette condition.",{"type":31,"tag":32,"props":43,"children":44},{},[45],{"type":40,"value":46},"Ce n'était pas un bug Claude. C'était un bug de mes tests. Mes tests vérifiaient que la fonction marchait. Pas qu'elle survivait. Voici la différence, et les 4 tests que Claude n'écrit jamais spontanément, que vous devez exiger explicitement.",{"type":31,"tag":48,"props":49,"children":50},"hr",{},[],{"type":31,"tag":52,"props":53,"children":55},"h2",{"id":54},"pourquoi-les-tests-claude-ne-couvrent-que-le-happy-path",[56],{"type":40,"value":57},"Pourquoi les tests Claude ne couvrent que le happy path",{"type":31,"tag":32,"props":59,"children":60},{},[61,63,72,74,80],{"type":40,"value":62},"Le constat est simple, et il est documenté. Selon le ",{"type":31,"tag":64,"props":65,"children":69},"a",{"href":66,"rel":67},"https://www.gitclear.com/ai_assistant_code_quality_2024_research",[68],"nofollow",[70],{"type":40,"value":71},"GitClear AI Copilot Code Quality Report 2024",{"type":40,"value":73},", les équipes IA-heavy livrent en moyenne 35% plus de code. Mais le ratio de tests behavior-level reste stable, voire baisse. Le code grossit, le filet de tests ne suit pas. Ce déséquilibre est précisément ce que je détaille dans ",{"type":31,"tag":64,"props":75,"children":77},{"href":76},"/fr/intelligence-artificielle/tester-code-genere-ia-checklist",[78],{"type":40,"value":79},"la checklist pour tester du code généré par IA",{"type":40,"value":81}," publiée en 2025.",{"type":31,"tag":32,"props":83,"children":84},{},[85,87,94],{"type":40,"value":86},"Pourquoi ? Parce que Claude génère des tests qui imitent le pattern moyen de son training data. Et ce pattern, c'est : un test par fonction, un mock par dépendance, une assertion sur le happy path. Si vous lui demandez \"écris des tests pour ",{"type":31,"tag":88,"props":89,"children":91},"code",{"className":90},[],[92],{"type":40,"value":93},"sendConfirmationEmail",{"type":40,"value":95},"\", il vous livre un test qui vérifie que la méthode envoie un email quand tout va bien. Il ne vous livre pas le test où Brevo renvoie un 429. Il ne vous livre pas le test où la méthode est appelée 50 fois en parallèle. Il ne vous livre pas le test où le réseau timeout après 30 secondes.",{"type":31,"tag":97,"props":98,"children":99},"blockquote",{},[100],{"type":31,"tag":32,"props":101,"children":102},{},[103,108,110,116,118,124],{"type":31,"tag":36,"props":104,"children":105},{},[106],{"type":40,"value":107},"Ce que j'ai observé sur crmcoaching",{"type":40,"value":109}," : j'ai compté les tests présents dans mon module ",{"type":31,"tag":88,"props":111,"children":113},{"className":112},[],[114],{"type":40,"value":115},"notification",{"type":40,"value":117},". Des dizaines de tests, une couverture de lignes correcte. Aucun ne simulait une réponse 429 de Brevo. Aucun ne simulait un timeout. Aucun ne lançait plus de 5 appels en parallèle via ",{"type":31,"tag":88,"props":119,"children":121},{"className":120},[],[122],{"type":40,"value":123},"Promise.all",{"type":40,"value":125},". Le filet de tests avait l'air dense, mais il était plein de trous sur les conditions réelles de production.",{"type":31,"tag":32,"props":127,"children":128},{},[129,131,137,139,144],{"type":40,"value":130},"Michael Nygard a écrit dans ",{"type":31,"tag":132,"props":133,"children":134},"em",{},[135],{"type":40,"value":136},"Release It!",{"type":40,"value":138}," (2007, deuxième édition 2018) : ",{"type":31,"tag":132,"props":140,"children":141},{},[142],{"type":40,"value":143},"\"Every feature in production must be hardened by tests of failure modes, not just success modes.\"",{"type":40,"value":145}," En 2026, Claude accélère la production de features, mais il n'accélère pas la production de tests de modes d'échec. Le ratio se déséquilibre, et la prod paie. C'est aussi la racine de la dérive que je décris dans le diagnostic du legacy à risque que personne n'avait vu venir.",{"type":31,"tag":48,"props":147,"children":148},{},[],{"type":31,"tag":52,"props":150,"children":152},{"id":151},"le-scénario-du-crash-brevo-rate-limit-sur-crmcoaching",[153],{"type":40,"value":154},"Le scénario du crash Brevo rate-limit sur crmcoaching",{"type":31,"tag":32,"props":156,"children":157},{},[158],{"type":40,"value":159},"Reprenons le code que Claude avait généré pour l'envoi des confirmations de séance. Voici la version simplifiée, en TypeScript NestJS :",{"type":31,"tag":161,"props":162,"children":166},"pre",{"className":163,"code":164,"language":165,"meta":8,"style":8},"language-typescript shiki shiki-themes catppuccin-frappe github-dark","// apps/api/src/infrastructure/notification/brevo-notification.service.ts\n\n@Injectable()\nexport class BrevoNotificationService {\n  constructor(\n    private readonly sessionRepository: SessionRepository,\n    private readonly brevoClient: BrevoClient,\n  ) {}\n\n  async sendSessionConfirmation(sessionId: string): Promise\u003Cvoid> {\n    const session = await this.sessionRepository.findById(sessionId);\n    if (!session) throw new Error(`Session not found: ${sessionId}`);\n\n    await this.brevoClient.sendTransactionalEmail({\n      to: [{ email: session.coacheeEmail }],\n      templateId: BREVO_TEMPLATE_IDS.SESSION_CONFIRMATION,\n      params: { sessionDate: session.scheduledAt },\n    });\n  }\n}\n","typescript",[167],{"type":31,"tag":88,"props":168,"children":169},{"__ignoreMap":8},[170,182,191,213,240,254,290,320,334,342,410,472,550,558,598,656,688,733,750,759],{"type":31,"tag":171,"props":172,"children":175},"span",{"class":173,"line":174},"line",1,[176],{"type":31,"tag":171,"props":177,"children":179},{"style":178},"--shiki-default:#737994;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit",[180],{"type":40,"value":181},"// apps/api/src/infrastructure/notification/brevo-notification.service.ts\n",{"type":31,"tag":171,"props":183,"children":185},{"class":173,"line":184},2,[186],{"type":31,"tag":171,"props":187,"children":188},{"emptyLinePlaceholder":13},[189],{"type":40,"value":190},"\n",{"type":31,"tag":171,"props":192,"children":194},{"class":173,"line":193},3,[195,201,207],{"type":31,"tag":171,"props":196,"children":198},{"style":197},"--shiki-default:#8CAAEE;--shiki-default-font-style:italic;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit",[199],{"type":40,"value":200},"@",{"type":31,"tag":171,"props":202,"children":204},{"style":203},"--shiki-default:#8CAAEE;--shiki-default-font-style:italic;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit",[205],{"type":40,"value":206},"Injectable",{"type":31,"tag":171,"props":208,"children":210},{"style":209},"--shiki-default:#EF9F76;--shiki-dark:#E1E4E8",[211],{"type":40,"value":212},"()\n",{"type":31,"tag":171,"props":214,"children":216},{"class":173,"line":215},4,[217,223,228,234],{"type":31,"tag":171,"props":218,"children":220},{"style":219},"--shiki-default:#CA9EE6;--shiki-dark:#F97583",[221],{"type":40,"value":222},"export",{"type":31,"tag":171,"props":224,"children":225},{"style":219},[226],{"type":40,"value":227}," class",{"type":31,"tag":171,"props":229,"children":231},{"style":230},"--shiki-default:#E5C890;--shiki-default-font-style:italic;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit",[232],{"type":40,"value":233}," BrevoNotificationService",{"type":31,"tag":171,"props":235,"children":237},{"style":236},"--shiki-default:#949CBB;--shiki-dark:#E1E4E8",[238],{"type":40,"value":239}," {\n",{"type":31,"tag":171,"props":241,"children":243},{"class":173,"line":242},5,[244,249],{"type":31,"tag":171,"props":245,"children":246},{"style":219},[247],{"type":40,"value":248},"  constructor",{"type":31,"tag":171,"props":250,"children":251},{"style":236},[252],{"type":40,"value":253},"(\n",{"type":31,"tag":171,"props":255,"children":257},{"class":173,"line":256},6,[258,263,268,274,280,285],{"type":31,"tag":171,"props":259,"children":260},{"style":219},[261],{"type":40,"value":262},"    private",{"type":31,"tag":171,"props":264,"children":265},{"style":219},[266],{"type":40,"value":267}," readonly",{"type":31,"tag":171,"props":269,"children":271},{"style":270},"--shiki-default:#EA999C;--shiki-default-font-style:italic;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit",[272],{"type":40,"value":273}," sessionRepository",{"type":31,"tag":171,"props":275,"children":277},{"style":276},"--shiki-default:#81C8BE;--shiki-dark:#F97583",[278],{"type":40,"value":279},":",{"type":31,"tag":171,"props":281,"children":282},{"style":230},[283],{"type":40,"value":284}," SessionRepository",{"type":31,"tag":171,"props":286,"children":287},{"style":236},[288],{"type":40,"value":289},",\n",{"type":31,"tag":171,"props":291,"children":293},{"class":173,"line":292},7,[294,298,302,307,311,316],{"type":31,"tag":171,"props":295,"children":296},{"style":219},[297],{"type":40,"value":262},{"type":31,"tag":171,"props":299,"children":300},{"style":219},[301],{"type":40,"value":267},{"type":31,"tag":171,"props":303,"children":304},{"style":270},[305],{"type":40,"value":306}," brevoClient",{"type":31,"tag":171,"props":308,"children":309},{"style":276},[310],{"type":40,"value":279},{"type":31,"tag":171,"props":312,"children":313},{"style":230},[314],{"type":40,"value":315}," BrevoClient",{"type":31,"tag":171,"props":317,"children":318},{"style":236},[319],{"type":40,"value":289},{"type":31,"tag":171,"props":321,"children":323},{"class":173,"line":322},8,[324,329],{"type":31,"tag":171,"props":325,"children":326},{"style":236},[327],{"type":40,"value":328},"  )",{"type":31,"tag":171,"props":330,"children":331},{"style":236},[332],{"type":40,"value":333}," {}\n",{"type":31,"tag":171,"props":335,"children":337},{"class":173,"line":336},9,[338],{"type":31,"tag":171,"props":339,"children":340},{"emptyLinePlaceholder":13},[341],{"type":40,"value":190},{"type":31,"tag":171,"props":343,"children":345},{"class":173,"line":344},10,[346,351,356,361,366,370,376,381,385,390,396,401,406],{"type":31,"tag":171,"props":347,"children":348},{"style":219},[349],{"type":40,"value":350},"  async",{"type":31,"tag":171,"props":352,"children":353},{"style":203},[354],{"type":40,"value":355}," sendSessionConfirmation",{"type":31,"tag":171,"props":357,"children":358},{"style":236},[359],{"type":40,"value":360},"(",{"type":31,"tag":171,"props":362,"children":363},{"style":270},[364],{"type":40,"value":365},"sessionId",{"type":31,"tag":171,"props":367,"children":368},{"style":276},[369],{"type":40,"value":279},{"type":31,"tag":171,"props":371,"children":373},{"style":372},"--shiki-default:#CA9EE6;--shiki-dark:#79B8FF",[374],{"type":40,"value":375}," string",{"type":31,"tag":171,"props":377,"children":378},{"style":236},[379],{"type":40,"value":380},")",{"type":31,"tag":171,"props":382,"children":383},{"style":276},[384],{"type":40,"value":279},{"type":31,"tag":171,"props":386,"children":387},{"style":230},[388],{"type":40,"value":389}," Promise",{"type":31,"tag":171,"props":391,"children":393},{"style":392},"--shiki-default:#99D1DB;--shiki-dark:#E1E4E8",[394],{"type":40,"value":395},"\u003C",{"type":31,"tag":171,"props":397,"children":398},{"style":372},[399],{"type":40,"value":400},"void",{"type":31,"tag":171,"props":402,"children":403},{"style":392},[404],{"type":40,"value":405},">",{"type":31,"tag":171,"props":407,"children":408},{"style":236},[409],{"type":40,"value":239},{"type":31,"tag":171,"props":411,"children":413},{"class":173,"line":412},11,[414,419,425,430,435,441,447,453,457,462,467],{"type":31,"tag":171,"props":415,"children":416},{"style":219},[417],{"type":40,"value":418},"    const",{"type":31,"tag":171,"props":420,"children":422},{"style":421},"--shiki-default:#C6D0F5;--shiki-dark:#79B8FF",[423],{"type":40,"value":424}," session",{"type":31,"tag":171,"props":426,"children":427},{"style":276},[428],{"type":40,"value":429}," =",{"type":31,"tag":171,"props":431,"children":432},{"style":219},[433],{"type":40,"value":434}," await",{"type":31,"tag":171,"props":436,"children":438},{"style":437},"--shiki-default:#E78284;--shiki-dark:#79B8FF",[439],{"type":40,"value":440}," this",{"type":31,"tag":171,"props":442,"children":444},{"style":443},"--shiki-default:#81C8BE;--shiki-dark:#E1E4E8",[445],{"type":40,"value":446},".",{"type":31,"tag":171,"props":448,"children":450},{"style":449},"--shiki-default:#C6D0F5;--shiki-dark:#E1E4E8",[451],{"type":40,"value":452},"sessionRepository",{"type":31,"tag":171,"props":454,"children":455},{"style":443},[456],{"type":40,"value":446},{"type":31,"tag":171,"props":458,"children":459},{"style":203},[460],{"type":40,"value":461},"findById",{"type":31,"tag":171,"props":463,"children":464},{"style":449},[465],{"type":40,"value":466},"(sessionId)",{"type":31,"tag":171,"props":468,"children":469},{"style":236},[470],{"type":40,"value":471},";\n",{"type":31,"tag":171,"props":473,"children":475},{"class":173,"line":474},12,[476,481,486,491,496,501,507,512,516,522,528,532,537,542,546],{"type":31,"tag":171,"props":477,"children":478},{"style":219},[479],{"type":40,"value":480},"    if",{"type":31,"tag":171,"props":482,"children":483},{"style":449},[484],{"type":40,"value":485}," (",{"type":31,"tag":171,"props":487,"children":488},{"style":276},[489],{"type":40,"value":490},"!",{"type":31,"tag":171,"props":492,"children":493},{"style":449},[494],{"type":40,"value":495},"session) ",{"type":31,"tag":171,"props":497,"children":498},{"style":219},[499],{"type":40,"value":500},"throw",{"type":31,"tag":171,"props":502,"children":504},{"style":503},"--shiki-default:#CA9EE6;--shiki-default-font-weight:bold;--shiki-dark:#F97583;--shiki-dark-font-weight:inherit",[505],{"type":40,"value":506}," new",{"type":31,"tag":171,"props":508,"children":509},{"style":203},[510],{"type":40,"value":511}," Error",{"type":31,"tag":171,"props":513,"children":514},{"style":449},[515],{"type":40,"value":360},{"type":31,"tag":171,"props":517,"children":519},{"style":518},"--shiki-default:#A6D189;--shiki-dark:#9ECBFF",[520],{"type":40,"value":521},"`Session not found: ",{"type":31,"tag":171,"props":523,"children":525},{"style":524},"--shiki-default:#949CBB;--shiki-dark:#9ECBFF",[526],{"type":40,"value":527},"${",{"type":31,"tag":171,"props":529,"children":530},{"style":449},[531],{"type":40,"value":365},{"type":31,"tag":171,"props":533,"children":534},{"style":524},[535],{"type":40,"value":536},"}",{"type":31,"tag":171,"props":538,"children":539},{"style":518},[540],{"type":40,"value":541},"`",{"type":31,"tag":171,"props":543,"children":544},{"style":449},[545],{"type":40,"value":380},{"type":31,"tag":171,"props":547,"children":548},{"style":236},[549],{"type":40,"value":471},{"type":31,"tag":171,"props":551,"children":553},{"class":173,"line":552},13,[554],{"type":31,"tag":171,"props":555,"children":556},{"emptyLinePlaceholder":13},[557],{"type":40,"value":190},{"type":31,"tag":171,"props":559,"children":561},{"class":173,"line":560},14,[562,567,571,575,580,584,589,593],{"type":31,"tag":171,"props":563,"children":564},{"style":219},[565],{"type":40,"value":566},"    await",{"type":31,"tag":171,"props":568,"children":569},{"style":437},[570],{"type":40,"value":440},{"type":31,"tag":171,"props":572,"children":573},{"style":443},[574],{"type":40,"value":446},{"type":31,"tag":171,"props":576,"children":577},{"style":449},[578],{"type":40,"value":579},"brevoClient",{"type":31,"tag":171,"props":581,"children":582},{"style":443},[583],{"type":40,"value":446},{"type":31,"tag":171,"props":585,"children":586},{"style":203},[587],{"type":40,"value":588},"sendTransactionalEmail",{"type":31,"tag":171,"props":590,"children":591},{"style":449},[592],{"type":40,"value":360},{"type":31,"tag":171,"props":594,"children":595},{"style":236},[596],{"type":40,"value":597},"{\n",{"type":31,"tag":171,"props":599,"children":601},{"class":173,"line":600},15,[602,607,611,616,621,626,630,634,638,643,647,652],{"type":31,"tag":171,"props":603,"children":604},{"style":449},[605],{"type":40,"value":606},"      to",{"type":31,"tag":171,"props":608,"children":609},{"style":443},[610],{"type":40,"value":279},{"type":31,"tag":171,"props":612,"children":613},{"style":449},[614],{"type":40,"value":615}," [",{"type":31,"tag":171,"props":617,"children":618},{"style":236},[619],{"type":40,"value":620},"{",{"type":31,"tag":171,"props":622,"children":623},{"style":449},[624],{"type":40,"value":625}," email",{"type":31,"tag":171,"props":627,"children":628},{"style":443},[629],{"type":40,"value":279},{"type":31,"tag":171,"props":631,"children":632},{"style":449},[633],{"type":40,"value":424},{"type":31,"tag":171,"props":635,"children":636},{"style":443},[637],{"type":40,"value":446},{"type":31,"tag":171,"props":639,"children":640},{"style":449},[641],{"type":40,"value":642},"coacheeEmail ",{"type":31,"tag":171,"props":644,"children":645},{"style":236},[646],{"type":40,"value":536},{"type":31,"tag":171,"props":648,"children":649},{"style":449},[650],{"type":40,"value":651},"]",{"type":31,"tag":171,"props":653,"children":654},{"style":236},[655],{"type":40,"value":289},{"type":31,"tag":171,"props":657,"children":659},{"class":173,"line":658},16,[660,665,669,675,679,684],{"type":31,"tag":171,"props":661,"children":662},{"style":449},[663],{"type":40,"value":664},"      templateId",{"type":31,"tag":171,"props":666,"children":667},{"style":443},[668],{"type":40,"value":279},{"type":31,"tag":171,"props":670,"children":672},{"style":671},"--shiki-default:#EF9F76;--shiki-dark:#79B8FF",[673],{"type":40,"value":674}," BREVO_TEMPLATE_IDS",{"type":31,"tag":171,"props":676,"children":677},{"style":443},[678],{"type":40,"value":446},{"type":31,"tag":171,"props":680,"children":681},{"style":671},[682],{"type":40,"value":683},"SESSION_CONFIRMATION",{"type":31,"tag":171,"props":685,"children":686},{"style":236},[687],{"type":40,"value":289},{"type":31,"tag":171,"props":689,"children":691},{"class":173,"line":690},17,[692,697,701,706,711,715,719,723,728],{"type":31,"tag":171,"props":693,"children":694},{"style":449},[695],{"type":40,"value":696},"      params",{"type":31,"tag":171,"props":698,"children":699},{"style":443},[700],{"type":40,"value":279},{"type":31,"tag":171,"props":702,"children":703},{"style":236},[704],{"type":40,"value":705}," {",{"type":31,"tag":171,"props":707,"children":708},{"style":449},[709],{"type":40,"value":710}," sessionDate",{"type":31,"tag":171,"props":712,"children":713},{"style":443},[714],{"type":40,"value":279},{"type":31,"tag":171,"props":716,"children":717},{"style":449},[718],{"type":40,"value":424},{"type":31,"tag":171,"props":720,"children":721},{"style":443},[722],{"type":40,"value":446},{"type":31,"tag":171,"props":724,"children":725},{"style":449},[726],{"type":40,"value":727},"scheduledAt ",{"type":31,"tag":171,"props":729,"children":730},{"style":236},[731],{"type":40,"value":732},"},\n",{"type":31,"tag":171,"props":734,"children":736},{"class":173,"line":735},18,[737,742,746],{"type":31,"tag":171,"props":738,"children":739},{"style":236},[740],{"type":40,"value":741},"    }",{"type":31,"tag":171,"props":743,"children":744},{"style":449},[745],{"type":40,"value":380},{"type":31,"tag":171,"props":747,"children":748},{"style":236},[749],{"type":40,"value":471},{"type":31,"tag":171,"props":751,"children":753},{"class":173,"line":752},19,[754],{"type":31,"tag":171,"props":755,"children":756},{"style":236},[757],{"type":40,"value":758},"  }\n",{"type":31,"tag":171,"props":760,"children":762},{"class":173,"line":761},20,[763],{"type":31,"tag":171,"props":764,"children":765},{"style":236},[766],{"type":40,"value":767},"}\n",{"type":31,"tag":32,"props":769,"children":770},{},[771,773,779,781,787,789,795],{"type":40,"value":772},"Le code est propre, lisible, testable. Les tests unitaires Vitest mockaient ",{"type":31,"tag":88,"props":774,"children":776},{"className":775},[],[777],{"type":40,"value":778},"sessionRepository.findById",{"type":40,"value":780}," et ",{"type":31,"tag":88,"props":782,"children":784},{"className":783},[],[785],{"type":40,"value":786},"brevoClient.sendTransactionalEmail",{"type":40,"value":788}," avec ",{"type":31,"tag":88,"props":790,"children":792},{"className":791},[],[793],{"type":40,"value":794},"vi.fn()",{"type":40,"value":796},". Tous verts. Tous tautologiques.",{"type":31,"tag":32,"props":798,"children":799},{},[800,802,808,810,815,817,823],{"type":40,"value":801},"Voici ce qui s'est passé en prod. Un mardi à 2h47, mon job de rappel de séances a lancé plusieurs ",{"type":31,"tag":88,"props":803,"children":805},{"className":804},[],[806],{"type":40,"value":807},"sendSessionConfirmation",{"type":40,"value":809}," en parallèle via ",{"type":31,"tag":88,"props":811,"children":813},{"className":812},[],[814],{"type":40,"value":123},{"type":40,"value":816}," pour un groupe de coachees dont les séances étaient le lendemain matin. Brevo, comme tous les providers d'emails transactionnels, a un rate limit. À partir d'un certain nombre d'appels par seconde, il renvoie ",{"type":31,"tag":88,"props":818,"children":820},{"className":819},[],[821],{"type":40,"value":822},"429 Too Many Requests",{"type":40,"value":824},". Mon code ne gérait pas ce 429. L'exception remontait. Le job scheduler marquait les envois en échec. Aucun retry, parce que la stratégie de retry n'avait pas été codée pour ce service.",{"type":31,"tag":32,"props":826,"children":827},{},[828],{"type":40,"value":829},"Résultat : plusieurs coachees n'avaient pas reçu leur confirmation de séance. Certains ne s'étaient pas présentés le lendemain matin, pensant que la séance avait été annulée. La confiance envers le SaaS en avait pris un coup, et moi j'avais passé la matinée à déboguer au lieu de développer.",{"type":31,"tag":32,"props":831,"children":832},{},[833,835,841],{"type":40,"value":834},"Et tout ça parce qu'aucun test n'avait simulé ces 4 conditions de production. Le pire, c'est que les ",{"type":31,"tag":64,"props":836,"children":838},{"href":837},"/fr/dette-technique/clean-code-software-craftsmanship-principes-java",[839],{"type":40,"value":840},"principes de clean code et software craftsmanship",{"type":40,"value":842}," auraient suffi à rendre cette fonction testable sous concurrence, mais je ne les avais pas formalisés dans mes prompts à Claude.",{"type":31,"tag":48,"props":844,"children":845},{},[],{"type":31,"tag":847,"props":848,"children":853},"cta",{"cta":849,"href":850,"title":851,"type":852},"Coder comme un senior →","https://app.kamanga.fr/forms/mentoring","Vous voulez écrire vous-même les tests que Claude ne génère jamais ?","call",[854],{"type":31,"tag":32,"props":855,"children":856},{},[857],{"type":40,"value":858},"Repérer un mode d'échec absent du filet de tests, ça ne s'apprend pas en lisant un article : ça se travaille. En mentoring 1:1, on prend votre vrai code généré par IA et on écrit ensemble les tests de concurrence, de rate limit et de timeout sur vos fonctions critiques. Vous repartez avec le réflexe d'exiger ces tests avant chaque merge, sans dépendre de personne.",{"type":31,"tag":48,"props":860,"children":861},{},[],{"type":31,"tag":52,"props":863,"children":865},{"id":864},"les-4-tests-que-claude-nécrit-jamais",[866],{"type":40,"value":867},"Les 4 tests que Claude n'écrit jamais",{"type":31,"tag":32,"props":869,"children":870},{},[871],{"type":40,"value":872},"Voici les 4 tests que j'exige maintenant sur tout code Claude qui touche à une dépendance externe (réseau, DB, queue, file system). Les exemples sont en Vitest/TypeScript, dans le contexte crmcoaching.",{"type":31,"tag":874,"props":875,"children":877},"h3",{"id":876},"test-1-le-test-de-concurrence",[878],{"type":40,"value":879},"Test 1 : le test de concurrence",{"type":31,"tag":32,"props":881,"children":882},{},[883,885,890,892,898],{"type":40,"value":884},"Soumettez la fonction en parallèle via ",{"type":31,"tag":88,"props":886,"children":888},{"className":887},[],[889],{"type":40,"value":123},{"type":40,"value":891}," ou ",{"type":31,"tag":88,"props":893,"children":895},{"className":894},[],[896],{"type":40,"value":897},"Promise.allSettled",{"type":40,"value":899}," sur la même ressource ou avec des paramètres qui peuvent se télescoper. Vérifiez que l'état final est cohérent.",{"type":31,"tag":161,"props":901,"children":903},{"className":163,"code":902,"language":165,"meta":8,"style":8},"// apps/api/src/infrastructure/notification/brevo-notification.service.spec.ts\n\nit('handles 50 concurrent session confirmations without losing any', async () => {\n  const sessionIds = Array.from({ length: 50 }, (_, i) => `session-${i}`);\n\n  // mock : toutes les sessions existent, Brevo répond OK\n  vi.mocked(sessionRepository.findById).mockImplementation(async (id) => ({\n    id,\n    coacheeEmail: `coach-${id}@example.com`,\n    scheduledAt: new Date('2026-06-10T09:00:00Z'),\n  }));\n  vi.mocked(brevoClient.sendTransactionalEmail).mockResolvedValue(undefined);\n\n  const results = await Promise.allSettled(\n    sessionIds.map((id) => service.sendSessionConfirmation(id)),\n  );\n\n  const failed = results.filter((r) => r.status === 'rejected');\n  expect(failed).toHaveLength(0);\n  expect(brevoClient.sendTransactionalEmail).toHaveBeenCalledTimes(50);\n});\n",[904],{"type":31,"tag":88,"props":905,"children":906},{"__ignoreMap":8},[907,915,922,963,1077,1084,1092,1166,1178,1216,1254,1271,1326,1333,1371,1430,1441,1448,1530,1569,1614],{"type":31,"tag":171,"props":908,"children":909},{"class":173,"line":174},[910],{"type":31,"tag":171,"props":911,"children":912},{"style":178},[913],{"type":40,"value":914},"// apps/api/src/infrastructure/notification/brevo-notification.service.spec.ts\n",{"type":31,"tag":171,"props":916,"children":917},{"class":173,"line":184},[918],{"type":31,"tag":171,"props":919,"children":920},{"emptyLinePlaceholder":13},[921],{"type":40,"value":190},{"type":31,"tag":171,"props":923,"children":924},{"class":173,"line":193},[925,930,934,939,944,949,954,959],{"type":31,"tag":171,"props":926,"children":927},{"style":203},[928],{"type":40,"value":929},"it",{"type":31,"tag":171,"props":931,"children":932},{"style":449},[933],{"type":40,"value":360},{"type":31,"tag":171,"props":935,"children":936},{"style":518},[937],{"type":40,"value":938},"'handles 50 concurrent session confirmations without losing any'",{"type":31,"tag":171,"props":940,"children":941},{"style":236},[942],{"type":40,"value":943},",",{"type":31,"tag":171,"props":945,"children":946},{"style":219},[947],{"type":40,"value":948}," async",{"type":31,"tag":171,"props":950,"children":951},{"style":236},[952],{"type":40,"value":953}," ()",{"type":31,"tag":171,"props":955,"children":956},{"style":276},[957],{"type":40,"value":958}," =>",{"type":31,"tag":171,"props":960,"children":961},{"style":236},[962],{"type":40,"value":239},{"type":31,"tag":171,"props":964,"children":965},{"class":173,"line":215},[966,971,976,980,985,989,994,998,1002,1007,1011,1016,1021,1025,1030,1034,1039,1043,1047,1052,1056,1061,1065,1069,1073],{"type":31,"tag":171,"props":967,"children":968},{"style":219},[969],{"type":40,"value":970},"  const",{"type":31,"tag":171,"props":972,"children":973},{"style":421},[974],{"type":40,"value":975}," sessionIds",{"type":31,"tag":171,"props":977,"children":978},{"style":276},[979],{"type":40,"value":429},{"type":31,"tag":171,"props":981,"children":982},{"style":449},[983],{"type":40,"value":984}," Array",{"type":31,"tag":171,"props":986,"children":987},{"style":443},[988],{"type":40,"value":446},{"type":31,"tag":171,"props":990,"children":991},{"style":203},[992],{"type":40,"value":993},"from",{"type":31,"tag":171,"props":995,"children":996},{"style":449},[997],{"type":40,"value":360},{"type":31,"tag":171,"props":999,"children":1000},{"style":236},[1001],{"type":40,"value":620},{"type":31,"tag":171,"props":1003,"children":1004},{"style":449},[1005],{"type":40,"value":1006}," length",{"type":31,"tag":171,"props":1008,"children":1009},{"style":443},[1010],{"type":40,"value":279},{"type":31,"tag":171,"props":1012,"children":1013},{"style":671},[1014],{"type":40,"value":1015}," 50",{"type":31,"tag":171,"props":1017,"children":1018},{"style":236},[1019],{"type":40,"value":1020}," },",{"type":31,"tag":171,"props":1022,"children":1023},{"style":236},[1024],{"type":40,"value":485},{"type":31,"tag":171,"props":1026,"children":1027},{"style":270},[1028],{"type":40,"value":1029},"_",{"type":31,"tag":171,"props":1031,"children":1032},{"style":236},[1033],{"type":40,"value":943},{"type":31,"tag":171,"props":1035,"children":1036},{"style":270},[1037],{"type":40,"value":1038}," i",{"type":31,"tag":171,"props":1040,"children":1041},{"style":236},[1042],{"type":40,"value":380},{"type":31,"tag":171,"props":1044,"children":1045},{"style":276},[1046],{"type":40,"value":958},{"type":31,"tag":171,"props":1048,"children":1049},{"style":518},[1050],{"type":40,"value":1051}," `session-",{"type":31,"tag":171,"props":1053,"children":1054},{"style":524},[1055],{"type":40,"value":527},{"type":31,"tag":171,"props":1057,"children":1058},{"style":449},[1059],{"type":40,"value":1060},"i",{"type":31,"tag":171,"props":1062,"children":1063},{"style":524},[1064],{"type":40,"value":536},{"type":31,"tag":171,"props":1066,"children":1067},{"style":518},[1068],{"type":40,"value":541},{"type":31,"tag":171,"props":1070,"children":1071},{"style":449},[1072],{"type":40,"value":380},{"type":31,"tag":171,"props":1074,"children":1075},{"style":236},[1076],{"type":40,"value":471},{"type":31,"tag":171,"props":1078,"children":1079},{"class":173,"line":242},[1080],{"type":31,"tag":171,"props":1081,"children":1082},{"emptyLinePlaceholder":13},[1083],{"type":40,"value":190},{"type":31,"tag":171,"props":1085,"children":1086},{"class":173,"line":256},[1087],{"type":31,"tag":171,"props":1088,"children":1089},{"style":178},[1090],{"type":40,"value":1091},"  // mock : toutes les sessions existent, Brevo répond OK\n",{"type":31,"tag":171,"props":1093,"children":1094},{"class":173,"line":292},[1095,1100,1104,1109,1114,1118,1123,1127,1132,1136,1141,1145,1150,1154,1158,1162],{"type":31,"tag":171,"props":1096,"children":1097},{"style":449},[1098],{"type":40,"value":1099},"  vi",{"type":31,"tag":171,"props":1101,"children":1102},{"style":443},[1103],{"type":40,"value":446},{"type":31,"tag":171,"props":1105,"children":1106},{"style":203},[1107],{"type":40,"value":1108},"mocked",{"type":31,"tag":171,"props":1110,"children":1111},{"style":449},[1112],{"type":40,"value":1113},"(sessionRepository",{"type":31,"tag":171,"props":1115,"children":1116},{"style":443},[1117],{"type":40,"value":446},{"type":31,"tag":171,"props":1119,"children":1120},{"style":449},[1121],{"type":40,"value":1122},"findById)",{"type":31,"tag":171,"props":1124,"children":1125},{"style":443},[1126],{"type":40,"value":446},{"type":31,"tag":171,"props":1128,"children":1129},{"style":203},[1130],{"type":40,"value":1131},"mockImplementation",{"type":31,"tag":171,"props":1133,"children":1134},{"style":449},[1135],{"type":40,"value":360},{"type":31,"tag":171,"props":1137,"children":1138},{"style":219},[1139],{"type":40,"value":1140},"async",{"type":31,"tag":171,"props":1142,"children":1143},{"style":236},[1144],{"type":40,"value":485},{"type":31,"tag":171,"props":1146,"children":1147},{"style":270},[1148],{"type":40,"value":1149},"id",{"type":31,"tag":171,"props":1151,"children":1152},{"style":236},[1153],{"type":40,"value":380},{"type":31,"tag":171,"props":1155,"children":1156},{"style":276},[1157],{"type":40,"value":958},{"type":31,"tag":171,"props":1159,"children":1160},{"style":449},[1161],{"type":40,"value":485},{"type":31,"tag":171,"props":1163,"children":1164},{"style":236},[1165],{"type":40,"value":597},{"type":31,"tag":171,"props":1167,"children":1168},{"class":173,"line":322},[1169,1174],{"type":31,"tag":171,"props":1170,"children":1171},{"style":449},[1172],{"type":40,"value":1173},"    id",{"type":31,"tag":171,"props":1175,"children":1176},{"style":236},[1177],{"type":40,"value":289},{"type":31,"tag":171,"props":1179,"children":1180},{"class":173,"line":336},[1181,1186,1190,1195,1199,1203,1207,1212],{"type":31,"tag":171,"props":1182,"children":1183},{"style":449},[1184],{"type":40,"value":1185},"    coacheeEmail",{"type":31,"tag":171,"props":1187,"children":1188},{"style":443},[1189],{"type":40,"value":279},{"type":31,"tag":171,"props":1191,"children":1192},{"style":518},[1193],{"type":40,"value":1194}," `coach-",{"type":31,"tag":171,"props":1196,"children":1197},{"style":524},[1198],{"type":40,"value":527},{"type":31,"tag":171,"props":1200,"children":1201},{"style":449},[1202],{"type":40,"value":1149},{"type":31,"tag":171,"props":1204,"children":1205},{"style":524},[1206],{"type":40,"value":536},{"type":31,"tag":171,"props":1208,"children":1209},{"style":518},[1210],{"type":40,"value":1211},"@example.com`",{"type":31,"tag":171,"props":1213,"children":1214},{"style":236},[1215],{"type":40,"value":289},{"type":31,"tag":171,"props":1217,"children":1218},{"class":173,"line":344},[1219,1224,1228,1232,1237,1241,1246,1250],{"type":31,"tag":171,"props":1220,"children":1221},{"style":449},[1222],{"type":40,"value":1223},"    scheduledAt",{"type":31,"tag":171,"props":1225,"children":1226},{"style":443},[1227],{"type":40,"value":279},{"type":31,"tag":171,"props":1229,"children":1230},{"style":503},[1231],{"type":40,"value":506},{"type":31,"tag":171,"props":1233,"children":1234},{"style":203},[1235],{"type":40,"value":1236}," Date",{"type":31,"tag":171,"props":1238,"children":1239},{"style":449},[1240],{"type":40,"value":360},{"type":31,"tag":171,"props":1242,"children":1243},{"style":518},[1244],{"type":40,"value":1245},"'2026-06-10T09:00:00Z'",{"type":31,"tag":171,"props":1247,"children":1248},{"style":449},[1249],{"type":40,"value":380},{"type":31,"tag":171,"props":1251,"children":1252},{"style":236},[1253],{"type":40,"value":289},{"type":31,"tag":171,"props":1255,"children":1256},{"class":173,"line":412},[1257,1262,1267],{"type":31,"tag":171,"props":1258,"children":1259},{"style":236},[1260],{"type":40,"value":1261},"  }",{"type":31,"tag":171,"props":1263,"children":1264},{"style":449},[1265],{"type":40,"value":1266},"))",{"type":31,"tag":171,"props":1268,"children":1269},{"style":236},[1270],{"type":40,"value":471},{"type":31,"tag":171,"props":1272,"children":1273},{"class":173,"line":474},[1274,1278,1282,1286,1291,1295,1300,1304,1309,1313,1318,1322],{"type":31,"tag":171,"props":1275,"children":1276},{"style":449},[1277],{"type":40,"value":1099},{"type":31,"tag":171,"props":1279,"children":1280},{"style":443},[1281],{"type":40,"value":446},{"type":31,"tag":171,"props":1283,"children":1284},{"style":203},[1285],{"type":40,"value":1108},{"type":31,"tag":171,"props":1287,"children":1288},{"style":449},[1289],{"type":40,"value":1290},"(brevoClient",{"type":31,"tag":171,"props":1292,"children":1293},{"style":443},[1294],{"type":40,"value":446},{"type":31,"tag":171,"props":1296,"children":1297},{"style":449},[1298],{"type":40,"value":1299},"sendTransactionalEmail)",{"type":31,"tag":171,"props":1301,"children":1302},{"style":443},[1303],{"type":40,"value":446},{"type":31,"tag":171,"props":1305,"children":1306},{"style":203},[1307],{"type":40,"value":1308},"mockResolvedValue",{"type":31,"tag":171,"props":1310,"children":1311},{"style":449},[1312],{"type":40,"value":360},{"type":31,"tag":171,"props":1314,"children":1315},{"style":372},[1316],{"type":40,"value":1317},"undefined",{"type":31,"tag":171,"props":1319,"children":1320},{"style":449},[1321],{"type":40,"value":380},{"type":31,"tag":171,"props":1323,"children":1324},{"style":236},[1325],{"type":40,"value":471},{"type":31,"tag":171,"props":1327,"children":1328},{"class":173,"line":552},[1329],{"type":31,"tag":171,"props":1330,"children":1331},{"emptyLinePlaceholder":13},[1332],{"type":40,"value":190},{"type":31,"tag":171,"props":1334,"children":1335},{"class":173,"line":560},[1336,1340,1345,1349,1353,1358,1362,1367],{"type":31,"tag":171,"props":1337,"children":1338},{"style":219},[1339],{"type":40,"value":970},{"type":31,"tag":171,"props":1341,"children":1342},{"style":421},[1343],{"type":40,"value":1344}," results",{"type":31,"tag":171,"props":1346,"children":1347},{"style":276},[1348],{"type":40,"value":429},{"type":31,"tag":171,"props":1350,"children":1351},{"style":219},[1352],{"type":40,"value":434},{"type":31,"tag":171,"props":1354,"children":1356},{"style":1355},"--shiki-default:#E5C890;--shiki-default-font-style:italic;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit",[1357],{"type":40,"value":389},{"type":31,"tag":171,"props":1359,"children":1360},{"style":443},[1361],{"type":40,"value":446},{"type":31,"tag":171,"props":1363,"children":1364},{"style":203},[1365],{"type":40,"value":1366},"allSettled",{"type":31,"tag":171,"props":1368,"children":1369},{"style":449},[1370],{"type":40,"value":253},{"type":31,"tag":171,"props":1372,"children":1373},{"class":173,"line":600},[1374,1379,1383,1388,1392,1396,1400,1404,1408,1413,1417,1421,1426],{"type":31,"tag":171,"props":1375,"children":1376},{"style":449},[1377],{"type":40,"value":1378},"    sessionIds",{"type":31,"tag":171,"props":1380,"children":1381},{"style":443},[1382],{"type":40,"value":446},{"type":31,"tag":171,"props":1384,"children":1385},{"style":203},[1386],{"type":40,"value":1387},"map",{"type":31,"tag":171,"props":1389,"children":1390},{"style":449},[1391],{"type":40,"value":360},{"type":31,"tag":171,"props":1393,"children":1394},{"style":236},[1395],{"type":40,"value":360},{"type":31,"tag":171,"props":1397,"children":1398},{"style":270},[1399],{"type":40,"value":1149},{"type":31,"tag":171,"props":1401,"children":1402},{"style":236},[1403],{"type":40,"value":380},{"type":31,"tag":171,"props":1405,"children":1406},{"style":276},[1407],{"type":40,"value":958},{"type":31,"tag":171,"props":1409,"children":1410},{"style":449},[1411],{"type":40,"value":1412}," service",{"type":31,"tag":171,"props":1414,"children":1415},{"style":443},[1416],{"type":40,"value":446},{"type":31,"tag":171,"props":1418,"children":1419},{"style":203},[1420],{"type":40,"value":807},{"type":31,"tag":171,"props":1422,"children":1423},{"style":449},[1424],{"type":40,"value":1425},"(id))",{"type":31,"tag":171,"props":1427,"children":1428},{"style":236},[1429],{"type":40,"value":289},{"type":31,"tag":171,"props":1431,"children":1432},{"class":173,"line":658},[1433,1437],{"type":31,"tag":171,"props":1434,"children":1435},{"style":449},[1436],{"type":40,"value":328},{"type":31,"tag":171,"props":1438,"children":1439},{"style":236},[1440],{"type":40,"value":471},{"type":31,"tag":171,"props":1442,"children":1443},{"class":173,"line":690},[1444],{"type":31,"tag":171,"props":1445,"children":1446},{"emptyLinePlaceholder":13},[1447],{"type":40,"value":190},{"type":31,"tag":171,"props":1449,"children":1450},{"class":173,"line":735},[1451,1455,1460,1464,1468,1472,1477,1481,1485,1490,1494,1498,1503,1507,1512,1517,1522,1526],{"type":31,"tag":171,"props":1452,"children":1453},{"style":219},[1454],{"type":40,"value":970},{"type":31,"tag":171,"props":1456,"children":1457},{"style":421},[1458],{"type":40,"value":1459}," failed",{"type":31,"tag":171,"props":1461,"children":1462},{"style":276},[1463],{"type":40,"value":429},{"type":31,"tag":171,"props":1465,"children":1466},{"style":449},[1467],{"type":40,"value":1344},{"type":31,"tag":171,"props":1469,"children":1470},{"style":443},[1471],{"type":40,"value":446},{"type":31,"tag":171,"props":1473,"children":1474},{"style":203},[1475],{"type":40,"value":1476},"filter",{"type":31,"tag":171,"props":1478,"children":1479},{"style":449},[1480],{"type":40,"value":360},{"type":31,"tag":171,"props":1482,"children":1483},{"style":236},[1484],{"type":40,"value":360},{"type":31,"tag":171,"props":1486,"children":1487},{"style":270},[1488],{"type":40,"value":1489},"r",{"type":31,"tag":171,"props":1491,"children":1492},{"style":236},[1493],{"type":40,"value":380},{"type":31,"tag":171,"props":1495,"children":1496},{"style":276},[1497],{"type":40,"value":958},{"type":31,"tag":171,"props":1499,"children":1500},{"style":449},[1501],{"type":40,"value":1502}," r",{"type":31,"tag":171,"props":1504,"children":1505},{"style":443},[1506],{"type":40,"value":446},{"type":31,"tag":171,"props":1508,"children":1509},{"style":449},[1510],{"type":40,"value":1511},"status ",{"type":31,"tag":171,"props":1513,"children":1514},{"style":276},[1515],{"type":40,"value":1516},"===",{"type":31,"tag":171,"props":1518,"children":1519},{"style":518},[1520],{"type":40,"value":1521}," 'rejected'",{"type":31,"tag":171,"props":1523,"children":1524},{"style":449},[1525],{"type":40,"value":380},{"type":31,"tag":171,"props":1527,"children":1528},{"style":236},[1529],{"type":40,"value":471},{"type":31,"tag":171,"props":1531,"children":1532},{"class":173,"line":752},[1533,1538,1543,1547,1552,1556,1561,1565],{"type":31,"tag":171,"props":1534,"children":1535},{"style":203},[1536],{"type":40,"value":1537},"  expect",{"type":31,"tag":171,"props":1539,"children":1540},{"style":449},[1541],{"type":40,"value":1542},"(failed)",{"type":31,"tag":171,"props":1544,"children":1545},{"style":443},[1546],{"type":40,"value":446},{"type":31,"tag":171,"props":1548,"children":1549},{"style":203},[1550],{"type":40,"value":1551},"toHaveLength",{"type":31,"tag":171,"props":1553,"children":1554},{"style":449},[1555],{"type":40,"value":360},{"type":31,"tag":171,"props":1557,"children":1558},{"style":671},[1559],{"type":40,"value":1560},"0",{"type":31,"tag":171,"props":1562,"children":1563},{"style":449},[1564],{"type":40,"value":380},{"type":31,"tag":171,"props":1566,"children":1567},{"style":236},[1568],{"type":40,"value":471},{"type":31,"tag":171,"props":1570,"children":1571},{"class":173,"line":761},[1572,1576,1580,1584,1588,1592,1597,1601,1606,1610],{"type":31,"tag":171,"props":1573,"children":1574},{"style":203},[1575],{"type":40,"value":1537},{"type":31,"tag":171,"props":1577,"children":1578},{"style":449},[1579],{"type":40,"value":1290},{"type":31,"tag":171,"props":1581,"children":1582},{"style":443},[1583],{"type":40,"value":446},{"type":31,"tag":171,"props":1585,"children":1586},{"style":449},[1587],{"type":40,"value":1299},{"type":31,"tag":171,"props":1589,"children":1590},{"style":443},[1591],{"type":40,"value":446},{"type":31,"tag":171,"props":1593,"children":1594},{"style":203},[1595],{"type":40,"value":1596},"toHaveBeenCalledTimes",{"type":31,"tag":171,"props":1598,"children":1599},{"style":449},[1600],{"type":40,"value":360},{"type":31,"tag":171,"props":1602,"children":1603},{"style":671},[1604],{"type":40,"value":1605},"50",{"type":31,"tag":171,"props":1607,"children":1608},{"style":449},[1609],{"type":40,"value":380},{"type":31,"tag":171,"props":1611,"children":1612},{"style":236},[1613],{"type":40,"value":471},{"type":31,"tag":171,"props":1615,"children":1617},{"class":173,"line":1616},21,[1618,1622,1626],{"type":31,"tag":171,"props":1619,"children":1620},{"style":236},[1621],{"type":40,"value":536},{"type":31,"tag":171,"props":1623,"children":1624},{"style":449},[1625],{"type":40,"value":380},{"type":31,"tag":171,"props":1627,"children":1628},{"style":236},[1629],{"type":40,"value":471},{"type":31,"tag":32,"props":1631,"children":1632},{},[1633,1635],{"type":40,"value":1634},"Ce test, Claude ne l'écrit pas spontanément. Il faut le prompter explicitement : ",{"type":31,"tag":132,"props":1636,"children":1637},{},[1638,1640,1645],{"type":40,"value":1639},"\"Écris un test Vitest qui exécute cette méthode 50 fois en parallèle via ",{"type":31,"tag":88,"props":1641,"children":1643},{"className":1642},[],[1644],{"type":40,"value":897},{"type":40,"value":1646}," et vérifie qu'aucune ne rejette.\"",{"type":31,"tag":874,"props":1648,"children":1650},{"id":1649},"test-2-le-test-de-rate-limit-429",[1651],{"type":40,"value":1652},"Test 2 : le test de rate limit (429)",{"type":31,"tag":32,"props":1654,"children":1655},{},[1656],{"type":40,"value":1657},"Mockez la réponse de Brevo pour qu'elle lève une erreur 429 au premier appel. Vérifiez que la méthode retry avec backoff au lieu d'échouer.",{"type":31,"tag":161,"props":1659,"children":1661},{"className":163,"code":1660,"language":165,"meta":8,"style":8},"it('retries with backoff on 429 from Brevo', async () => {\n  vi.mocked(sessionRepository.findById).mockResolvedValue({\n    id: 'session-abc',\n    coacheeEmail: 'coachee@example.com',\n    scheduledAt: new Date(),\n  });\n\n  let callCount = 0;\n  vi.mocked(brevoClient.sendTransactionalEmail).mockImplementation(async () => {\n    callCount += 1;\n    if (callCount === 1) {\n      const err = new Error('Too Many Requests') as Error & { statusCode: number };\n      err.statusCode = 429;\n      throw err;\n    }\n  });\n\n  await service.sendSessionConfirmation('session-abc');\n\n  expect(callCount).toBe(2);\n  expect(brevoClient.sendTransactionalEmail).toHaveBeenCalledTimes(2);\n});\n",[1662],{"type":31,"tag":88,"props":1663,"children":1664},{"__ignoreMap":8},[1665,1701,1744,1764,1784,1812,1827,1834,1861,1916,1938,1967,2043,2073,2089,2097,2112,2119,2156,2163,2201,2244],{"type":31,"tag":171,"props":1666,"children":1667},{"class":173,"line":174},[1668,1672,1676,1681,1685,1689,1693,1697],{"type":31,"tag":171,"props":1669,"children":1670},{"style":203},[1671],{"type":40,"value":929},{"type":31,"tag":171,"props":1673,"children":1674},{"style":449},[1675],{"type":40,"value":360},{"type":31,"tag":171,"props":1677,"children":1678},{"style":518},[1679],{"type":40,"value":1680},"'retries with backoff on 429 from Brevo'",{"type":31,"tag":171,"props":1682,"children":1683},{"style":236},[1684],{"type":40,"value":943},{"type":31,"tag":171,"props":1686,"children":1687},{"style":219},[1688],{"type":40,"value":948},{"type":31,"tag":171,"props":1690,"children":1691},{"style":236},[1692],{"type":40,"value":953},{"type":31,"tag":171,"props":1694,"children":1695},{"style":276},[1696],{"type":40,"value":958},{"type":31,"tag":171,"props":1698,"children":1699},{"style":236},[1700],{"type":40,"value":239},{"type":31,"tag":171,"props":1702,"children":1703},{"class":173,"line":184},[1704,1708,1712,1716,1720,1724,1728,1732,1736,1740],{"type":31,"tag":171,"props":1705,"children":1706},{"style":449},[1707],{"type":40,"value":1099},{"type":31,"tag":171,"props":1709,"children":1710},{"style":443},[1711],{"type":40,"value":446},{"type":31,"tag":171,"props":1713,"children":1714},{"style":203},[1715],{"type":40,"value":1108},{"type":31,"tag":171,"props":1717,"children":1718},{"style":449},[1719],{"type":40,"value":1113},{"type":31,"tag":171,"props":1721,"children":1722},{"style":443},[1723],{"type":40,"value":446},{"type":31,"tag":171,"props":1725,"children":1726},{"style":449},[1727],{"type":40,"value":1122},{"type":31,"tag":171,"props":1729,"children":1730},{"style":443},[1731],{"type":40,"value":446},{"type":31,"tag":171,"props":1733,"children":1734},{"style":203},[1735],{"type":40,"value":1308},{"type":31,"tag":171,"props":1737,"children":1738},{"style":449},[1739],{"type":40,"value":360},{"type":31,"tag":171,"props":1741,"children":1742},{"style":236},[1743],{"type":40,"value":597},{"type":31,"tag":171,"props":1745,"children":1746},{"class":173,"line":193},[1747,1751,1755,1760],{"type":31,"tag":171,"props":1748,"children":1749},{"style":449},[1750],{"type":40,"value":1173},{"type":31,"tag":171,"props":1752,"children":1753},{"style":443},[1754],{"type":40,"value":279},{"type":31,"tag":171,"props":1756,"children":1757},{"style":518},[1758],{"type":40,"value":1759}," 'session-abc'",{"type":31,"tag":171,"props":1761,"children":1762},{"style":236},[1763],{"type":40,"value":289},{"type":31,"tag":171,"props":1765,"children":1766},{"class":173,"line":215},[1767,1771,1775,1780],{"type":31,"tag":171,"props":1768,"children":1769},{"style":449},[1770],{"type":40,"value":1185},{"type":31,"tag":171,"props":1772,"children":1773},{"style":443},[1774],{"type":40,"value":279},{"type":31,"tag":171,"props":1776,"children":1777},{"style":518},[1778],{"type":40,"value":1779}," 'coachee@example.com'",{"type":31,"tag":171,"props":1781,"children":1782},{"style":236},[1783],{"type":40,"value":289},{"type":31,"tag":171,"props":1785,"children":1786},{"class":173,"line":242},[1787,1791,1795,1799,1803,1808],{"type":31,"tag":171,"props":1788,"children":1789},{"style":449},[1790],{"type":40,"value":1223},{"type":31,"tag":171,"props":1792,"children":1793},{"style":443},[1794],{"type":40,"value":279},{"type":31,"tag":171,"props":1796,"children":1797},{"style":503},[1798],{"type":40,"value":506},{"type":31,"tag":171,"props":1800,"children":1801},{"style":203},[1802],{"type":40,"value":1236},{"type":31,"tag":171,"props":1804,"children":1805},{"style":449},[1806],{"type":40,"value":1807},"()",{"type":31,"tag":171,"props":1809,"children":1810},{"style":236},[1811],{"type":40,"value":289},{"type":31,"tag":171,"props":1813,"children":1814},{"class":173,"line":256},[1815,1819,1823],{"type":31,"tag":171,"props":1816,"children":1817},{"style":236},[1818],{"type":40,"value":1261},{"type":31,"tag":171,"props":1820,"children":1821},{"style":449},[1822],{"type":40,"value":380},{"type":31,"tag":171,"props":1824,"children":1825},{"style":236},[1826],{"type":40,"value":471},{"type":31,"tag":171,"props":1828,"children":1829},{"class":173,"line":292},[1830],{"type":31,"tag":171,"props":1831,"children":1832},{"emptyLinePlaceholder":13},[1833],{"type":40,"value":190},{"type":31,"tag":171,"props":1835,"children":1836},{"class":173,"line":322},[1837,1842,1847,1852,1857],{"type":31,"tag":171,"props":1838,"children":1839},{"style":219},[1840],{"type":40,"value":1841},"  let",{"type":31,"tag":171,"props":1843,"children":1844},{"style":449},[1845],{"type":40,"value":1846}," callCount ",{"type":31,"tag":171,"props":1848,"children":1849},{"style":276},[1850],{"type":40,"value":1851},"=",{"type":31,"tag":171,"props":1853,"children":1854},{"style":671},[1855],{"type":40,"value":1856}," 0",{"type":31,"tag":171,"props":1858,"children":1859},{"style":236},[1860],{"type":40,"value":471},{"type":31,"tag":171,"props":1862,"children":1863},{"class":173,"line":336},[1864,1868,1872,1876,1880,1884,1888,1892,1896,1900,1904,1908,1912],{"type":31,"tag":171,"props":1865,"children":1866},{"style":449},[1867],{"type":40,"value":1099},{"type":31,"tag":171,"props":1869,"children":1870},{"style":443},[1871],{"type":40,"value":446},{"type":31,"tag":171,"props":1873,"children":1874},{"style":203},[1875],{"type":40,"value":1108},{"type":31,"tag":171,"props":1877,"children":1878},{"style":449},[1879],{"type":40,"value":1290},{"type":31,"tag":171,"props":1881,"children":1882},{"style":443},[1883],{"type":40,"value":446},{"type":31,"tag":171,"props":1885,"children":1886},{"style":449},[1887],{"type":40,"value":1299},{"type":31,"tag":171,"props":1889,"children":1890},{"style":443},[1891],{"type":40,"value":446},{"type":31,"tag":171,"props":1893,"children":1894},{"style":203},[1895],{"type":40,"value":1131},{"type":31,"tag":171,"props":1897,"children":1898},{"style":449},[1899],{"type":40,"value":360},{"type":31,"tag":171,"props":1901,"children":1902},{"style":219},[1903],{"type":40,"value":1140},{"type":31,"tag":171,"props":1905,"children":1906},{"style":236},[1907],{"type":40,"value":953},{"type":31,"tag":171,"props":1909,"children":1910},{"style":276},[1911],{"type":40,"value":958},{"type":31,"tag":171,"props":1913,"children":1914},{"style":236},[1915],{"type":40,"value":239},{"type":31,"tag":171,"props":1917,"children":1918},{"class":173,"line":344},[1919,1924,1929,1934],{"type":31,"tag":171,"props":1920,"children":1921},{"style":449},[1922],{"type":40,"value":1923},"    callCount ",{"type":31,"tag":171,"props":1925,"children":1926},{"style":276},[1927],{"type":40,"value":1928},"+=",{"type":31,"tag":171,"props":1930,"children":1931},{"style":671},[1932],{"type":40,"value":1933}," 1",{"type":31,"tag":171,"props":1935,"children":1936},{"style":236},[1937],{"type":40,"value":471},{"type":31,"tag":171,"props":1939,"children":1940},{"class":173,"line":412},[1941,1945,1950,1954,1958,1963],{"type":31,"tag":171,"props":1942,"children":1943},{"style":219},[1944],{"type":40,"value":480},{"type":31,"tag":171,"props":1946,"children":1947},{"style":449},[1948],{"type":40,"value":1949}," (callCount ",{"type":31,"tag":171,"props":1951,"children":1952},{"style":276},[1953],{"type":40,"value":1516},{"type":31,"tag":171,"props":1955,"children":1956},{"style":671},[1957],{"type":40,"value":1933},{"type":31,"tag":171,"props":1959,"children":1960},{"style":449},[1961],{"type":40,"value":1962},") ",{"type":31,"tag":171,"props":1964,"children":1965},{"style":236},[1966],{"type":40,"value":597},{"type":31,"tag":171,"props":1968,"children":1969},{"class":173,"line":474},[1970,1975,1980,1984,1988,1992,1996,2001,2005,2010,2014,2019,2023,2029,2033,2038],{"type":31,"tag":171,"props":1971,"children":1972},{"style":219},[1973],{"type":40,"value":1974},"      const",{"type":31,"tag":171,"props":1976,"children":1977},{"style":421},[1978],{"type":40,"value":1979}," err",{"type":31,"tag":171,"props":1981,"children":1982},{"style":276},[1983],{"type":40,"value":429},{"type":31,"tag":171,"props":1985,"children":1986},{"style":503},[1987],{"type":40,"value":506},{"type":31,"tag":171,"props":1989,"children":1990},{"style":203},[1991],{"type":40,"value":511},{"type":31,"tag":171,"props":1993,"children":1994},{"style":449},[1995],{"type":40,"value":360},{"type":31,"tag":171,"props":1997,"children":1998},{"style":518},[1999],{"type":40,"value":2000},"'Too Many Requests'",{"type":31,"tag":171,"props":2002,"children":2003},{"style":449},[2004],{"type":40,"value":1962},{"type":31,"tag":171,"props":2006,"children":2007},{"style":219},[2008],{"type":40,"value":2009},"as",{"type":31,"tag":171,"props":2011,"children":2012},{"style":230},[2013],{"type":40,"value":511},{"type":31,"tag":171,"props":2015,"children":2016},{"style":276},[2017],{"type":40,"value":2018}," &",{"type":31,"tag":171,"props":2020,"children":2021},{"style":236},[2022],{"type":40,"value":705},{"type":31,"tag":171,"props":2024,"children":2026},{"style":2025},"--shiki-default:#C6D0F5;--shiki-dark:#FFAB70",[2027],{"type":40,"value":2028}," statusCode",{"type":31,"tag":171,"props":2030,"children":2031},{"style":276},[2032],{"type":40,"value":279},{"type":31,"tag":171,"props":2034,"children":2035},{"style":372},[2036],{"type":40,"value":2037}," number",{"type":31,"tag":171,"props":2039,"children":2040},{"style":236},[2041],{"type":40,"value":2042}," };\n",{"type":31,"tag":171,"props":2044,"children":2045},{"class":173,"line":552},[2046,2051,2055,2060,2064,2069],{"type":31,"tag":171,"props":2047,"children":2048},{"style":449},[2049],{"type":40,"value":2050},"      err",{"type":31,"tag":171,"props":2052,"children":2053},{"style":443},[2054],{"type":40,"value":446},{"type":31,"tag":171,"props":2056,"children":2057},{"style":449},[2058],{"type":40,"value":2059},"statusCode ",{"type":31,"tag":171,"props":2061,"children":2062},{"style":276},[2063],{"type":40,"value":1851},{"type":31,"tag":171,"props":2065,"children":2066},{"style":671},[2067],{"type":40,"value":2068}," 429",{"type":31,"tag":171,"props":2070,"children":2071},{"style":236},[2072],{"type":40,"value":471},{"type":31,"tag":171,"props":2074,"children":2075},{"class":173,"line":560},[2076,2081,2085],{"type":31,"tag":171,"props":2077,"children":2078},{"style":219},[2079],{"type":40,"value":2080},"      throw",{"type":31,"tag":171,"props":2082,"children":2083},{"style":449},[2084],{"type":40,"value":1979},{"type":31,"tag":171,"props":2086,"children":2087},{"style":236},[2088],{"type":40,"value":471},{"type":31,"tag":171,"props":2090,"children":2091},{"class":173,"line":600},[2092],{"type":31,"tag":171,"props":2093,"children":2094},{"style":236},[2095],{"type":40,"value":2096},"    }\n",{"type":31,"tag":171,"props":2098,"children":2099},{"class":173,"line":658},[2100,2104,2108],{"type":31,"tag":171,"props":2101,"children":2102},{"style":236},[2103],{"type":40,"value":1261},{"type":31,"tag":171,"props":2105,"children":2106},{"style":449},[2107],{"type":40,"value":380},{"type":31,"tag":171,"props":2109,"children":2110},{"style":236},[2111],{"type":40,"value":471},{"type":31,"tag":171,"props":2113,"children":2114},{"class":173,"line":690},[2115],{"type":31,"tag":171,"props":2116,"children":2117},{"emptyLinePlaceholder":13},[2118],{"type":40,"value":190},{"type":31,"tag":171,"props":2120,"children":2121},{"class":173,"line":735},[2122,2127,2131,2135,2139,2143,2148,2152],{"type":31,"tag":171,"props":2123,"children":2124},{"style":219},[2125],{"type":40,"value":2126},"  await",{"type":31,"tag":171,"props":2128,"children":2129},{"style":449},[2130],{"type":40,"value":1412},{"type":31,"tag":171,"props":2132,"children":2133},{"style":443},[2134],{"type":40,"value":446},{"type":31,"tag":171,"props":2136,"children":2137},{"style":203},[2138],{"type":40,"value":807},{"type":31,"tag":171,"props":2140,"children":2141},{"style":449},[2142],{"type":40,"value":360},{"type":31,"tag":171,"props":2144,"children":2145},{"style":518},[2146],{"type":40,"value":2147},"'session-abc'",{"type":31,"tag":171,"props":2149,"children":2150},{"style":449},[2151],{"type":40,"value":380},{"type":31,"tag":171,"props":2153,"children":2154},{"style":236},[2155],{"type":40,"value":471},{"type":31,"tag":171,"props":2157,"children":2158},{"class":173,"line":752},[2159],{"type":31,"tag":171,"props":2160,"children":2161},{"emptyLinePlaceholder":13},[2162],{"type":40,"value":190},{"type":31,"tag":171,"props":2164,"children":2165},{"class":173,"line":761},[2166,2170,2175,2179,2184,2188,2193,2197],{"type":31,"tag":171,"props":2167,"children":2168},{"style":203},[2169],{"type":40,"value":1537},{"type":31,"tag":171,"props":2171,"children":2172},{"style":449},[2173],{"type":40,"value":2174},"(callCount)",{"type":31,"tag":171,"props":2176,"children":2177},{"style":443},[2178],{"type":40,"value":446},{"type":31,"tag":171,"props":2180,"children":2181},{"style":203},[2182],{"type":40,"value":2183},"toBe",{"type":31,"tag":171,"props":2185,"children":2186},{"style":449},[2187],{"type":40,"value":360},{"type":31,"tag":171,"props":2189,"children":2190},{"style":671},[2191],{"type":40,"value":2192},"2",{"type":31,"tag":171,"props":2194,"children":2195},{"style":449},[2196],{"type":40,"value":380},{"type":31,"tag":171,"props":2198,"children":2199},{"style":236},[2200],{"type":40,"value":471},{"type":31,"tag":171,"props":2202,"children":2203},{"class":173,"line":1616},[2204,2208,2212,2216,2220,2224,2228,2232,2236,2240],{"type":31,"tag":171,"props":2205,"children":2206},{"style":203},[2207],{"type":40,"value":1537},{"type":31,"tag":171,"props":2209,"children":2210},{"style":449},[2211],{"type":40,"value":1290},{"type":31,"tag":171,"props":2213,"children":2214},{"style":443},[2215],{"type":40,"value":446},{"type":31,"tag":171,"props":2217,"children":2218},{"style":449},[2219],{"type":40,"value":1299},{"type":31,"tag":171,"props":2221,"children":2222},{"style":443},[2223],{"type":40,"value":446},{"type":31,"tag":171,"props":2225,"children":2226},{"style":203},[2227],{"type":40,"value":1596},{"type":31,"tag":171,"props":2229,"children":2230},{"style":449},[2231],{"type":40,"value":360},{"type":31,"tag":171,"props":2233,"children":2234},{"style":671},[2235],{"type":40,"value":2192},{"type":31,"tag":171,"props":2237,"children":2238},{"style":449},[2239],{"type":40,"value":380},{"type":31,"tag":171,"props":2241,"children":2242},{"style":236},[2243],{"type":40,"value":471},{"type":31,"tag":171,"props":2245,"children":2247},{"class":173,"line":2246},22,[2248,2252,2256],{"type":31,"tag":171,"props":2249,"children":2250},{"style":236},[2251],{"type":40,"value":536},{"type":31,"tag":171,"props":2253,"children":2254},{"style":449},[2255],{"type":40,"value":380},{"type":31,"tag":171,"props":2257,"children":2258},{"style":236},[2259],{"type":40,"value":471},{"type":31,"tag":32,"props":2261,"children":2262},{},[2263],{"type":40,"value":2264},"C'est le test qui aurait évité le crash. 20 lignes. Une heure à écrire la première fois. Une protection durable contre ce mode d'échec.",{"type":31,"tag":874,"props":2266,"children":2268},{"id":2267},"test-3-le-test-de-timeout",[2269],{"type":40,"value":2270},"Test 3 : le test de timeout",{"type":31,"tag":32,"props":2272,"children":2273},{},[2274],{"type":40,"value":2275},"Simulez une réponse Brevo qui ne vient jamais (le mock attend indefiniment). Vérifiez que la méthode abandonne au bout de N secondes au lieu de bloquer l'event loop.",{"type":31,"tag":161,"props":2277,"children":2279},{"className":163,"code":2278,"language":165,"meta":8,"style":8},"it('aborts and throws after 5 seconds if Brevo does not respond', async () => {\n  vi.useFakeTimers();\n\n  vi.mocked(sessionRepository.findById).mockResolvedValue({\n    id: 'session-timeout',\n    coacheeEmail: 'coachee@example.com',\n    scheduledAt: new Date(),\n  });\n\n  // Brevo ne répond jamais\n  vi.mocked(brevoClient.sendTransactionalEmail).mockImplementation(\n    () => new Promise\u003Cvoid>(() => { /* jamais résolu */ }),\n  );\n\n  const promise = service.sendSessionConfirmation('session-timeout');\n\n  // avancer le temps de 5 secondes\n  await vi.advanceTimersByTimeAsync(5_000);\n\n  await expect(promise).rejects.toThrow('Brevo timeout');\n\n  vi.useRealTimers();\n});\n",[2280],{"type":31,"tag":88,"props":2281,"children":2282},{"__ignoreMap":8},[2283,2319,2343,2350,2393,2413,2432,2459,2474,2481,2489,2528,2594,2605,2612,2657,2664,2672,2710,2717,2769,2776,2800],{"type":31,"tag":171,"props":2284,"children":2285},{"class":173,"line":174},[2286,2290,2294,2299,2303,2307,2311,2315],{"type":31,"tag":171,"props":2287,"children":2288},{"style":203},[2289],{"type":40,"value":929},{"type":31,"tag":171,"props":2291,"children":2292},{"style":449},[2293],{"type":40,"value":360},{"type":31,"tag":171,"props":2295,"children":2296},{"style":518},[2297],{"type":40,"value":2298},"'aborts and throws after 5 seconds if Brevo does not respond'",{"type":31,"tag":171,"props":2300,"children":2301},{"style":236},[2302],{"type":40,"value":943},{"type":31,"tag":171,"props":2304,"children":2305},{"style":219},[2306],{"type":40,"value":948},{"type":31,"tag":171,"props":2308,"children":2309},{"style":236},[2310],{"type":40,"value":953},{"type":31,"tag":171,"props":2312,"children":2313},{"style":276},[2314],{"type":40,"value":958},{"type":31,"tag":171,"props":2316,"children":2317},{"style":236},[2318],{"type":40,"value":239},{"type":31,"tag":171,"props":2320,"children":2321},{"class":173,"line":184},[2322,2326,2330,2335,2339],{"type":31,"tag":171,"props":2323,"children":2324},{"style":449},[2325],{"type":40,"value":1099},{"type":31,"tag":171,"props":2327,"children":2328},{"style":443},[2329],{"type":40,"value":446},{"type":31,"tag":171,"props":2331,"children":2332},{"style":203},[2333],{"type":40,"value":2334},"useFakeTimers",{"type":31,"tag":171,"props":2336,"children":2337},{"style":449},[2338],{"type":40,"value":1807},{"type":31,"tag":171,"props":2340,"children":2341},{"style":236},[2342],{"type":40,"value":471},{"type":31,"tag":171,"props":2344,"children":2345},{"class":173,"line":193},[2346],{"type":31,"tag":171,"props":2347,"children":2348},{"emptyLinePlaceholder":13},[2349],{"type":40,"value":190},{"type":31,"tag":171,"props":2351,"children":2352},{"class":173,"line":215},[2353,2357,2361,2365,2369,2373,2377,2381,2385,2389],{"type":31,"tag":171,"props":2354,"children":2355},{"style":449},[2356],{"type":40,"value":1099},{"type":31,"tag":171,"props":2358,"children":2359},{"style":443},[2360],{"type":40,"value":446},{"type":31,"tag":171,"props":2362,"children":2363},{"style":203},[2364],{"type":40,"value":1108},{"type":31,"tag":171,"props":2366,"children":2367},{"style":449},[2368],{"type":40,"value":1113},{"type":31,"tag":171,"props":2370,"children":2371},{"style":443},[2372],{"type":40,"value":446},{"type":31,"tag":171,"props":2374,"children":2375},{"style":449},[2376],{"type":40,"value":1122},{"type":31,"tag":171,"props":2378,"children":2379},{"style":443},[2380],{"type":40,"value":446},{"type":31,"tag":171,"props":2382,"children":2383},{"style":203},[2384],{"type":40,"value":1308},{"type":31,"tag":171,"props":2386,"children":2387},{"style":449},[2388],{"type":40,"value":360},{"type":31,"tag":171,"props":2390,"children":2391},{"style":236},[2392],{"type":40,"value":597},{"type":31,"tag":171,"props":2394,"children":2395},{"class":173,"line":242},[2396,2400,2404,2409],{"type":31,"tag":171,"props":2397,"children":2398},{"style":449},[2399],{"type":40,"value":1173},{"type":31,"tag":171,"props":2401,"children":2402},{"style":443},[2403],{"type":40,"value":279},{"type":31,"tag":171,"props":2405,"children":2406},{"style":518},[2407],{"type":40,"value":2408}," 'session-timeout'",{"type":31,"tag":171,"props":2410,"children":2411},{"style":236},[2412],{"type":40,"value":289},{"type":31,"tag":171,"props":2414,"children":2415},{"class":173,"line":256},[2416,2420,2424,2428],{"type":31,"tag":171,"props":2417,"children":2418},{"style":449},[2419],{"type":40,"value":1185},{"type":31,"tag":171,"props":2421,"children":2422},{"style":443},[2423],{"type":40,"value":279},{"type":31,"tag":171,"props":2425,"children":2426},{"style":518},[2427],{"type":40,"value":1779},{"type":31,"tag":171,"props":2429,"children":2430},{"style":236},[2431],{"type":40,"value":289},{"type":31,"tag":171,"props":2433,"children":2434},{"class":173,"line":292},[2435,2439,2443,2447,2451,2455],{"type":31,"tag":171,"props":2436,"children":2437},{"style":449},[2438],{"type":40,"value":1223},{"type":31,"tag":171,"props":2440,"children":2441},{"style":443},[2442],{"type":40,"value":279},{"type":31,"tag":171,"props":2444,"children":2445},{"style":503},[2446],{"type":40,"value":506},{"type":31,"tag":171,"props":2448,"children":2449},{"style":203},[2450],{"type":40,"value":1236},{"type":31,"tag":171,"props":2452,"children":2453},{"style":449},[2454],{"type":40,"value":1807},{"type":31,"tag":171,"props":2456,"children":2457},{"style":236},[2458],{"type":40,"value":289},{"type":31,"tag":171,"props":2460,"children":2461},{"class":173,"line":322},[2462,2466,2470],{"type":31,"tag":171,"props":2463,"children":2464},{"style":236},[2465],{"type":40,"value":1261},{"type":31,"tag":171,"props":2467,"children":2468},{"style":449},[2469],{"type":40,"value":380},{"type":31,"tag":171,"props":2471,"children":2472},{"style":236},[2473],{"type":40,"value":471},{"type":31,"tag":171,"props":2475,"children":2476},{"class":173,"line":336},[2477],{"type":31,"tag":171,"props":2478,"children":2479},{"emptyLinePlaceholder":13},[2480],{"type":40,"value":190},{"type":31,"tag":171,"props":2482,"children":2483},{"class":173,"line":344},[2484],{"type":31,"tag":171,"props":2485,"children":2486},{"style":178},[2487],{"type":40,"value":2488},"  // Brevo ne répond jamais\n",{"type":31,"tag":171,"props":2490,"children":2491},{"class":173,"line":412},[2492,2496,2500,2504,2508,2512,2516,2520,2524],{"type":31,"tag":171,"props":2493,"children":2494},{"style":449},[2495],{"type":40,"value":1099},{"type":31,"tag":171,"props":2497,"children":2498},{"style":443},[2499],{"type":40,"value":446},{"type":31,"tag":171,"props":2501,"children":2502},{"style":203},[2503],{"type":40,"value":1108},{"type":31,"tag":171,"props":2505,"children":2506},{"style":449},[2507],{"type":40,"value":1290},{"type":31,"tag":171,"props":2509,"children":2510},{"style":443},[2511],{"type":40,"value":446},{"type":31,"tag":171,"props":2513,"children":2514},{"style":449},[2515],{"type":40,"value":1299},{"type":31,"tag":171,"props":2517,"children":2518},{"style":443},[2519],{"type":40,"value":446},{"type":31,"tag":171,"props":2521,"children":2522},{"style":203},[2523],{"type":40,"value":1131},{"type":31,"tag":171,"props":2525,"children":2526},{"style":449},[2527],{"type":40,"value":253},{"type":31,"tag":171,"props":2529,"children":2530},{"class":173,"line":474},[2531,2536,2540,2544,2548,2552,2556,2560,2564,2568,2572,2576,2581,2586,2590],{"type":31,"tag":171,"props":2532,"children":2533},{"style":236},[2534],{"type":40,"value":2535},"    ()",{"type":31,"tag":171,"props":2537,"children":2538},{"style":276},[2539],{"type":40,"value":958},{"type":31,"tag":171,"props":2541,"children":2542},{"style":503},[2543],{"type":40,"value":506},{"type":31,"tag":171,"props":2545,"children":2546},{"style":1355},[2547],{"type":40,"value":389},{"type":31,"tag":171,"props":2549,"children":2550},{"style":392},[2551],{"type":40,"value":395},{"type":31,"tag":171,"props":2553,"children":2554},{"style":372},[2555],{"type":40,"value":400},{"type":31,"tag":171,"props":2557,"children":2558},{"style":392},[2559],{"type":40,"value":405},{"type":31,"tag":171,"props":2561,"children":2562},{"style":449},[2563],{"type":40,"value":360},{"type":31,"tag":171,"props":2565,"children":2566},{"style":236},[2567],{"type":40,"value":1807},{"type":31,"tag":171,"props":2569,"children":2570},{"style":276},[2571],{"type":40,"value":958},{"type":31,"tag":171,"props":2573,"children":2574},{"style":236},[2575],{"type":40,"value":705},{"type":31,"tag":171,"props":2577,"children":2578},{"style":178},[2579],{"type":40,"value":2580}," /* jamais résolu */",{"type":31,"tag":171,"props":2582,"children":2583},{"style":236},[2584],{"type":40,"value":2585}," }",{"type":31,"tag":171,"props":2587,"children":2588},{"style":449},[2589],{"type":40,"value":380},{"type":31,"tag":171,"props":2591,"children":2592},{"style":236},[2593],{"type":40,"value":289},{"type":31,"tag":171,"props":2595,"children":2596},{"class":173,"line":552},[2597,2601],{"type":31,"tag":171,"props":2598,"children":2599},{"style":449},[2600],{"type":40,"value":328},{"type":31,"tag":171,"props":2602,"children":2603},{"style":236},[2604],{"type":40,"value":471},{"type":31,"tag":171,"props":2606,"children":2607},{"class":173,"line":560},[2608],{"type":31,"tag":171,"props":2609,"children":2610},{"emptyLinePlaceholder":13},[2611],{"type":40,"value":190},{"type":31,"tag":171,"props":2613,"children":2614},{"class":173,"line":600},[2615,2619,2624,2628,2632,2636,2640,2644,2649,2653],{"type":31,"tag":171,"props":2616,"children":2617},{"style":219},[2618],{"type":40,"value":970},{"type":31,"tag":171,"props":2620,"children":2621},{"style":421},[2622],{"type":40,"value":2623}," promise",{"type":31,"tag":171,"props":2625,"children":2626},{"style":276},[2627],{"type":40,"value":429},{"type":31,"tag":171,"props":2629,"children":2630},{"style":449},[2631],{"type":40,"value":1412},{"type":31,"tag":171,"props":2633,"children":2634},{"style":443},[2635],{"type":40,"value":446},{"type":31,"tag":171,"props":2637,"children":2638},{"style":203},[2639],{"type":40,"value":807},{"type":31,"tag":171,"props":2641,"children":2642},{"style":449},[2643],{"type":40,"value":360},{"type":31,"tag":171,"props":2645,"children":2646},{"style":518},[2647],{"type":40,"value":2648},"'session-timeout'",{"type":31,"tag":171,"props":2650,"children":2651},{"style":449},[2652],{"type":40,"value":380},{"type":31,"tag":171,"props":2654,"children":2655},{"style":236},[2656],{"type":40,"value":471},{"type":31,"tag":171,"props":2658,"children":2659},{"class":173,"line":658},[2660],{"type":31,"tag":171,"props":2661,"children":2662},{"emptyLinePlaceholder":13},[2663],{"type":40,"value":190},{"type":31,"tag":171,"props":2665,"children":2666},{"class":173,"line":690},[2667],{"type":31,"tag":171,"props":2668,"children":2669},{"style":178},[2670],{"type":40,"value":2671},"  // avancer le temps de 5 secondes\n",{"type":31,"tag":171,"props":2673,"children":2674},{"class":173,"line":735},[2675,2679,2684,2688,2693,2697,2702,2706],{"type":31,"tag":171,"props":2676,"children":2677},{"style":219},[2678],{"type":40,"value":2126},{"type":31,"tag":171,"props":2680,"children":2681},{"style":449},[2682],{"type":40,"value":2683}," vi",{"type":31,"tag":171,"props":2685,"children":2686},{"style":443},[2687],{"type":40,"value":446},{"type":31,"tag":171,"props":2689,"children":2690},{"style":203},[2691],{"type":40,"value":2692},"advanceTimersByTimeAsync",{"type":31,"tag":171,"props":2694,"children":2695},{"style":449},[2696],{"type":40,"value":360},{"type":31,"tag":171,"props":2698,"children":2699},{"style":671},[2700],{"type":40,"value":2701},"5_000",{"type":31,"tag":171,"props":2703,"children":2704},{"style":449},[2705],{"type":40,"value":380},{"type":31,"tag":171,"props":2707,"children":2708},{"style":236},[2709],{"type":40,"value":471},{"type":31,"tag":171,"props":2711,"children":2712},{"class":173,"line":752},[2713],{"type":31,"tag":171,"props":2714,"children":2715},{"emptyLinePlaceholder":13},[2716],{"type":40,"value":190},{"type":31,"tag":171,"props":2718,"children":2719},{"class":173,"line":761},[2720,2724,2729,2734,2738,2743,2747,2752,2756,2761,2765],{"type":31,"tag":171,"props":2721,"children":2722},{"style":219},[2723],{"type":40,"value":2126},{"type":31,"tag":171,"props":2725,"children":2726},{"style":203},[2727],{"type":40,"value":2728}," expect",{"type":31,"tag":171,"props":2730,"children":2731},{"style":449},[2732],{"type":40,"value":2733},"(promise)",{"type":31,"tag":171,"props":2735,"children":2736},{"style":443},[2737],{"type":40,"value":446},{"type":31,"tag":171,"props":2739,"children":2740},{"style":449},[2741],{"type":40,"value":2742},"rejects",{"type":31,"tag":171,"props":2744,"children":2745},{"style":443},[2746],{"type":40,"value":446},{"type":31,"tag":171,"props":2748,"children":2749},{"style":203},[2750],{"type":40,"value":2751},"toThrow",{"type":31,"tag":171,"props":2753,"children":2754},{"style":449},[2755],{"type":40,"value":360},{"type":31,"tag":171,"props":2757,"children":2758},{"style":518},[2759],{"type":40,"value":2760},"'Brevo timeout'",{"type":31,"tag":171,"props":2762,"children":2763},{"style":449},[2764],{"type":40,"value":380},{"type":31,"tag":171,"props":2766,"children":2767},{"style":236},[2768],{"type":40,"value":471},{"type":31,"tag":171,"props":2770,"children":2771},{"class":173,"line":1616},[2772],{"type":31,"tag":171,"props":2773,"children":2774},{"emptyLinePlaceholder":13},[2775],{"type":40,"value":190},{"type":31,"tag":171,"props":2777,"children":2778},{"class":173,"line":2246},[2779,2783,2787,2792,2796],{"type":31,"tag":171,"props":2780,"children":2781},{"style":449},[2782],{"type":40,"value":1099},{"type":31,"tag":171,"props":2784,"children":2785},{"style":443},[2786],{"type":40,"value":446},{"type":31,"tag":171,"props":2788,"children":2789},{"style":203},[2790],{"type":40,"value":2791},"useRealTimers",{"type":31,"tag":171,"props":2793,"children":2794},{"style":449},[2795],{"type":40,"value":1807},{"type":31,"tag":171,"props":2797,"children":2798},{"style":236},[2799],{"type":40,"value":471},{"type":31,"tag":171,"props":2801,"children":2803},{"class":173,"line":2802},23,[2804,2808,2812],{"type":31,"tag":171,"props":2805,"children":2806},{"style":236},[2807],{"type":40,"value":536},{"type":31,"tag":171,"props":2809,"children":2810},{"style":449},[2811],{"type":40,"value":380},{"type":31,"tag":171,"props":2813,"children":2814},{"style":236},[2815],{"type":40,"value":471},{"type":31,"tag":32,"props":2817,"children":2818},{},[2819],{"type":40,"value":2820},"Sans ce test, vous découvrirez le problème le jour où Brevo a une latence anormale et que votre job de notifications se bouche complètement.",{"type":31,"tag":874,"props":2822,"children":2824},{"id":2823},"test-4-le-test-de-partial-failure",[2825],{"type":40,"value":2826},"Test 4 : le test de partial failure",{"type":31,"tag":32,"props":2828,"children":2829},{},[2830],{"type":40,"value":2831},"Pour les méthodes qui enchainent deux actions (ex : persistance DB + envoi email), simulez l'échec de la deuxième et vérifiez que la première est compensée ou que la méthode est idempotente.",{"type":31,"tag":161,"props":2833,"children":2835},{"className":163,"code":2834,"language":165,"meta":8,"style":8},"it('does not mark session as notified in DB when Brevo send fails', async () => {\n  const session = {\n    id: 'session-partial',\n    coacheeEmail: 'coachee@example.com',\n    scheduledAt: new Date(),\n    notificationSentAt: null as Date | null,\n  };\n\n  vi.mocked(sessionRepository.findById).mockResolvedValue(session);\n  vi.mocked(brevoClient.sendTransactionalEmail).mockRejectedValue(\n    new Error('Brevo SMTP down'),\n  );\n\n  await expect(service.sendSessionConfirmation('session-partial')).rejects.toThrow();\n\n  // la DB ne doit pas avoir été mise à jour\n  expect(sessionRepository.save).not.toHaveBeenCalled();\n  expect(session.notificationSentAt).toBeNull();\n});\n",[2836],{"type":31,"tag":88,"props":2837,"children":2838},{"__ignoreMap":8},[2839,2875,2894,2914,2933,2960,3000,3008,3015,3059,3099,3128,3139,3146,3207,3214,3222,3268,3306],{"type":31,"tag":171,"props":2840,"children":2841},{"class":173,"line":174},[2842,2846,2850,2855,2859,2863,2867,2871],{"type":31,"tag":171,"props":2843,"children":2844},{"style":203},[2845],{"type":40,"value":929},{"type":31,"tag":171,"props":2847,"children":2848},{"style":449},[2849],{"type":40,"value":360},{"type":31,"tag":171,"props":2851,"children":2852},{"style":518},[2853],{"type":40,"value":2854},"'does not mark session as notified in DB when Brevo send fails'",{"type":31,"tag":171,"props":2856,"children":2857},{"style":236},[2858],{"type":40,"value":943},{"type":31,"tag":171,"props":2860,"children":2861},{"style":219},[2862],{"type":40,"value":948},{"type":31,"tag":171,"props":2864,"children":2865},{"style":236},[2866],{"type":40,"value":953},{"type":31,"tag":171,"props":2868,"children":2869},{"style":276},[2870],{"type":40,"value":958},{"type":31,"tag":171,"props":2872,"children":2873},{"style":236},[2874],{"type":40,"value":239},{"type":31,"tag":171,"props":2876,"children":2877},{"class":173,"line":184},[2878,2882,2886,2890],{"type":31,"tag":171,"props":2879,"children":2880},{"style":219},[2881],{"type":40,"value":970},{"type":31,"tag":171,"props":2883,"children":2884},{"style":421},[2885],{"type":40,"value":424},{"type":31,"tag":171,"props":2887,"children":2888},{"style":276},[2889],{"type":40,"value":429},{"type":31,"tag":171,"props":2891,"children":2892},{"style":236},[2893],{"type":40,"value":239},{"type":31,"tag":171,"props":2895,"children":2896},{"class":173,"line":193},[2897,2901,2905,2910],{"type":31,"tag":171,"props":2898,"children":2899},{"style":449},[2900],{"type":40,"value":1173},{"type":31,"tag":171,"props":2902,"children":2903},{"style":443},[2904],{"type":40,"value":279},{"type":31,"tag":171,"props":2906,"children":2907},{"style":518},[2908],{"type":40,"value":2909}," 'session-partial'",{"type":31,"tag":171,"props":2911,"children":2912},{"style":236},[2913],{"type":40,"value":289},{"type":31,"tag":171,"props":2915,"children":2916},{"class":173,"line":215},[2917,2921,2925,2929],{"type":31,"tag":171,"props":2918,"children":2919},{"style":449},[2920],{"type":40,"value":1185},{"type":31,"tag":171,"props":2922,"children":2923},{"style":443},[2924],{"type":40,"value":279},{"type":31,"tag":171,"props":2926,"children":2927},{"style":518},[2928],{"type":40,"value":1779},{"type":31,"tag":171,"props":2930,"children":2931},{"style":236},[2932],{"type":40,"value":289},{"type":31,"tag":171,"props":2934,"children":2935},{"class":173,"line":242},[2936,2940,2944,2948,2952,2956],{"type":31,"tag":171,"props":2937,"children":2938},{"style":449},[2939],{"type":40,"value":1223},{"type":31,"tag":171,"props":2941,"children":2942},{"style":443},[2943],{"type":40,"value":279},{"type":31,"tag":171,"props":2945,"children":2946},{"style":503},[2947],{"type":40,"value":506},{"type":31,"tag":171,"props":2949,"children":2950},{"style":203},[2951],{"type":40,"value":1236},{"type":31,"tag":171,"props":2953,"children":2954},{"style":449},[2955],{"type":40,"value":1807},{"type":31,"tag":171,"props":2957,"children":2958},{"style":236},[2959],{"type":40,"value":289},{"type":31,"tag":171,"props":2961,"children":2962},{"class":173,"line":256},[2963,2968,2972,2977,2982,2986,2991,2996],{"type":31,"tag":171,"props":2964,"children":2965},{"style":449},[2966],{"type":40,"value":2967},"    notificationSentAt",{"type":31,"tag":171,"props":2969,"children":2970},{"style":443},[2971],{"type":40,"value":279},{"type":31,"tag":171,"props":2973,"children":2974},{"style":372},[2975],{"type":40,"value":2976}," null",{"type":31,"tag":171,"props":2978,"children":2979},{"style":219},[2980],{"type":40,"value":2981}," as",{"type":31,"tag":171,"props":2983,"children":2984},{"style":230},[2985],{"type":40,"value":1236},{"type":31,"tag":171,"props":2987,"children":2988},{"style":276},[2989],{"type":40,"value":2990}," |",{"type":31,"tag":171,"props":2992,"children":2994},{"style":2993},"--shiki-default:#CA9EE6;--shiki-default-font-style:italic;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit",[2995],{"type":40,"value":2976},{"type":31,"tag":171,"props":2997,"children":2998},{"style":236},[2999],{"type":40,"value":289},{"type":31,"tag":171,"props":3001,"children":3002},{"class":173,"line":292},[3003],{"type":31,"tag":171,"props":3004,"children":3005},{"style":236},[3006],{"type":40,"value":3007},"  };\n",{"type":31,"tag":171,"props":3009,"children":3010},{"class":173,"line":322},[3011],{"type":31,"tag":171,"props":3012,"children":3013},{"emptyLinePlaceholder":13},[3014],{"type":40,"value":190},{"type":31,"tag":171,"props":3016,"children":3017},{"class":173,"line":336},[3018,3022,3026,3030,3034,3038,3042,3046,3050,3055],{"type":31,"tag":171,"props":3019,"children":3020},{"style":449},[3021],{"type":40,"value":1099},{"type":31,"tag":171,"props":3023,"children":3024},{"style":443},[3025],{"type":40,"value":446},{"type":31,"tag":171,"props":3027,"children":3028},{"style":203},[3029],{"type":40,"value":1108},{"type":31,"tag":171,"props":3031,"children":3032},{"style":449},[3033],{"type":40,"value":1113},{"type":31,"tag":171,"props":3035,"children":3036},{"style":443},[3037],{"type":40,"value":446},{"type":31,"tag":171,"props":3039,"children":3040},{"style":449},[3041],{"type":40,"value":1122},{"type":31,"tag":171,"props":3043,"children":3044},{"style":443},[3045],{"type":40,"value":446},{"type":31,"tag":171,"props":3047,"children":3048},{"style":203},[3049],{"type":40,"value":1308},{"type":31,"tag":171,"props":3051,"children":3052},{"style":449},[3053],{"type":40,"value":3054},"(session)",{"type":31,"tag":171,"props":3056,"children":3057},{"style":236},[3058],{"type":40,"value":471},{"type":31,"tag":171,"props":3060,"children":3061},{"class":173,"line":344},[3062,3066,3070,3074,3078,3082,3086,3090,3095],{"type":31,"tag":171,"props":3063,"children":3064},{"style":449},[3065],{"type":40,"value":1099},{"type":31,"tag":171,"props":3067,"children":3068},{"style":443},[3069],{"type":40,"value":446},{"type":31,"tag":171,"props":3071,"children":3072},{"style":203},[3073],{"type":40,"value":1108},{"type":31,"tag":171,"props":3075,"children":3076},{"style":449},[3077],{"type":40,"value":1290},{"type":31,"tag":171,"props":3079,"children":3080},{"style":443},[3081],{"type":40,"value":446},{"type":31,"tag":171,"props":3083,"children":3084},{"style":449},[3085],{"type":40,"value":1299},{"type":31,"tag":171,"props":3087,"children":3088},{"style":443},[3089],{"type":40,"value":446},{"type":31,"tag":171,"props":3091,"children":3092},{"style":203},[3093],{"type":40,"value":3094},"mockRejectedValue",{"type":31,"tag":171,"props":3096,"children":3097},{"style":449},[3098],{"type":40,"value":253},{"type":31,"tag":171,"props":3100,"children":3101},{"class":173,"line":412},[3102,3107,3111,3115,3120,3124],{"type":31,"tag":171,"props":3103,"children":3104},{"style":503},[3105],{"type":40,"value":3106},"    new",{"type":31,"tag":171,"props":3108,"children":3109},{"style":203},[3110],{"type":40,"value":511},{"type":31,"tag":171,"props":3112,"children":3113},{"style":449},[3114],{"type":40,"value":360},{"type":31,"tag":171,"props":3116,"children":3117},{"style":518},[3118],{"type":40,"value":3119},"'Brevo SMTP down'",{"type":31,"tag":171,"props":3121,"children":3122},{"style":449},[3123],{"type":40,"value":380},{"type":31,"tag":171,"props":3125,"children":3126},{"style":236},[3127],{"type":40,"value":289},{"type":31,"tag":171,"props":3129,"children":3130},{"class":173,"line":474},[3131,3135],{"type":31,"tag":171,"props":3132,"children":3133},{"style":449},[3134],{"type":40,"value":328},{"type":31,"tag":171,"props":3136,"children":3137},{"style":236},[3138],{"type":40,"value":471},{"type":31,"tag":171,"props":3140,"children":3141},{"class":173,"line":552},[3142],{"type":31,"tag":171,"props":3143,"children":3144},{"emptyLinePlaceholder":13},[3145],{"type":40,"value":190},{"type":31,"tag":171,"props":3147,"children":3148},{"class":173,"line":560},[3149,3153,3157,3162,3166,3170,3174,3179,3183,3187,3191,3195,3199,3203],{"type":31,"tag":171,"props":3150,"children":3151},{"style":219},[3152],{"type":40,"value":2126},{"type":31,"tag":171,"props":3154,"children":3155},{"style":203},[3156],{"type":40,"value":2728},{"type":31,"tag":171,"props":3158,"children":3159},{"style":449},[3160],{"type":40,"value":3161},"(service",{"type":31,"tag":171,"props":3163,"children":3164},{"style":443},[3165],{"type":40,"value":446},{"type":31,"tag":171,"props":3167,"children":3168},{"style":203},[3169],{"type":40,"value":807},{"type":31,"tag":171,"props":3171,"children":3172},{"style":449},[3173],{"type":40,"value":360},{"type":31,"tag":171,"props":3175,"children":3176},{"style":518},[3177],{"type":40,"value":3178},"'session-partial'",{"type":31,"tag":171,"props":3180,"children":3181},{"style":449},[3182],{"type":40,"value":1266},{"type":31,"tag":171,"props":3184,"children":3185},{"style":443},[3186],{"type":40,"value":446},{"type":31,"tag":171,"props":3188,"children":3189},{"style":449},[3190],{"type":40,"value":2742},{"type":31,"tag":171,"props":3192,"children":3193},{"style":443},[3194],{"type":40,"value":446},{"type":31,"tag":171,"props":3196,"children":3197},{"style":203},[3198],{"type":40,"value":2751},{"type":31,"tag":171,"props":3200,"children":3201},{"style":449},[3202],{"type":40,"value":1807},{"type":31,"tag":171,"props":3204,"children":3205},{"style":236},[3206],{"type":40,"value":471},{"type":31,"tag":171,"props":3208,"children":3209},{"class":173,"line":600},[3210],{"type":31,"tag":171,"props":3211,"children":3212},{"emptyLinePlaceholder":13},[3213],{"type":40,"value":190},{"type":31,"tag":171,"props":3215,"children":3216},{"class":173,"line":658},[3217],{"type":31,"tag":171,"props":3218,"children":3219},{"style":178},[3220],{"type":40,"value":3221},"  // la DB ne doit pas avoir été mise à jour\n",{"type":31,"tag":171,"props":3223,"children":3224},{"class":173,"line":690},[3225,3229,3233,3237,3242,3246,3251,3255,3260,3264],{"type":31,"tag":171,"props":3226,"children":3227},{"style":203},[3228],{"type":40,"value":1537},{"type":31,"tag":171,"props":3230,"children":3231},{"style":449},[3232],{"type":40,"value":1113},{"type":31,"tag":171,"props":3234,"children":3235},{"style":443},[3236],{"type":40,"value":446},{"type":31,"tag":171,"props":3238,"children":3239},{"style":449},[3240],{"type":40,"value":3241},"save)",{"type":31,"tag":171,"props":3243,"children":3244},{"style":443},[3245],{"type":40,"value":446},{"type":31,"tag":171,"props":3247,"children":3248},{"style":449},[3249],{"type":40,"value":3250},"not",{"type":31,"tag":171,"props":3252,"children":3253},{"style":443},[3254],{"type":40,"value":446},{"type":31,"tag":171,"props":3256,"children":3257},{"style":203},[3258],{"type":40,"value":3259},"toHaveBeenCalled",{"type":31,"tag":171,"props":3261,"children":3262},{"style":449},[3263],{"type":40,"value":1807},{"type":31,"tag":171,"props":3265,"children":3266},{"style":236},[3267],{"type":40,"value":471},{"type":31,"tag":171,"props":3269,"children":3270},{"class":173,"line":735},[3271,3275,3280,3284,3289,3293,3298,3302],{"type":31,"tag":171,"props":3272,"children":3273},{"style":203},[3274],{"type":40,"value":1537},{"type":31,"tag":171,"props":3276,"children":3277},{"style":449},[3278],{"type":40,"value":3279},"(session",{"type":31,"tag":171,"props":3281,"children":3282},{"style":443},[3283],{"type":40,"value":446},{"type":31,"tag":171,"props":3285,"children":3286},{"style":449},[3287],{"type":40,"value":3288},"notificationSentAt)",{"type":31,"tag":171,"props":3290,"children":3291},{"style":443},[3292],{"type":40,"value":446},{"type":31,"tag":171,"props":3294,"children":3295},{"style":203},[3296],{"type":40,"value":3297},"toBeNull",{"type":31,"tag":171,"props":3299,"children":3300},{"style":449},[3301],{"type":40,"value":1807},{"type":31,"tag":171,"props":3303,"children":3304},{"style":236},[3305],{"type":40,"value":471},{"type":31,"tag":171,"props":3307,"children":3308},{"class":173,"line":752},[3309,3313,3317],{"type":31,"tag":171,"props":3310,"children":3311},{"style":236},[3312],{"type":40,"value":536},{"type":31,"tag":171,"props":3314,"children":3315},{"style":449},[3316],{"type":40,"value":380},{"type":31,"tag":171,"props":3318,"children":3319},{"style":236},[3320],{"type":40,"value":471},{"type":31,"tag":32,"props":3322,"children":3323},{},[3324],{"type":40,"value":3325},"Ce test révèle souvent un bug d'idempotence : la méthode marque la session \"notifiée\" en DB avant d'envoyer l'email via Brevo, donc si l'envoi échoue et qu'on retry, on n'envoie pas le deuxième email. Le coachee ne reçoit jamais sa confirmation, mais la DB indique que tout va bien.",{"type":31,"tag":48,"props":3327,"children":3328},{},[],{"type":31,"tag":52,"props":3330,"children":3332},{"id":3331},"le-wrapper-anti-fragile-à-demander-à-claude",[3333],{"type":40,"value":3334},"Le wrapper anti-fragile à demander à Claude",{"type":31,"tag":32,"props":3336,"children":3337},{},[3338,3340,3345],{"type":40,"value":3339},"Une fois ces 4 tests écrits, je prompte Claude différemment. Au lieu de \"implémente ",{"type":31,"tag":88,"props":3341,"children":3343},{"className":3342},[],[3344],{"type":40,"value":807},{"type":40,"value":3346},"\", je dis :",{"type":31,"tag":32,"props":3348,"children":3349},{},[3350],{"type":31,"tag":132,"props":3351,"children":3352},{},[3353,3355,3360,3362,3368],{"type":40,"value":3354},"\"Implémente ",{"type":31,"tag":88,"props":3356,"children":3358},{"className":3357},[],[3359],{"type":40,"value":807},{"type":40,"value":3361}," dans NestJS en gérant les 429 de Brevo avec un retry exponentiel (p-retry ou helper maison), un timeout sur l'appel réseau (AbortSignal ou p-timeout), et une stratégie d'idempotence basée sur un champ ",{"type":31,"tag":88,"props":3363,"children":3365},{"className":3364},[],[3366],{"type":40,"value":3367},"notificationSentAt",{"type":40,"value":3369}," en DB. Les tests Vitest fournis doivent tous passer.\"",{"type":31,"tag":32,"props":3371,"children":3372},{},[3373],{"type":40,"value":3374},"Voici ce que Claude livre alors :",{"type":31,"tag":161,"props":3376,"children":3378},{"className":163,"code":3377,"language":165,"meta":8,"style":8},"// apps/api/src/infrastructure/notification/brevo-notification.service.ts\n\nimport pRetry, { AbortError } from 'p-retry';\n\nconst BREVO_TIMEOUT_MS = 5_000;\nconst BREVO_RETRY_MAX = 5;\n\n@Injectable()\nexport class BrevoNotificationService {\n  constructor(\n    private readonly sessionRepository: SessionRepository,\n    private readonly brevoClient: BrevoClient,\n  ) {}\n\n  async sendSessionConfirmation(sessionId: string): Promise\u003Cvoid> {\n    const session = await this.sessionRepository.findById(sessionId);\n    if (session == null) throw new Error(`Session not found: ${sessionId}`);\n\n    // idempotence : ne pas renvoyer si déjà envoyé\n    if (session.notificationSentAt != null) return;\n\n    await pRetry(\n      async () => {\n        const controller = new AbortController();\n        const timer = setTimeout(() => controller.abort(), BREVO_TIMEOUT_MS);\n\n        try {\n          await this.brevoClient.sendTransactionalEmail(\n            {\n              to: [{ email: session.coacheeEmail }],\n              templateId: BREVO_TEMPLATE_IDS.SESSION_CONFIRMATION,\n              params: { sessionDate: session.scheduledAt },\n            },\n            { signal: controller.signal },\n          );\n        } catch (err: unknown) {\n          clearTimeout(timer);\n          if (controller.signal.aborted) {\n            throw new AbortError('Brevo timeout');\n          }\n          const statusCode = (err as { statusCode?: number }).statusCode;\n          if (statusCode === 429 || statusCode === 503) throw err; // retry\n          throw new AbortError((err as Error).message); // pas de retry sur les 4xx\n        }\n        clearTimeout(timer);\n      },\n      {\n        retries: BREVO_RETRY_MAX,\n        factor: 2,\n        minTimeout: 100,\n        onFailedAttempt: (error) => {\n          if (error.retriesLeft === 0) throw error;\n        },\n      },\n    );\n\n    await this.sessionRepository.markNotified(sessionId, new Date());\n  }\n}\n",[3379],{"type":31,"tag":88,"props":3380,"children":3381},{"__ignoreMap":8},[3382,3389,3396,3440,3447,3473,3498,3505,3520,3539,3550,3577,3604,3615,3622,3677,3724,3793,3800,3808,3851,3858,3873,3893,3928,3995,4003,4016,4049,4058,4111,4140,4181,4190,4225,4238,4278,4296,4332,4366,4375,4439,4501,4553,4562,4579,4588,4597,4618,4640,4662,4696,4743,4752,4760,4773,4781,4836,4844],{"type":31,"tag":171,"props":3383,"children":3384},{"class":173,"line":174},[3385],{"type":31,"tag":171,"props":3386,"children":3387},{"style":178},[3388],{"type":40,"value":181},{"type":31,"tag":171,"props":3390,"children":3391},{"class":173,"line":184},[3392],{"type":31,"tag":171,"props":3393,"children":3394},{"emptyLinePlaceholder":13},[3395],{"type":40,"value":190},{"type":31,"tag":171,"props":3397,"children":3398},{"class":173,"line":193},[3399,3404,3409,3413,3417,3422,3426,3431,3436],{"type":31,"tag":171,"props":3400,"children":3401},{"style":219},[3402],{"type":40,"value":3403},"import",{"type":31,"tag":171,"props":3405,"children":3406},{"style":449},[3407],{"type":40,"value":3408}," pRetry",{"type":31,"tag":171,"props":3410,"children":3411},{"style":236},[3412],{"type":40,"value":943},{"type":31,"tag":171,"props":3414,"children":3415},{"style":236},[3416],{"type":40,"value":705},{"type":31,"tag":171,"props":3418,"children":3419},{"style":449},[3420],{"type":40,"value":3421}," AbortError ",{"type":31,"tag":171,"props":3423,"children":3424},{"style":236},[3425],{"type":40,"value":536},{"type":31,"tag":171,"props":3427,"children":3428},{"style":219},[3429],{"type":40,"value":3430}," from",{"type":31,"tag":171,"props":3432,"children":3433},{"style":518},[3434],{"type":40,"value":3435}," 'p-retry'",{"type":31,"tag":171,"props":3437,"children":3438},{"style":236},[3439],{"type":40,"value":471},{"type":31,"tag":171,"props":3441,"children":3442},{"class":173,"line":215},[3443],{"type":31,"tag":171,"props":3444,"children":3445},{"emptyLinePlaceholder":13},[3446],{"type":40,"value":190},{"type":31,"tag":171,"props":3448,"children":3449},{"class":173,"line":242},[3450,3455,3460,3464,3469],{"type":31,"tag":171,"props":3451,"children":3452},{"style":219},[3453],{"type":40,"value":3454},"const",{"type":31,"tag":171,"props":3456,"children":3457},{"style":421},[3458],{"type":40,"value":3459}," BREVO_TIMEOUT_MS",{"type":31,"tag":171,"props":3461,"children":3462},{"style":276},[3463],{"type":40,"value":429},{"type":31,"tag":171,"props":3465,"children":3466},{"style":671},[3467],{"type":40,"value":3468}," 5_000",{"type":31,"tag":171,"props":3470,"children":3471},{"style":236},[3472],{"type":40,"value":471},{"type":31,"tag":171,"props":3474,"children":3475},{"class":173,"line":256},[3476,3480,3485,3489,3494],{"type":31,"tag":171,"props":3477,"children":3478},{"style":219},[3479],{"type":40,"value":3454},{"type":31,"tag":171,"props":3481,"children":3482},{"style":421},[3483],{"type":40,"value":3484}," BREVO_RETRY_MAX",{"type":31,"tag":171,"props":3486,"children":3487},{"style":276},[3488],{"type":40,"value":429},{"type":31,"tag":171,"props":3490,"children":3491},{"style":671},[3492],{"type":40,"value":3493}," 5",{"type":31,"tag":171,"props":3495,"children":3496},{"style":236},[3497],{"type":40,"value":471},{"type":31,"tag":171,"props":3499,"children":3500},{"class":173,"line":292},[3501],{"type":31,"tag":171,"props":3502,"children":3503},{"emptyLinePlaceholder":13},[3504],{"type":40,"value":190},{"type":31,"tag":171,"props":3506,"children":3507},{"class":173,"line":322},[3508,3512,3516],{"type":31,"tag":171,"props":3509,"children":3510},{"style":197},[3511],{"type":40,"value":200},{"type":31,"tag":171,"props":3513,"children":3514},{"style":203},[3515],{"type":40,"value":206},{"type":31,"tag":171,"props":3517,"children":3518},{"style":209},[3519],{"type":40,"value":212},{"type":31,"tag":171,"props":3521,"children":3522},{"class":173,"line":336},[3523,3527,3531,3535],{"type":31,"tag":171,"props":3524,"children":3525},{"style":219},[3526],{"type":40,"value":222},{"type":31,"tag":171,"props":3528,"children":3529},{"style":219},[3530],{"type":40,"value":227},{"type":31,"tag":171,"props":3532,"children":3533},{"style":230},[3534],{"type":40,"value":233},{"type":31,"tag":171,"props":3536,"children":3537},{"style":236},[3538],{"type":40,"value":239},{"type":31,"tag":171,"props":3540,"children":3541},{"class":173,"line":344},[3542,3546],{"type":31,"tag":171,"props":3543,"children":3544},{"style":219},[3545],{"type":40,"value":248},{"type":31,"tag":171,"props":3547,"children":3548},{"style":236},[3549],{"type":40,"value":253},{"type":31,"tag":171,"props":3551,"children":3552},{"class":173,"line":412},[3553,3557,3561,3565,3569,3573],{"type":31,"tag":171,"props":3554,"children":3555},{"style":219},[3556],{"type":40,"value":262},{"type":31,"tag":171,"props":3558,"children":3559},{"style":219},[3560],{"type":40,"value":267},{"type":31,"tag":171,"props":3562,"children":3563},{"style":270},[3564],{"type":40,"value":273},{"type":31,"tag":171,"props":3566,"children":3567},{"style":276},[3568],{"type":40,"value":279},{"type":31,"tag":171,"props":3570,"children":3571},{"style":230},[3572],{"type":40,"value":284},{"type":31,"tag":171,"props":3574,"children":3575},{"style":236},[3576],{"type":40,"value":289},{"type":31,"tag":171,"props":3578,"children":3579},{"class":173,"line":474},[3580,3584,3588,3592,3596,3600],{"type":31,"tag":171,"props":3581,"children":3582},{"style":219},[3583],{"type":40,"value":262},{"type":31,"tag":171,"props":3585,"children":3586},{"style":219},[3587],{"type":40,"value":267},{"type":31,"tag":171,"props":3589,"children":3590},{"style":270},[3591],{"type":40,"value":306},{"type":31,"tag":171,"props":3593,"children":3594},{"style":276},[3595],{"type":40,"value":279},{"type":31,"tag":171,"props":3597,"children":3598},{"style":230},[3599],{"type":40,"value":315},{"type":31,"tag":171,"props":3601,"children":3602},{"style":236},[3603],{"type":40,"value":289},{"type":31,"tag":171,"props":3605,"children":3606},{"class":173,"line":552},[3607,3611],{"type":31,"tag":171,"props":3608,"children":3609},{"style":236},[3610],{"type":40,"value":328},{"type":31,"tag":171,"props":3612,"children":3613},{"style":236},[3614],{"type":40,"value":333},{"type":31,"tag":171,"props":3616,"children":3617},{"class":173,"line":560},[3618],{"type":31,"tag":171,"props":3619,"children":3620},{"emptyLinePlaceholder":13},[3621],{"type":40,"value":190},{"type":31,"tag":171,"props":3623,"children":3624},{"class":173,"line":600},[3625,3629,3633,3637,3641,3645,3649,3653,3657,3661,3665,3669,3673],{"type":31,"tag":171,"props":3626,"children":3627},{"style":219},[3628],{"type":40,"value":350},{"type":31,"tag":171,"props":3630,"children":3631},{"style":203},[3632],{"type":40,"value":355},{"type":31,"tag":171,"props":3634,"children":3635},{"style":236},[3636],{"type":40,"value":360},{"type":31,"tag":171,"props":3638,"children":3639},{"style":270},[3640],{"type":40,"value":365},{"type":31,"tag":171,"props":3642,"children":3643},{"style":276},[3644],{"type":40,"value":279},{"type":31,"tag":171,"props":3646,"children":3647},{"style":372},[3648],{"type":40,"value":375},{"type":31,"tag":171,"props":3650,"children":3651},{"style":236},[3652],{"type":40,"value":380},{"type":31,"tag":171,"props":3654,"children":3655},{"style":276},[3656],{"type":40,"value":279},{"type":31,"tag":171,"props":3658,"children":3659},{"style":230},[3660],{"type":40,"value":389},{"type":31,"tag":171,"props":3662,"children":3663},{"style":392},[3664],{"type":40,"value":395},{"type":31,"tag":171,"props":3666,"children":3667},{"style":372},[3668],{"type":40,"value":400},{"type":31,"tag":171,"props":3670,"children":3671},{"style":392},[3672],{"type":40,"value":405},{"type":31,"tag":171,"props":3674,"children":3675},{"style":236},[3676],{"type":40,"value":239},{"type":31,"tag":171,"props":3678,"children":3679},{"class":173,"line":658},[3680,3684,3688,3692,3696,3700,3704,3708,3712,3716,3720],{"type":31,"tag":171,"props":3681,"children":3682},{"style":219},[3683],{"type":40,"value":418},{"type":31,"tag":171,"props":3685,"children":3686},{"style":421},[3687],{"type":40,"value":424},{"type":31,"tag":171,"props":3689,"children":3690},{"style":276},[3691],{"type":40,"value":429},{"type":31,"tag":171,"props":3693,"children":3694},{"style":219},[3695],{"type":40,"value":434},{"type":31,"tag":171,"props":3697,"children":3698},{"style":437},[3699],{"type":40,"value":440},{"type":31,"tag":171,"props":3701,"children":3702},{"style":443},[3703],{"type":40,"value":446},{"type":31,"tag":171,"props":3705,"children":3706},{"style":449},[3707],{"type":40,"value":452},{"type":31,"tag":171,"props":3709,"children":3710},{"style":443},[3711],{"type":40,"value":446},{"type":31,"tag":171,"props":3713,"children":3714},{"style":203},[3715],{"type":40,"value":461},{"type":31,"tag":171,"props":3717,"children":3718},{"style":449},[3719],{"type":40,"value":466},{"type":31,"tag":171,"props":3721,"children":3722},{"style":236},[3723],{"type":40,"value":471},{"type":31,"tag":171,"props":3725,"children":3726},{"class":173,"line":690},[3727,3731,3736,3741,3745,3749,3753,3757,3761,3765,3769,3773,3777,3781,3785,3789],{"type":31,"tag":171,"props":3728,"children":3729},{"style":219},[3730],{"type":40,"value":480},{"type":31,"tag":171,"props":3732,"children":3733},{"style":449},[3734],{"type":40,"value":3735}," (session ",{"type":31,"tag":171,"props":3737,"children":3738},{"style":276},[3739],{"type":40,"value":3740},"==",{"type":31,"tag":171,"props":3742,"children":3743},{"style":372},[3744],{"type":40,"value":2976},{"type":31,"tag":171,"props":3746,"children":3747},{"style":449},[3748],{"type":40,"value":1962},{"type":31,"tag":171,"props":3750,"children":3751},{"style":219},[3752],{"type":40,"value":500},{"type":31,"tag":171,"props":3754,"children":3755},{"style":503},[3756],{"type":40,"value":506},{"type":31,"tag":171,"props":3758,"children":3759},{"style":203},[3760],{"type":40,"value":511},{"type":31,"tag":171,"props":3762,"children":3763},{"style":449},[3764],{"type":40,"value":360},{"type":31,"tag":171,"props":3766,"children":3767},{"style":518},[3768],{"type":40,"value":521},{"type":31,"tag":171,"props":3770,"children":3771},{"style":524},[3772],{"type":40,"value":527},{"type":31,"tag":171,"props":3774,"children":3775},{"style":449},[3776],{"type":40,"value":365},{"type":31,"tag":171,"props":3778,"children":3779},{"style":524},[3780],{"type":40,"value":536},{"type":31,"tag":171,"props":3782,"children":3783},{"style":518},[3784],{"type":40,"value":541},{"type":31,"tag":171,"props":3786,"children":3787},{"style":449},[3788],{"type":40,"value":380},{"type":31,"tag":171,"props":3790,"children":3791},{"style":236},[3792],{"type":40,"value":471},{"type":31,"tag":171,"props":3794,"children":3795},{"class":173,"line":735},[3796],{"type":31,"tag":171,"props":3797,"children":3798},{"emptyLinePlaceholder":13},[3799],{"type":40,"value":190},{"type":31,"tag":171,"props":3801,"children":3802},{"class":173,"line":752},[3803],{"type":31,"tag":171,"props":3804,"children":3805},{"style":178},[3806],{"type":40,"value":3807},"    // idempotence : ne pas renvoyer si déjà envoyé\n",{"type":31,"tag":171,"props":3809,"children":3810},{"class":173,"line":761},[3811,3815,3820,3824,3829,3834,3838,3842,3847],{"type":31,"tag":171,"props":3812,"children":3813},{"style":219},[3814],{"type":40,"value":480},{"type":31,"tag":171,"props":3816,"children":3817},{"style":449},[3818],{"type":40,"value":3819}," (session",{"type":31,"tag":171,"props":3821,"children":3822},{"style":443},[3823],{"type":40,"value":446},{"type":31,"tag":171,"props":3825,"children":3826},{"style":449},[3827],{"type":40,"value":3828},"notificationSentAt ",{"type":31,"tag":171,"props":3830,"children":3831},{"style":276},[3832],{"type":40,"value":3833},"!=",{"type":31,"tag":171,"props":3835,"children":3836},{"style":372},[3837],{"type":40,"value":2976},{"type":31,"tag":171,"props":3839,"children":3840},{"style":449},[3841],{"type":40,"value":1962},{"type":31,"tag":171,"props":3843,"children":3844},{"style":219},[3845],{"type":40,"value":3846},"return",{"type":31,"tag":171,"props":3848,"children":3849},{"style":236},[3850],{"type":40,"value":471},{"type":31,"tag":171,"props":3852,"children":3853},{"class":173,"line":1616},[3854],{"type":31,"tag":171,"props":3855,"children":3856},{"emptyLinePlaceholder":13},[3857],{"type":40,"value":190},{"type":31,"tag":171,"props":3859,"children":3860},{"class":173,"line":2246},[3861,3865,3869],{"type":31,"tag":171,"props":3862,"children":3863},{"style":219},[3864],{"type":40,"value":566},{"type":31,"tag":171,"props":3866,"children":3867},{"style":203},[3868],{"type":40,"value":3408},{"type":31,"tag":171,"props":3870,"children":3871},{"style":449},[3872],{"type":40,"value":253},{"type":31,"tag":171,"props":3874,"children":3875},{"class":173,"line":2802},[3876,3881,3885,3889],{"type":31,"tag":171,"props":3877,"children":3878},{"style":219},[3879],{"type":40,"value":3880},"      async",{"type":31,"tag":171,"props":3882,"children":3883},{"style":236},[3884],{"type":40,"value":953},{"type":31,"tag":171,"props":3886,"children":3887},{"style":276},[3888],{"type":40,"value":958},{"type":31,"tag":171,"props":3890,"children":3891},{"style":236},[3892],{"type":40,"value":239},{"type":31,"tag":171,"props":3894,"children":3896},{"class":173,"line":3895},24,[3897,3902,3907,3911,3915,3920,3924],{"type":31,"tag":171,"props":3898,"children":3899},{"style":219},[3900],{"type":40,"value":3901},"        const",{"type":31,"tag":171,"props":3903,"children":3904},{"style":421},[3905],{"type":40,"value":3906}," controller",{"type":31,"tag":171,"props":3908,"children":3909},{"style":276},[3910],{"type":40,"value":429},{"type":31,"tag":171,"props":3912,"children":3913},{"style":503},[3914],{"type":40,"value":506},{"type":31,"tag":171,"props":3916,"children":3917},{"style":203},[3918],{"type":40,"value":3919}," AbortController",{"type":31,"tag":171,"props":3921,"children":3922},{"style":449},[3923],{"type":40,"value":1807},{"type":31,"tag":171,"props":3925,"children":3926},{"style":236},[3927],{"type":40,"value":471},{"type":31,"tag":171,"props":3929,"children":3931},{"class":173,"line":3930},25,[3932,3936,3941,3945,3950,3954,3958,3962,3966,3970,3975,3979,3983,3987,3991],{"type":31,"tag":171,"props":3933,"children":3934},{"style":219},[3935],{"type":40,"value":3901},{"type":31,"tag":171,"props":3937,"children":3938},{"style":421},[3939],{"type":40,"value":3940}," timer",{"type":31,"tag":171,"props":3942,"children":3943},{"style":276},[3944],{"type":40,"value":429},{"type":31,"tag":171,"props":3946,"children":3947},{"style":203},[3948],{"type":40,"value":3949}," setTimeout",{"type":31,"tag":171,"props":3951,"children":3952},{"style":449},[3953],{"type":40,"value":360},{"type":31,"tag":171,"props":3955,"children":3956},{"style":236},[3957],{"type":40,"value":1807},{"type":31,"tag":171,"props":3959,"children":3960},{"style":276},[3961],{"type":40,"value":958},{"type":31,"tag":171,"props":3963,"children":3964},{"style":449},[3965],{"type":40,"value":3906},{"type":31,"tag":171,"props":3967,"children":3968},{"style":443},[3969],{"type":40,"value":446},{"type":31,"tag":171,"props":3971,"children":3972},{"style":203},[3973],{"type":40,"value":3974},"abort",{"type":31,"tag":171,"props":3976,"children":3977},{"style":449},[3978],{"type":40,"value":1807},{"type":31,"tag":171,"props":3980,"children":3981},{"style":236},[3982],{"type":40,"value":943},{"type":31,"tag":171,"props":3984,"children":3985},{"style":421},[3986],{"type":40,"value":3459},{"type":31,"tag":171,"props":3988,"children":3989},{"style":449},[3990],{"type":40,"value":380},{"type":31,"tag":171,"props":3992,"children":3993},{"style":236},[3994],{"type":40,"value":471},{"type":31,"tag":171,"props":3996,"children":3998},{"class":173,"line":3997},26,[3999],{"type":31,"tag":171,"props":4000,"children":4001},{"emptyLinePlaceholder":13},[4002],{"type":40,"value":190},{"type":31,"tag":171,"props":4004,"children":4006},{"class":173,"line":4005},27,[4007,4012],{"type":31,"tag":171,"props":4008,"children":4009},{"style":219},[4010],{"type":40,"value":4011},"        try",{"type":31,"tag":171,"props":4013,"children":4014},{"style":236},[4015],{"type":40,"value":239},{"type":31,"tag":171,"props":4017,"children":4019},{"class":173,"line":4018},28,[4020,4025,4029,4033,4037,4041,4045],{"type":31,"tag":171,"props":4021,"children":4022},{"style":219},[4023],{"type":40,"value":4024},"          await",{"type":31,"tag":171,"props":4026,"children":4027},{"style":437},[4028],{"type":40,"value":440},{"type":31,"tag":171,"props":4030,"children":4031},{"style":443},[4032],{"type":40,"value":446},{"type":31,"tag":171,"props":4034,"children":4035},{"style":449},[4036],{"type":40,"value":579},{"type":31,"tag":171,"props":4038,"children":4039},{"style":443},[4040],{"type":40,"value":446},{"type":31,"tag":171,"props":4042,"children":4043},{"style":203},[4044],{"type":40,"value":588},{"type":31,"tag":171,"props":4046,"children":4047},{"style":449},[4048],{"type":40,"value":253},{"type":31,"tag":171,"props":4050,"children":4052},{"class":173,"line":4051},29,[4053],{"type":31,"tag":171,"props":4054,"children":4055},{"style":236},[4056],{"type":40,"value":4057},"            {\n",{"type":31,"tag":171,"props":4059,"children":4061},{"class":173,"line":4060},30,[4062,4067,4071,4075,4079,4083,4087,4091,4095,4099,4103,4107],{"type":31,"tag":171,"props":4063,"children":4064},{"style":449},[4065],{"type":40,"value":4066},"              to",{"type":31,"tag":171,"props":4068,"children":4069},{"style":443},[4070],{"type":40,"value":279},{"type":31,"tag":171,"props":4072,"children":4073},{"style":449},[4074],{"type":40,"value":615},{"type":31,"tag":171,"props":4076,"children":4077},{"style":236},[4078],{"type":40,"value":620},{"type":31,"tag":171,"props":4080,"children":4081},{"style":449},[4082],{"type":40,"value":625},{"type":31,"tag":171,"props":4084,"children":4085},{"style":443},[4086],{"type":40,"value":279},{"type":31,"tag":171,"props":4088,"children":4089},{"style":449},[4090],{"type":40,"value":424},{"type":31,"tag":171,"props":4092,"children":4093},{"style":443},[4094],{"type":40,"value":446},{"type":31,"tag":171,"props":4096,"children":4097},{"style":449},[4098],{"type":40,"value":642},{"type":31,"tag":171,"props":4100,"children":4101},{"style":236},[4102],{"type":40,"value":536},{"type":31,"tag":171,"props":4104,"children":4105},{"style":449},[4106],{"type":40,"value":651},{"type":31,"tag":171,"props":4108,"children":4109},{"style":236},[4110],{"type":40,"value":289},{"type":31,"tag":171,"props":4112,"children":4114},{"class":173,"line":4113},31,[4115,4120,4124,4128,4132,4136],{"type":31,"tag":171,"props":4116,"children":4117},{"style":449},[4118],{"type":40,"value":4119},"              templateId",{"type":31,"tag":171,"props":4121,"children":4122},{"style":443},[4123],{"type":40,"value":279},{"type":31,"tag":171,"props":4125,"children":4126},{"style":671},[4127],{"type":40,"value":674},{"type":31,"tag":171,"props":4129,"children":4130},{"style":443},[4131],{"type":40,"value":446},{"type":31,"tag":171,"props":4133,"children":4134},{"style":671},[4135],{"type":40,"value":683},{"type":31,"tag":171,"props":4137,"children":4138},{"style":236},[4139],{"type":40,"value":289},{"type":31,"tag":171,"props":4141,"children":4143},{"class":173,"line":4142},32,[4144,4149,4153,4157,4161,4165,4169,4173,4177],{"type":31,"tag":171,"props":4145,"children":4146},{"style":449},[4147],{"type":40,"value":4148},"              params",{"type":31,"tag":171,"props":4150,"children":4151},{"style":443},[4152],{"type":40,"value":279},{"type":31,"tag":171,"props":4154,"children":4155},{"style":236},[4156],{"type":40,"value":705},{"type":31,"tag":171,"props":4158,"children":4159},{"style":449},[4160],{"type":40,"value":710},{"type":31,"tag":171,"props":4162,"children":4163},{"style":443},[4164],{"type":40,"value":279},{"type":31,"tag":171,"props":4166,"children":4167},{"style":449},[4168],{"type":40,"value":424},{"type":31,"tag":171,"props":4170,"children":4171},{"style":443},[4172],{"type":40,"value":446},{"type":31,"tag":171,"props":4174,"children":4175},{"style":449},[4176],{"type":40,"value":727},{"type":31,"tag":171,"props":4178,"children":4179},{"style":236},[4180],{"type":40,"value":732},{"type":31,"tag":171,"props":4182,"children":4184},{"class":173,"line":4183},33,[4185],{"type":31,"tag":171,"props":4186,"children":4187},{"style":236},[4188],{"type":40,"value":4189},"            },\n",{"type":31,"tag":171,"props":4191,"children":4193},{"class":173,"line":4192},34,[4194,4199,4204,4208,4212,4216,4221],{"type":31,"tag":171,"props":4195,"children":4196},{"style":236},[4197],{"type":40,"value":4198},"            {",{"type":31,"tag":171,"props":4200,"children":4201},{"style":449},[4202],{"type":40,"value":4203}," signal",{"type":31,"tag":171,"props":4205,"children":4206},{"style":443},[4207],{"type":40,"value":279},{"type":31,"tag":171,"props":4209,"children":4210},{"style":449},[4211],{"type":40,"value":3906},{"type":31,"tag":171,"props":4213,"children":4214},{"style":443},[4215],{"type":40,"value":446},{"type":31,"tag":171,"props":4217,"children":4218},{"style":449},[4219],{"type":40,"value":4220},"signal ",{"type":31,"tag":171,"props":4222,"children":4223},{"style":236},[4224],{"type":40,"value":732},{"type":31,"tag":171,"props":4226,"children":4228},{"class":173,"line":4227},35,[4229,4234],{"type":31,"tag":171,"props":4230,"children":4231},{"style":449},[4232],{"type":40,"value":4233},"          )",{"type":31,"tag":171,"props":4235,"children":4236},{"style":236},[4237],{"type":40,"value":471},{"type":31,"tag":171,"props":4239,"children":4241},{"class":173,"line":4240},36,[4242,4247,4252,4256,4261,4265,4270,4274],{"type":31,"tag":171,"props":4243,"children":4244},{"style":236},[4245],{"type":40,"value":4246},"        }",{"type":31,"tag":171,"props":4248,"children":4249},{"style":219},[4250],{"type":40,"value":4251}," catch",{"type":31,"tag":171,"props":4253,"children":4254},{"style":236},[4255],{"type":40,"value":485},{"type":31,"tag":171,"props":4257,"children":4258},{"style":270},[4259],{"type":40,"value":4260},"err",{"type":31,"tag":171,"props":4262,"children":4263},{"style":276},[4264],{"type":40,"value":279},{"type":31,"tag":171,"props":4266,"children":4267},{"style":372},[4268],{"type":40,"value":4269}," unknown",{"type":31,"tag":171,"props":4271,"children":4272},{"style":236},[4273],{"type":40,"value":380},{"type":31,"tag":171,"props":4275,"children":4276},{"style":236},[4277],{"type":40,"value":239},{"type":31,"tag":171,"props":4279,"children":4281},{"class":173,"line":4280},37,[4282,4287,4292],{"type":31,"tag":171,"props":4283,"children":4284},{"style":203},[4285],{"type":40,"value":4286},"          clearTimeout",{"type":31,"tag":171,"props":4288,"children":4289},{"style":449},[4290],{"type":40,"value":4291},"(timer)",{"type":31,"tag":171,"props":4293,"children":4294},{"style":236},[4295],{"type":40,"value":471},{"type":31,"tag":171,"props":4297,"children":4299},{"class":173,"line":4298},38,[4300,4305,4310,4314,4319,4323,4328],{"type":31,"tag":171,"props":4301,"children":4302},{"style":219},[4303],{"type":40,"value":4304},"          if",{"type":31,"tag":171,"props":4306,"children":4307},{"style":449},[4308],{"type":40,"value":4309}," (controller",{"type":31,"tag":171,"props":4311,"children":4312},{"style":443},[4313],{"type":40,"value":446},{"type":31,"tag":171,"props":4315,"children":4316},{"style":449},[4317],{"type":40,"value":4318},"signal",{"type":31,"tag":171,"props":4320,"children":4321},{"style":443},[4322],{"type":40,"value":446},{"type":31,"tag":171,"props":4324,"children":4325},{"style":449},[4326],{"type":40,"value":4327},"aborted) ",{"type":31,"tag":171,"props":4329,"children":4330},{"style":236},[4331],{"type":40,"value":597},{"type":31,"tag":171,"props":4333,"children":4335},{"class":173,"line":4334},39,[4336,4341,4345,4350,4354,4358,4362],{"type":31,"tag":171,"props":4337,"children":4338},{"style":219},[4339],{"type":40,"value":4340},"            throw",{"type":31,"tag":171,"props":4342,"children":4343},{"style":503},[4344],{"type":40,"value":506},{"type":31,"tag":171,"props":4346,"children":4347},{"style":203},[4348],{"type":40,"value":4349}," AbortError",{"type":31,"tag":171,"props":4351,"children":4352},{"style":449},[4353],{"type":40,"value":360},{"type":31,"tag":171,"props":4355,"children":4356},{"style":518},[4357],{"type":40,"value":2760},{"type":31,"tag":171,"props":4359,"children":4360},{"style":449},[4361],{"type":40,"value":380},{"type":31,"tag":171,"props":4363,"children":4364},{"style":236},[4365],{"type":40,"value":471},{"type":31,"tag":171,"props":4367,"children":4369},{"class":173,"line":4368},40,[4370],{"type":31,"tag":171,"props":4371,"children":4372},{"style":236},[4373],{"type":40,"value":4374},"          }\n",{"type":31,"tag":171,"props":4376,"children":4378},{"class":173,"line":4377},41,[4379,4384,4388,4392,4397,4401,4405,4409,4414,4418,4422,4426,4430,4435],{"type":31,"tag":171,"props":4380,"children":4381},{"style":219},[4382],{"type":40,"value":4383},"          const",{"type":31,"tag":171,"props":4385,"children":4386},{"style":421},[4387],{"type":40,"value":2028},{"type":31,"tag":171,"props":4389,"children":4390},{"style":276},[4391],{"type":40,"value":429},{"type":31,"tag":171,"props":4393,"children":4394},{"style":449},[4395],{"type":40,"value":4396}," (err ",{"type":31,"tag":171,"props":4398,"children":4399},{"style":219},[4400],{"type":40,"value":2009},{"type":31,"tag":171,"props":4402,"children":4403},{"style":236},[4404],{"type":40,"value":705},{"type":31,"tag":171,"props":4406,"children":4407},{"style":2025},[4408],{"type":40,"value":2028},{"type":31,"tag":171,"props":4410,"children":4411},{"style":276},[4412],{"type":40,"value":4413},"?:",{"type":31,"tag":171,"props":4415,"children":4416},{"style":372},[4417],{"type":40,"value":2037},{"type":31,"tag":171,"props":4419,"children":4420},{"style":236},[4421],{"type":40,"value":2585},{"type":31,"tag":171,"props":4423,"children":4424},{"style":449},[4425],{"type":40,"value":380},{"type":31,"tag":171,"props":4427,"children":4428},{"style":443},[4429],{"type":40,"value":446},{"type":31,"tag":171,"props":4431,"children":4432},{"style":449},[4433],{"type":40,"value":4434},"statusCode",{"type":31,"tag":171,"props":4436,"children":4437},{"style":236},[4438],{"type":40,"value":471},{"type":31,"tag":171,"props":4440,"children":4442},{"class":173,"line":4441},42,[4443,4447,4452,4456,4460,4465,4470,4474,4479,4483,4487,4491,4496],{"type":31,"tag":171,"props":4444,"children":4445},{"style":219},[4446],{"type":40,"value":4304},{"type":31,"tag":171,"props":4448,"children":4449},{"style":449},[4450],{"type":40,"value":4451}," (statusCode ",{"type":31,"tag":171,"props":4453,"children":4454},{"style":276},[4455],{"type":40,"value":1516},{"type":31,"tag":171,"props":4457,"children":4458},{"style":671},[4459],{"type":40,"value":2068},{"type":31,"tag":171,"props":4461,"children":4462},{"style":276},[4463],{"type":40,"value":4464}," ||",{"type":31,"tag":171,"props":4466,"children":4467},{"style":449},[4468],{"type":40,"value":4469}," statusCode ",{"type":31,"tag":171,"props":4471,"children":4472},{"style":276},[4473],{"type":40,"value":1516},{"type":31,"tag":171,"props":4475,"children":4476},{"style":671},[4477],{"type":40,"value":4478}," 503",{"type":31,"tag":171,"props":4480,"children":4481},{"style":449},[4482],{"type":40,"value":1962},{"type":31,"tag":171,"props":4484,"children":4485},{"style":219},[4486],{"type":40,"value":500},{"type":31,"tag":171,"props":4488,"children":4489},{"style":449},[4490],{"type":40,"value":1979},{"type":31,"tag":171,"props":4492,"children":4493},{"style":236},[4494],{"type":40,"value":4495},";",{"type":31,"tag":171,"props":4497,"children":4498},{"style":178},[4499],{"type":40,"value":4500}," // retry\n",{"type":31,"tag":171,"props":4502,"children":4504},{"class":173,"line":4503},43,[4505,4510,4514,4518,4523,4527,4531,4535,4539,4544,4548],{"type":31,"tag":171,"props":4506,"children":4507},{"style":219},[4508],{"type":40,"value":4509},"          throw",{"type":31,"tag":171,"props":4511,"children":4512},{"style":503},[4513],{"type":40,"value":506},{"type":31,"tag":171,"props":4515,"children":4516},{"style":203},[4517],{"type":40,"value":4349},{"type":31,"tag":171,"props":4519,"children":4520},{"style":449},[4521],{"type":40,"value":4522},"((err ",{"type":31,"tag":171,"props":4524,"children":4525},{"style":219},[4526],{"type":40,"value":2009},{"type":31,"tag":171,"props":4528,"children":4529},{"style":230},[4530],{"type":40,"value":511},{"type":31,"tag":171,"props":4532,"children":4533},{"style":449},[4534],{"type":40,"value":380},{"type":31,"tag":171,"props":4536,"children":4537},{"style":443},[4538],{"type":40,"value":446},{"type":31,"tag":171,"props":4540,"children":4541},{"style":449},[4542],{"type":40,"value":4543},"message)",{"type":31,"tag":171,"props":4545,"children":4546},{"style":236},[4547],{"type":40,"value":4495},{"type":31,"tag":171,"props":4549,"children":4550},{"style":178},[4551],{"type":40,"value":4552}," // pas de retry sur les 4xx\n",{"type":31,"tag":171,"props":4554,"children":4556},{"class":173,"line":4555},44,[4557],{"type":31,"tag":171,"props":4558,"children":4559},{"style":236},[4560],{"type":40,"value":4561},"        }\n",{"type":31,"tag":171,"props":4563,"children":4565},{"class":173,"line":4564},45,[4566,4571,4575],{"type":31,"tag":171,"props":4567,"children":4568},{"style":203},[4569],{"type":40,"value":4570},"        clearTimeout",{"type":31,"tag":171,"props":4572,"children":4573},{"style":449},[4574],{"type":40,"value":4291},{"type":31,"tag":171,"props":4576,"children":4577},{"style":236},[4578],{"type":40,"value":471},{"type":31,"tag":171,"props":4580,"children":4582},{"class":173,"line":4581},46,[4583],{"type":31,"tag":171,"props":4584,"children":4585},{"style":236},[4586],{"type":40,"value":4587},"      },\n",{"type":31,"tag":171,"props":4589,"children":4591},{"class":173,"line":4590},47,[4592],{"type":31,"tag":171,"props":4593,"children":4594},{"style":236},[4595],{"type":40,"value":4596},"      {\n",{"type":31,"tag":171,"props":4598,"children":4600},{"class":173,"line":4599},48,[4601,4606,4610,4614],{"type":31,"tag":171,"props":4602,"children":4603},{"style":449},[4604],{"type":40,"value":4605},"        retries",{"type":31,"tag":171,"props":4607,"children":4608},{"style":443},[4609],{"type":40,"value":279},{"type":31,"tag":171,"props":4611,"children":4612},{"style":421},[4613],{"type":40,"value":3484},{"type":31,"tag":171,"props":4615,"children":4616},{"style":236},[4617],{"type":40,"value":289},{"type":31,"tag":171,"props":4619,"children":4621},{"class":173,"line":4620},49,[4622,4627,4631,4636],{"type":31,"tag":171,"props":4623,"children":4624},{"style":449},[4625],{"type":40,"value":4626},"        factor",{"type":31,"tag":171,"props":4628,"children":4629},{"style":443},[4630],{"type":40,"value":279},{"type":31,"tag":171,"props":4632,"children":4633},{"style":671},[4634],{"type":40,"value":4635}," 2",{"type":31,"tag":171,"props":4637,"children":4638},{"style":236},[4639],{"type":40,"value":289},{"type":31,"tag":171,"props":4641,"children":4643},{"class":173,"line":4642},50,[4644,4649,4653,4658],{"type":31,"tag":171,"props":4645,"children":4646},{"style":449},[4647],{"type":40,"value":4648},"        minTimeout",{"type":31,"tag":171,"props":4650,"children":4651},{"style":443},[4652],{"type":40,"value":279},{"type":31,"tag":171,"props":4654,"children":4655},{"style":671},[4656],{"type":40,"value":4657}," 100",{"type":31,"tag":171,"props":4659,"children":4660},{"style":236},[4661],{"type":40,"value":289},{"type":31,"tag":171,"props":4663,"children":4665},{"class":173,"line":4664},51,[4666,4671,4675,4679,4684,4688,4692],{"type":31,"tag":171,"props":4667,"children":4668},{"style":203},[4669],{"type":40,"value":4670},"        onFailedAttempt",{"type":31,"tag":171,"props":4672,"children":4673},{"style":443},[4674],{"type":40,"value":279},{"type":31,"tag":171,"props":4676,"children":4677},{"style":236},[4678],{"type":40,"value":485},{"type":31,"tag":171,"props":4680,"children":4681},{"style":270},[4682],{"type":40,"value":4683},"error",{"type":31,"tag":171,"props":4685,"children":4686},{"style":236},[4687],{"type":40,"value":380},{"type":31,"tag":171,"props":4689,"children":4690},{"style":276},[4691],{"type":40,"value":958},{"type":31,"tag":171,"props":4693,"children":4694},{"style":236},[4695],{"type":40,"value":239},{"type":31,"tag":171,"props":4697,"children":4699},{"class":173,"line":4698},52,[4700,4704,4709,4713,4718,4722,4726,4730,4734,4739],{"type":31,"tag":171,"props":4701,"children":4702},{"style":219},[4703],{"type":40,"value":4304},{"type":31,"tag":171,"props":4705,"children":4706},{"style":449},[4707],{"type":40,"value":4708}," (error",{"type":31,"tag":171,"props":4710,"children":4711},{"style":443},[4712],{"type":40,"value":446},{"type":31,"tag":171,"props":4714,"children":4715},{"style":449},[4716],{"type":40,"value":4717},"retriesLeft ",{"type":31,"tag":171,"props":4719,"children":4720},{"style":276},[4721],{"type":40,"value":1516},{"type":31,"tag":171,"props":4723,"children":4724},{"style":671},[4725],{"type":40,"value":1856},{"type":31,"tag":171,"props":4727,"children":4728},{"style":449},[4729],{"type":40,"value":1962},{"type":31,"tag":171,"props":4731,"children":4732},{"style":219},[4733],{"type":40,"value":500},{"type":31,"tag":171,"props":4735,"children":4736},{"style":449},[4737],{"type":40,"value":4738}," error",{"type":31,"tag":171,"props":4740,"children":4741},{"style":236},[4742],{"type":40,"value":471},{"type":31,"tag":171,"props":4744,"children":4746},{"class":173,"line":4745},53,[4747],{"type":31,"tag":171,"props":4748,"children":4749},{"style":236},[4750],{"type":40,"value":4751},"        },\n",{"type":31,"tag":171,"props":4753,"children":4755},{"class":173,"line":4754},54,[4756],{"type":31,"tag":171,"props":4757,"children":4758},{"style":236},[4759],{"type":40,"value":4587},{"type":31,"tag":171,"props":4761,"children":4763},{"class":173,"line":4762},55,[4764,4769],{"type":31,"tag":171,"props":4765,"children":4766},{"style":449},[4767],{"type":40,"value":4768},"    )",{"type":31,"tag":171,"props":4770,"children":4771},{"style":236},[4772],{"type":40,"value":471},{"type":31,"tag":171,"props":4774,"children":4776},{"class":173,"line":4775},56,[4777],{"type":31,"tag":171,"props":4778,"children":4779},{"emptyLinePlaceholder":13},[4780],{"type":40,"value":190},{"type":31,"tag":171,"props":4782,"children":4784},{"class":173,"line":4783},57,[4785,4789,4793,4797,4801,4805,4810,4815,4819,4823,4827,4832],{"type":31,"tag":171,"props":4786,"children":4787},{"style":219},[4788],{"type":40,"value":566},{"type":31,"tag":171,"props":4790,"children":4791},{"style":437},[4792],{"type":40,"value":440},{"type":31,"tag":171,"props":4794,"children":4795},{"style":443},[4796],{"type":40,"value":446},{"type":31,"tag":171,"props":4798,"children":4799},{"style":449},[4800],{"type":40,"value":452},{"type":31,"tag":171,"props":4802,"children":4803},{"style":443},[4804],{"type":40,"value":446},{"type":31,"tag":171,"props":4806,"children":4807},{"style":203},[4808],{"type":40,"value":4809},"markNotified",{"type":31,"tag":171,"props":4811,"children":4812},{"style":449},[4813],{"type":40,"value":4814},"(sessionId",{"type":31,"tag":171,"props":4816,"children":4817},{"style":236},[4818],{"type":40,"value":943},{"type":31,"tag":171,"props":4820,"children":4821},{"style":503},[4822],{"type":40,"value":506},{"type":31,"tag":171,"props":4824,"children":4825},{"style":203},[4826],{"type":40,"value":1236},{"type":31,"tag":171,"props":4828,"children":4829},{"style":449},[4830],{"type":40,"value":4831},"())",{"type":31,"tag":171,"props":4833,"children":4834},{"style":236},[4835],{"type":40,"value":471},{"type":31,"tag":171,"props":4837,"children":4839},{"class":173,"line":4838},58,[4840],{"type":31,"tag":171,"props":4841,"children":4842},{"style":236},[4843],{"type":40,"value":758},{"type":31,"tag":171,"props":4845,"children":4847},{"class":173,"line":4846},59,[4848],{"type":31,"tag":171,"props":4849,"children":4850},{"style":236},[4851],{"type":40,"value":767},{"type":31,"tag":32,"props":4853,"children":4854},{},[4855,4857,4862,4864,4870],{"type":40,"value":4856},"Quelques lignes de plus en surface. Les 4 modes d'échec couverts. Le wrapper anti-fragile est la combinaison qui rend Claude utilisable en prod. C'est ce que recommande Martin Fowler dans ",{"type":31,"tag":132,"props":4858,"children":4859},{},[4860],{"type":40,"value":4861},"Patterns of Enterprise Application Architecture",{"type":40,"value":4863}," (2002) sur les ",{"type":31,"tag":64,"props":4865,"children":4867},{"href":4866},"/fr/architecture-craft/patterns-resilience-circuit-breaker-retry",[4868],{"type":40,"value":4869},"patterns de résilience type Circuit Breaker et Retry",{"type":40,"value":446},{"type":31,"tag":48,"props":4872,"children":4873},{},[],{"type":31,"tag":52,"props":4875,"children":4877},{"id":4876},"comment-intégrer-ces-tests-sans-ralentir-la-ci",[4878],{"type":40,"value":4879},"Comment intégrer ces tests sans ralentir la CI",{"type":31,"tag":32,"props":4881,"children":4882},{},[4883,4885,4890],{"type":40,"value":4884},"L'objection classique : ",{"type":31,"tag":132,"props":4886,"children":4887},{},[4888],{"type":40,"value":4889},"\"On va mettre 15 minutes de CI au lieu de 4.\"",{"type":40,"value":4891}," Voici comment je structure la pyramide sur crmcoaching pour que ça ne soit pas le cas.",{"type":31,"tag":32,"props":4893,"children":4894},{},[4895,4900,4902,4907],{"type":31,"tag":36,"props":4896,"children":4897},{},[4898],{"type":40,"value":4899},"Etage 1 : tests unitaires Vitest (90% du volume).",{"type":40,"value":4901}," Tournent en moins de 2 minutes. Tous les comportements métier sont couverts ici, en utilisant des fakes en mémoire ou des mocks ",{"type":31,"tag":88,"props":4903,"children":4905},{"className":4904},[],[4906],{"type":40,"value":794},{"type":40,"value":4908}," au lieu de vraies dépendances. C'est l'etage où les 4 tests \"concurrence, 429, timeout, partial failure\" vivent, mais sur du code instrumenté pour ne pas réellement faire d'I/O réseau vers Brevo.",{"type":31,"tag":32,"props":4910,"children":4911},{},[4912,4917,4919,4925],{"type":31,"tag":36,"props":4913,"children":4914},{},[4915],{"type":40,"value":4916},"Etage 2 : tests d'intégration NestJS (8% du volume).",{"type":40,"value":4918}," Tournent en 3-5 minutes en parallèle. Valident que les adapters (Prisma, client Brevo, jobs Bull) fonctionnent avec leurs vraies implémentations contre des conteneurs Docker (Postgres, Brevo sandbox). On ne re-teste pas la logique métier ici, on teste l'intégration. Tout ce qui touche au piège classique des ",{"type":31,"tag":64,"props":4920,"children":4922},{"href":4921},"/fr/dette-technique/tests-integration-legacy-pieges",[4923],{"type":40,"value":4924},"tests d'intégration sur du code legacy",{"type":40,"value":4926}," est traité dans un article dédié.",{"type":31,"tag":32,"props":4928,"children":4929},{},[4930,4935],{"type":31,"tag":36,"props":4931,"children":4932},{},[4933],{"type":40,"value":4934},"Etage 3 : tests end-to-end (2% du volume).",{"type":40,"value":4936}," Tournent en 5-10 minutes sur un seul scénario critique end-to-end, en pre-prod. C'est l'etage \"ça marche vraiment quand tout est branché, Brevo compris\".",{"type":31,"tag":32,"props":4938,"children":4939},{},[4940,4942,4948],{"type":40,"value":4941},"Avec cette pyramide, ajouter 4 tests de modes d'échec à l'etage 1 coûte 0,5 seconde de plus en CI par module. C'est négligeable. C'est exactement le sujet que je traite quand j'aide une équipe à se rapprocher de la ",{"type":31,"tag":64,"props":4943,"children":4945},{"href":4944},"/fr/dette-technique/definition-of-done-qualite",[4946],{"type":40,"value":4947},"Definition of Done sur la qualité",{"type":40,"value":446},{"type":31,"tag":48,"props":4950,"children":4951},{},[],{"type":31,"tag":52,"props":4953,"children":4955},{"id":4954},"ce-que-ça-change-concrètement",[4956],{"type":40,"value":4957},"Ce que ça change concrètement",{"type":31,"tag":32,"props":4959,"children":4960},{},[4961],{"type":40,"value":4962},"Depuis que j'ai installé cette discipline sur crmcoaching, les chiffres sur 3 mois sont nets.",{"type":31,"tag":4964,"props":4965,"children":4966},"table",{},[4967,4991],{"type":31,"tag":4968,"props":4969,"children":4970},"thead",{},[4971],{"type":31,"tag":4972,"props":4973,"children":4974},"tr",{},[4975,4981,4986],{"type":31,"tag":4976,"props":4977,"children":4978},"th",{},[4979],{"type":40,"value":4980},"Métrique",{"type":31,"tag":4976,"props":4982,"children":4983},{},[4984],{"type":40,"value":4985},"Avant",{"type":31,"tag":4976,"props":4987,"children":4988},{},[4989],{"type":40,"value":4990},"Après 3 mois",{"type":31,"tag":4992,"props":4993,"children":4994},"tbody",{},[4995,5014,5032,5050],{"type":31,"tag":4972,"props":4996,"children":4997},{},[4998,5004,5009],{"type":31,"tag":4999,"props":5000,"children":5001},"td",{},[5002],{"type":40,"value":5003},"Incidents prod liés à un mode d'échec non testé",{"type":31,"tag":4999,"props":5005,"children":5006},{},[5007],{"type":40,"value":5008},"3 par trimestre",{"type":31,"tag":4999,"props":5010,"children":5011},{},[5012],{"type":40,"value":5013},"0 par trimestre",{"type":31,"tag":4972,"props":5015,"children":5016},{},[5017,5022,5027],{"type":31,"tag":4999,"props":5018,"children":5019},{},[5020],{"type":40,"value":5021},"MTTR (temps moyen de restauration)",{"type":31,"tag":4999,"props":5023,"children":5024},{},[5025],{"type":40,"value":5026},"2h30",{"type":31,"tag":4999,"props":5028,"children":5029},{},[5030],{"type":40,"value":5031},"30 minutes",{"type":31,"tag":4972,"props":5033,"children":5034},{},[5035,5040,5045],{"type":31,"tag":4999,"props":5036,"children":5037},{},[5038],{"type":40,"value":5039},"Confiance pour déployer le vendredi",{"type":31,"tag":4999,"props":5041,"children":5042},{},[5043],{"type":40,"value":5044},"\"pas avant lundi\"",{"type":31,"tag":4999,"props":5046,"children":5047},{},[5048],{"type":40,"value":5049},"\"sans stress\"",{"type":31,"tag":4972,"props":5051,"children":5052},{},[5053,5058,5063],{"type":31,"tag":4999,"props":5054,"children":5055},{},[5056],{"type":40,"value":5057},"Heures consacrées au debug post-incident",{"type":31,"tag":4999,"props":5059,"children":5060},{},[5061],{"type":40,"value":5062},"12h par trimestre",{"type":31,"tag":4999,"props":5064,"children":5065},{},[5066],{"type":40,"value":5067},"2h par trimestre",{"type":31,"tag":32,"props":5069,"children":5070},{},[5071,5073,5078],{"type":40,"value":5072},"Le gain n'est pas que technique. Quand je sais que mes tests couvrent les modes d'échec, je déploie sereinement. Quand je crains mes propres déploiements, je me freine, je retarde les releases, je perds du flux. La métrique sous-jacente, c'est ce que la DORA appelle le ",{"type":31,"tag":132,"props":5074,"children":5075},{},[5076],{"type":40,"value":5077},"Mean Time to Restore",{"type":40,"value":5079},", et c'est l'un des 4 indicateurs de performance d'une équipe engineering.",{"type":31,"tag":48,"props":5081,"children":5082},{},[],{"type":31,"tag":52,"props":5084,"children":5086},{"id":5085},"conclusion",[5087],{"type":40,"value":5088},"Conclusion",{"type":31,"tag":32,"props":5090,"children":5091},{},[5092],{"type":40,"value":5093},"Ce que je veux que vous reteniez de cet article, c'est que les tests Claude couvrent ce que Claude voit. Et Claude ne voit pas la prod. Il ne voit pas la concurrence à 2h du matin sur un weekend. Il ne voit pas le rate limit de Brevo qui change à 30 secondes près. Il ne voit pas le timeout silencieux qui bouche votre queue de jobs. Si vous lui demandez \"écris les tests\", vous obtenez le filet du happy path. Si vous lui demandez \"écris les 4 tests de modes d'échec critiques\", vous obtenez un filet utile.",{"type":31,"tag":32,"props":5095,"children":5096},{},[5097],{"type":40,"value":5098},"Votre rôle de développeur solo ou de senior en 2026 n'est pas de relire des assertions. C'est de nommer explicitement les 4 modes d'échec que Claude doit tester, et d'exiger ces tests dans votre Definition of Done. Si vous tenez cette discipline, vos déploiements du vendredi deviennent calmes. Si vous la lâchez, vous découvrez vos modes d'échec en plein milieu de la nuit, et chaque incident coûte un cran de confiance que vous ne récupérez pas facilement.",{"type":31,"tag":32,"props":5100,"children":5101},{},[5102],{"type":40,"value":5103},"Si en lisant ces lignes vous reconnaissez votre situation, vous avez deux choix. Vous pouvez attendre le prochain crash 429 nocturne. Ou vous pouvez commencer lundi matin, par 4 tests supplémentaires sur la méthode critique de votre choix, et apprendre à dormir tranquille.",{"type":31,"tag":32,"props":5105,"children":5106},{},[5107,5109,5116],{"type":40,"value":5108},"Pour la suite des patterns de tests anti-fragiles, retrouvez-moi sur ",{"type":31,"tag":64,"props":5110,"children":5113},{"href":5111,"rel":5112},"https://www.instagram.com/kamangacode/",[68],[5114],{"type":40,"value":5115},"mon profil Instagram kamangacode",{"type":40,"value":5117},", où je publie chaque semaine les cas réels rencontrés sur crmcoaching.",{"type":31,"tag":847,"props":5119,"children":5124},{"cta":5120,"href":5121,"title":5122,"type":5123},"Les 100 pratiques que l'IA n'enseigne pas →","https://kamanga.fr/referentiel-craft","Tester les modes d'échec n'est qu'une des 100 pratiques craft","product",[5125],{"type":31,"tag":32,"props":5126,"children":5127},{},[5128],{"type":40,"value":5129},"Exiger les 4 tests de modes d'échec sur du code généré par Claude, c'est une seule pratique parmi celles qui font la différence en prod. Le Craft Bundle réunit les 100 pratiques que j'applique pour coder propre et résilient, celles que l'IA ne vous apprendra jamais parce qu'elle ne les a jamais vues planter à 2h du matin sous un rate limit Brevo.",{"type":31,"tag":48,"props":5131,"children":5132},{},[],{"type":31,"tag":52,"props":5134,"children":5136},{"id":5135},"faq-sur-les-tests-claude-et-la-résilience-prod",[5137],{"type":40,"value":5138},"FAQ sur les tests Claude et la résilience prod",{"type":31,"tag":5140,"props":5141,"children":5142},"details",{},[5143,5149],{"type":31,"tag":5144,"props":5145,"children":5146},"summary",{},[5147],{"type":40,"value":5148},"1. Faut-il écrire ces 4 tests pour chaque fonction du repo ?",{"type":31,"tag":32,"props":5150,"children":5151},{},[5152],{"type":40,"value":5153},"Non, ce serait disproportionné. La règle que j'applique : ces 4 tests sont obligatoires sur toute fonction qui touche à un service externe (réseau, DB, queue, file system). Sur les fonctions pures (calcul, transformation), un test unitaire classique suffit. Le test de criticité, c'est : \"si cette fonction échoue, est-ce qu'un utilisateur ou un système externe en souffre ?\". Si oui, les 4 tests.",{"type":31,"tag":5140,"props":5155,"children":5156},{},[5157,5162],{"type":31,"tag":5144,"props":5158,"children":5159},{},[5160],{"type":40,"value":5161},"2. Comment introduire cette discipline sans bloquer les PR existantes ?",{"type":31,"tag":32,"props":5163,"children":5164},{},[5165],{"type":40,"value":5166},"Je recommande deux phases. Phase 1 (3 mois) : tout nouveau code qui touche à un service externe doit avoir les 4 tests. Pas de rétroactif. Phase 2 (6 mois suivants) : on remonte le backlog, en commençant par les 10 fonctions les plus critiques (celles que vous citeriez en post-mortem). C'est la stratégie Boy Scout Rule appliquée aux tests, comme je le décris dans la Boy Scout Rule du développement clean code : améliorer ce qu'on touche, sans tout réécrire d'un coup.",{"type":31,"tag":5140,"props":5168,"children":5169},{},[5170,5175],{"type":31,"tag":5144,"props":5171,"children":5172},{},[5173],{"type":40,"value":5174},"3. Quelles librairies pour le retry et le timeout en TypeScript ?",{"type":31,"tag":32,"props":5176,"children":5177},{},[5178,5180,5186,5188,5194,5196,5202,5203,5209,5211,5217],{"type":40,"value":5179},"Sur crmcoaching j'utilise ",{"type":31,"tag":88,"props":5181,"children":5183},{"className":5182},[],[5184],{"type":40,"value":5185},"p-retry",{"type":40,"value":5187}," (retry exponentiel avec hook ",{"type":31,"tag":88,"props":5189,"children":5191},{"className":5190},[],[5192],{"type":40,"value":5193},"onFailedAttempt",{"type":40,"value":5195},") et ",{"type":31,"tag":88,"props":5197,"children":5199},{"className":5198},[],[5200],{"type":40,"value":5201},"p-timeout",{"type":40,"value":891},{"type":31,"tag":88,"props":5204,"children":5206},{"className":5205},[],[5207],{"type":40,"value":5208},"AbortSignal",{"type":40,"value":5210}," natif pour le timeout. Les deux sont légères, bien maintenues, et s'intègrent sans friction dans NestJS. Pour le circuit breaker si besoin, ",{"type":31,"tag":88,"props":5212,"children":5214},{"className":5213},[],[5215],{"type":40,"value":5216},"opossum",{"type":40,"value":5218}," est la référence Node.js. Le choix d'outil compte moins que la discipline d'instrumenter : l'important c'est que la stratégie soit explicite et testée, pas qu'elle utilise telle ou telle lib.",{"type":31,"tag":5140,"props":5220,"children":5221},{},[5222,5227],{"type":31,"tag":5144,"props":5223,"children":5224},{},[5225],{"type":40,"value":5226},"4. Quel rapport entre ces tests et la métrique DORA \"MTTR\" ?",{"type":31,"tag":32,"props":5228,"children":5229},{},[5230],{"type":40,"value":5231},"Direct. Le MTTR (Mean Time to Restore) mesure le temps moyen entre la détection d'un incident et sa résolution. Un incident causé par un mode d'échec testé en CI ne devrait jamais arriver en prod (c'est la prévention). Un incident sur un mode d'échec non testé prend en moyenne 6x plus de temps à diagnostiquer, parce qu'on découvre le comportement en live. Tester en amont = MTTR plus court en aval.",{"type":31,"tag":5140,"props":5233,"children":5234},{},[5235,5240],{"type":31,"tag":5144,"props":5236,"children":5237},{},[5238],{"type":40,"value":5239},"5. Comment convaincre un investisseur ou un client sceptique sur le ROI de ces tests ?",{"type":31,"tag":32,"props":5241,"children":5242},{},[5243,5245,5251],{"type":40,"value":5244},"Avec deux chiffres. D'abord, le coût d'un incident rate-limit Brevo comme celui que je décris : journée perdue à déboguer, coachees absents à leurs séances, perte de confiance dans le SaaS. Ensuite, le coût de prévention : 4 tests en plus, 1 heure de dev. Le rapport est sans commune mesure. C'est l'angle business que je détaille dans ",{"type":31,"tag":64,"props":5246,"children":5248},{"href":5247},"/fr/dette-technique/ingenierie-logicielle-avantage-concurrentiel",[5249],{"type":40,"value":5250},"l'ingénierie logicielle comme avantage concurrentiel",{"type":40,"value":446},{"type":31,"tag":5140,"props":5253,"children":5254},{},[5255,5260],{"type":31,"tag":5144,"props":5256,"children":5257},{},[5258],{"type":40,"value":5259},"6. Et si Claude refuse de générer ces tests parce que le code n'est pas \"testable\" ?",{"type":31,"tag":32,"props":5261,"children":5262},{},[5263,5265,5277],{"type":40,"value":5264},"C'est un signal précieux. Si Claude n'arrive pas à écrire un test de concurrence sur votre fonction, c'est probablement que la fonction n'est pas découplée correctement de ses dépendances. C'est l'occasion de re-prompter avec une contrainte d'inversion de dépendance : ",{"type":31,"tag":132,"props":5266,"children":5267},{},[5268,5270,5275],{"type":40,"value":5269},"\"Réécris la classe pour qu'elle injecte ses dépendances via le constructeur NestJS, afin que les 4 tests de modes d'échec deviennent triviaux à écrire avec ",{"type":31,"tag":88,"props":5271,"children":5273},{"className":5272},[],[5274],{"type":40,"value":794},{"type":40,"value":5276},".\"",{"type":40,"value":5278}," L'architecture s'améliore en sortie, exactement comme le défend la dependency inversion pratique.",{"type":31,"tag":48,"props":5280,"children":5281},{},[],{"type":31,"tag":847,"props":5283,"children":5288},{"cta":5284,"href":5285,"title":5286,"type":5287},"Évaluer la maturité de mon équipe →","/mes-ressources","Ressource gratuite : Engineering Maturity Assessment","resource",[5289],{"type":31,"tag":32,"props":5290,"children":5291},{},[5292],{"type":40,"value":5293},"L'EMA est l'outil que je propose au début de chaque mission. Il mesure la maturité de votre équipe sur plusieurs axes engineering : qualité des tests, résilience prod, gouvernance IA, delivery. Quelques minutes pour identifier où votre filet de tests craque sous la concurrence et la latence, et où concentrer vos efforts en priorité.",{"type":31,"tag":5295,"props":5296,"children":5297},"style",{},[5298],{"type":40,"value":5299},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":8,"searchDepth":184,"depth":184,"links":5301},[5302,5303,5304,5310,5311,5312,5313,5314],{"id":54,"depth":184,"text":57},{"id":151,"depth":184,"text":154},{"id":864,"depth":184,"text":867,"children":5305},[5306,5307,5308,5309],{"id":876,"depth":193,"text":879},{"id":1649,"depth":193,"text":1652},{"id":2267,"depth":193,"text":2270},{"id":2823,"depth":193,"text":2826},{"id":3331,"depth":184,"text":3334},{"id":4876,"depth":184,"text":4879},{"id":4954,"depth":184,"text":4957},{"id":5085,"depth":184,"text":5088},{"id":5135,"depth":184,"text":5138},"markdown","content:fr:intelligence-artificielle:code-claude-tests-passent-plante-prod.md","content","fr/intelligence-artificielle/code-claude-tests-passent-plante-prod.md","fr/intelligence-artificielle/code-claude-tests-passent-plante-prod","md",1782669322436]