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