From 36917d79b4caa220a44a12410bd5063e574d4bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20FAMIBELLE-PRONZOLA?= Date: Sat, 4 Jul 2026 09:47:26 +0400 Subject: [PATCH] =?UTF-8?q?fix:=20ajouter=20un=20timeout=20DeepL=20et=20is?= =?UTF-8?q?oler=20les=20=C3=A9checs=20par=20langue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../parole/services/__tests__/parole.test.js | 60 +++++++++++++++++++ src/api/parole/services/parole.js | 11 +++- 2 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/api/parole/services/__tests__/parole.test.js diff --git a/src/api/parole/services/__tests__/parole.test.js b/src/api/parole/services/__tests__/parole.test.js new file mode 100644 index 0000000..6127ac2 --- /dev/null +++ b/src/api/parole/services/__tests__/parole.test.js @@ -0,0 +1,60 @@ +import {describe, it, expect, vi, afterEach} from 'vitest' + +const {default: createService} = await import('../parole.js') + +function fakeDeeplResponse(text) { + return { + ok: true, + json: async () => ({translations: [{text}]}) + } +} + +describe('Translator (DeepL)', () => { + const originalFetch = global.fetch + + afterEach(() => { + global.fetch = originalFetch + vi.restoreAllMocks() + }) + + it('attache un timeout à la requête DeepL', async () => { + global.fetch = vi.fn(async () => fakeDeeplResponse('hello')) + + const strapi = {contentType: vi.fn(() => ({uid: 'api::parole.parole', kind: 'collectionType'}))} + const service = createService({strapi}) + await service.translate('FR', 'EN', 'bonjour') + + const [, options] = global.fetch.mock.calls[0] + expect(options.signal).toBeInstanceOf(AbortSignal) + }) +}) + +describe('translateLyrics', () => { + const originalFetch = global.fetch + + afterEach(() => { + global.fetch = originalFetch + vi.restoreAllMocks() + }) + + it('continue les autres langues quand une traduction DeepL échoue', async () => { + global.fetch = vi.fn(async (_url, options) => { + const {target_lang: target} = JSON.parse(options.body) + if (target === 'ES') { + return {ok: false, status: 500, text: async () => 'boom'} + } + + return fakeDeeplResponse(`traduit-${target}`) + }) + + const strapi = { + contentType: vi.fn(() => ({uid: 'api::parole.parole', kind: 'collectionType'})), + log: {error: vi.fn()} + } + const service = createService({strapi}) + const result = await service.translateLyrics('Bonjour le monde') + + expect(result.anglais).toContain('traduit-EN') + expect(result.espagnol).toBeUndefined() + }) +}) diff --git a/src/api/parole/services/parole.js b/src/api/parole/services/parole.js index bc78202..536b9e4 100644 --- a/src/api/parole/services/parole.js +++ b/src/api/parole/services/parole.js @@ -64,7 +64,8 @@ class Translator { text: Array.isArray(text) ? text : [text], source_lang: origin, target_lang: target, - }) + }), + signal: AbortSignal.timeout(15_000) }) if (!response.ok) { @@ -90,8 +91,12 @@ module.exports = createCoreService('api::parole.parole', ({strapi}) => ({ for (const lang of ALL_LANGS) { if (lang === 'fr') continue const { field, deeplTarget, suffix } = LANG_MAP[lang] - const translated = await this.translate('FR', deeplTarget, parolesFR) - result[field] = translated + suffix + try { + const translated = await this.translate('FR', deeplTarget, parolesFR) + result[field] = translated + suffix + } catch (err) { + strapi.log.error(`DeepL (${deeplTarget}): ${err.message}`) + } } return result