From 1a1938d3715347a361d63932c02ce98094a9e5fe Mon Sep 17 00:00:00 2001 From: Yannick Lang Date: Wed, 27 Nov 2024 13:49:03 +0100 Subject: [PATCH 1/6] test(libretranslate-provider): fix missing query handler warning re #470 --- .../libretranslate/lib/__tests__/client.test.js | 10 ++++++++-- .../lib/__tests__/libretranslate.test.js | 13 +++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/providers/libretranslate/lib/__tests__/client.test.js b/providers/libretranslate/lib/__tests__/client.test.js index e2a1b9e4..7b34b92b 100644 --- a/providers/libretranslate/lib/__tests__/client.test.js +++ b/providers/libretranslate/lib/__tests__/client.test.js @@ -69,13 +69,19 @@ describe('libretranslate client', () => { beforeEach(() => { server.use(http.post(`${VALID_URL}/translate`, translateHandler)) server.use(http.get(`${VALID_URL}/languages`, languagesHandler)) - server.use(http.get(`${INVALID_URL}/languages`, () => new HttpResponse())) }) it('sets LocaleInformation default values', () => { - const client = new Client(INVALID_URL) + server.use( + http.get(`${INVALID_URL}/languages`, async () => { + await new Promise((r) => setTimeout(r, 500)) + return new HttpResponse(null, { status: 500 }) + }) + ) + const client = new Client(INVALID_URL) expect(client.localeInformation).toBeDefined() + expect(client.localeInformation.length).toBe(30) }) it('sets LocaleInformation according to server response', async () => { diff --git a/providers/libretranslate/lib/__tests__/libretranslate.test.js b/providers/libretranslate/lib/__tests__/libretranslate.test.js index 6f3f0685..65ac6445 100644 --- a/providers/libretranslate/lib/__tests__/libretranslate.test.js +++ b/providers/libretranslate/lib/__tests__/libretranslate.test.js @@ -82,6 +82,9 @@ describe('libretranslate provider', () => { } beforeAll(() => { server = getServer() + server.use( + http.get(`${BASE_URL}/languages`, () => HttpResponse.json(enabledLocales)) + ) Object.defineProperty(global, 'strapi', { value: require('../../__mocks__/initStrapi')({}), @@ -115,10 +118,12 @@ describe('libretranslate provider', () => { http.post( `${BASE_URL}/translate`, buildTranslateHandler({ maxTexts: 50, maxChars: 10000 }) - ), - http.get(`${BASE_URL}/languages`, async (req, res, ctx) => { - return res(ctx.json(enabledLocales)) - }) + ) + ) + server.use( + http.get(`${BASE_URL}/languages`, async () => + HttpResponse.json(enabledLocales) + ) ) ltProvider = provider.init({ apiUrl: BASE_URL, From c4150cda333f5ce6be34b22e432eb0e3a3a3d0e9 Mon Sep 17 00:00:00 2001 From: Yannick Lang Date: Wed, 27 Nov 2024 18:37:48 +0100 Subject: [PATCH 2/6] test(utils): add test coverage for dummy provider --- .../utils/__tests__/dummy-provider.test.js | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 plugin/server/utils/__tests__/dummy-provider.test.js diff --git a/plugin/server/utils/__tests__/dummy-provider.test.js b/plugin/server/utils/__tests__/dummy-provider.test.js new file mode 100644 index 00000000..5b743696 --- /dev/null +++ b/plugin/server/utils/__tests__/dummy-provider.test.js @@ -0,0 +1,72 @@ +'use strict' + +const { provider, name, init } = require('../dummy-provider') + +describe('Dummy Provider', () => { + it('meta data is correct', () => { + expect(provider).toBe('dummy') + expect(name).toBe('Dummy') + }) + + describe('translation function', () => { + let translate + + beforeAll(() => { + translate = init().translate + }) + + it('throws if targetLocale is not defined', () => { + return expect(async () => + translate({ sourceLocale: 'de', text: 'Lorem Ipsum' }) + ).rejects.toBeTruthy() + }) + + it('throws if sourceLocale is not defined', () => { + return expect(async () => + translate({ targetLocale: 'de', text: 'Lorem Ipsum' }) + ).rejects.toBeTruthy() + }) + + it('returns empty Array if no text is give', async () => { + expect( + await translate({ sourceLocale: 'de', targetLocale: 'en' }) + ).toEqual([]) + }) + + it('return array of input if string is given', async () => { + expect( + await translate({ + sourceLocale: 'de', + targetLocale: 'anything', + text: 'Give me this as an array', + }) + ).toEqual(['Give me this as an array']) + }) + + it('return input if array of strings is given', async () => { + expect( + await translate({ + sourceLocale: 'de', + targetLocale: 'anything', + text: ['Give', 'me', 'this back'], + }) + ).toEqual(['Give', 'me', 'this back']) + }) + }) + + it('usage function is static', async () => { + let { usage, translate } = init() + + const usageResult1 = await usage() + + await translate({ + sourceLocale: 'de', + targetLocale: 'en', + text: 'Some random long text that should increase the usage, but does not, because this is the dummy provider.', + }) + + const usageResult2 = await usage() + + expect(usageResult1).toEqual(usageResult2) + }) +}) From 77bb906054c9277b49c75947542874cf4dcb4383 Mon Sep 17 00:00:00 2001 From: Yannick Lang Date: Thu, 28 Nov 2024 17:10:09 +0100 Subject: [PATCH 3/6] test: add test coverage to untranslated-service --- .../__tests__/untranslated-service.test.js | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 plugin/server/services/__tests__/untranslated-service.test.js diff --git a/plugin/server/services/__tests__/untranslated-service.test.js b/plugin/server/services/__tests__/untranslated-service.test.js new file mode 100644 index 00000000..15e2e30d --- /dev/null +++ b/plugin/server/services/__tests__/untranslated-service.test.js @@ -0,0 +1,119 @@ +'use strict' + +const service = require('../untranslated') + +describe('untranslated service', () => { + describe('getUntranslatedEntity', () => { + it('throws Error if Metadata is not found', () => { + const strapi = { + db: { + metadata: { + get: jest.fn(() => null), + }, + }, + } + + const untranslatedService = service({ strapi }) + + return expect(async () => + untranslatedService.getUntranslatedEntity({ uid: 'uid' }, {}) + ).rejects.toThrow('Content Type does not exist') + }) + + it('throws Error if content table is not localized', () => { + const strapi = { + db: { + metadata: { + get: jest.fn(() => ({ + attributes: { + localizations: {}, + }, + })), + }, + }, + } + + const untranslatedService = service({ strapi }) + + return expect(async () => + untranslatedService.getUntranslatedEntity({ uid: 'uid' }, {}) + ).rejects.toThrow('Content Type not localized') + }) + }) + + describe('getUntranslatedEntityIDs', () => { + it('throws Error if Metadata is not found', () => { + const strapi = { + db: { + metadata: { + get: jest.fn(() => null), + }, + }, + } + + const untranslatedService = service({ strapi }) + + return expect(async () => + untranslatedService.getUntranslatedEntityIDs({ uid: 'uid' }) + ).rejects.toThrow('Content Type does not exist') + }) + + it('throws Error if content table is not localized', () => { + const strapi = { + db: { + metadata: { + get: jest.fn(() => ({ + attributes: { + localizations: {}, + }, + })), + }, + }, + } + + const untranslatedService = service({ strapi }) + + return expect(async () => + untranslatedService.getUntranslatedEntityIDs({ uid: 'uid' }) + ).rejects.toThrow('Content Type not localized') + }) + }) + + describe('isFullyTranslated', () => { + it('throws Error if Metadata is not found', () => { + const strapi = { + db: { + metadata: { + get: jest.fn(() => null), + }, + }, + } + + const untranslatedService = service({ strapi }) + + return expect(async () => + untranslatedService.isFullyTranslated('uid', {}) + ).rejects.toThrow('Content Type does not exist') + }) + + it('throws Error if content table is not localized', () => { + const strapi = { + db: { + metadata: { + get: jest.fn(() => ({ + attributes: { + localizations: {}, + }, + })), + }, + }, + } + + const untranslatedService = service({ strapi }) + + return expect(async () => + untranslatedService.isFullyTranslated('uid', {}) + ).rejects.toThrow('Content Type not localized') + }) + }) +}) From 61620496361a8e6b4a414be6ec25f6df40fe4070 Mon Sep 17 00:00:00 2001 From: Yannick Lang Date: Thu, 28 Nov 2024 17:10:44 +0100 Subject: [PATCH 4/6] test(batch-translation): add test coverage to BatchTranslateJob --- plugin/__mocks__/initSetup.js | 12 +- .../__tests__/BatchTranslateJob.test.js | 154 ++++++++++++++++++ 2 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 plugin/server/services/batch-translate/__tests__/BatchTranslateJob.test.js diff --git a/plugin/__mocks__/initSetup.js b/plugin/__mocks__/initSetup.js index 0511d94b..a54f3d20 100644 --- a/plugin/__mocks__/initSetup.js +++ b/plugin/__mocks__/initSetup.js @@ -103,12 +103,12 @@ module.exports = ({ 'batch-translate-job': () => { const uid = 'plugin::translate.batch-translate-job' return { - findOne: this.db.query(uid).findOne, - find: this.db.query(uid).findMany, - count: this.db.query(uid).count, - create: this.db.query(uid).create, - update: this.db.query(uid).update, - delete: this.db.query(uid).delete, + findOne: mock.db.query(uid).findOne, + find: mock.db.query(uid).findMany, + count: mock.db.query(uid).count, + create: mock.db.query(uid).create, + update: mock.db.query(uid).update, + delete: mock.db.query(uid).delete, } }, }, diff --git a/plugin/server/services/batch-translate/__tests__/BatchTranslateJob.test.js b/plugin/server/services/batch-translate/__tests__/BatchTranslateJob.test.js new file mode 100644 index 00000000..5f452076 --- /dev/null +++ b/plugin/server/services/batch-translate/__tests__/BatchTranslateJob.test.js @@ -0,0 +1,154 @@ +'use strict' + +const { BatchTranslateJob } = require('../BatchTranslateJob') + +describe('BatchTranslateJob', () => { + beforeEach(() => { + jest.clearAllMocks() + Object.defineProperty(global, 'strapi', { + value: require('../../../../__mocks__/initSetup')({ + contentTypes: { + nonTranslatedContentType: { + pluginOptions: { i18n: { localized: false } }, + }, + translatedContentType: { + pluginOptions: { i18n: { localized: true } }, + }, + }, + }), + writable: true, + }) + }) + + it("constructor throws if content type isn't localized", () => { + expect(() => { + new BatchTranslateJob({ + id: 'id', + contentType: 'nonTranslatedContentType', + sourceLocale: 'sourceLocale', + targetLocale: 'targetLocale', + entityIds: ['entityIds'], + status: 'status', + autoPublish: false, + }) + }).toThrow('translate.batch-translate.content-type-not-localized') + }) + + it('constructor does not throw if content type is localized', () => { + expect(() => { + new BatchTranslateJob({ + id: 'id', + contentType: 'translatedContentType', + sourceLocale: 'sourceLocale', + targetLocale: 'targetLocale', + entityIds: ['entityIds'], + status: 'status', + autoPublish: false, + }) + }).not.toThrow() + }) + + describe('start', () => { + it('throws for status !== "created"', async () => { + const job = new BatchTranslateJob({ + id: 'id', + contentType: 'translatedContentType', + sourceLocale: 'sourceLocale', + targetLocale: 'targetLocale', + entityIds: ['entityIds'], + status: 'status', + autoPublish: false, + }) + + expect(async () => job.start()).rejects.toThrow() + }) + + it('does not throw for status === "created"', async () => { + const job = new BatchTranslateJob({ + id: 'id', + contentType: 'translatedContentType', + sourceLocale: 'sourceLocale', + targetLocale: 'targetLocale', + entityIds: ['entityIds'], + status: 'created', + autoPublish: false, + }) + + expect(job.start()).resolves.not.toThrow() + }) + }) + + describe('status updates', () => { + let job + + beforeEach(() => { + job = new BatchTranslateJob({ + id: 'id', + contentType: 'translatedContentType', + sourceLocale: 'sourceLocale', + targetLocale: 'targetLocale', + entityIds: ['entityIds'], + status: 'created', + autoPublish: false, + }) + }) + + it("cancel updates the status to 'cancelled' if it is running", async () => { + const f = jest.fn() + BatchTranslateJob.prototype.updateStatus = f + + await job.cancel() + + expect(f).toHaveBeenCalledWith('cancelled') + }) + + it('cancel does nothing if job is not running', async () => { + const f = jest.fn() + BatchTranslateJob.prototype.updateStatus = f + + job.status = 'finished' + await job.cancel() + + expect(f).not.toHaveBeenCalled() + }) + + it("pause updates the status to 'paused' if it is running", async () => { + const f = jest.fn() + BatchTranslateJob.prototype.updateStatus = f + + await job.pause() + + expect(f).toHaveBeenCalledWith('paused') + }) + + it('pause does nothing if job is not running', async () => { + const f = jest.fn() + BatchTranslateJob.prototype.updateStatus = f + + job.status = 'finished' + + await job.pause() + + expect(f).not.toHaveBeenCalled() + }) + + it('setup changes the status to setup and then running', async () => { + const f = jest.fn((status) => (job.status = status)) + BatchTranslateJob.prototype.updateStatus = f + + await job.setup() + + expect(f).toHaveBeenCalledWith('setup') + expect(f).toHaveBeenCalledWith('running') + }) + + it('start changes the status to finished after successful termination', async () => { + const f = jest.fn((status) => (job.status = status)) + BatchTranslateJob.prototype.updateStatus = f + + await job.start() + + expect(f).toHaveBeenCalledWith('finished') + }) + }) +}) From dd03122da2e3e1447b133734c7eb99b7779f6160 Mon Sep 17 00:00:00 2001 From: Yannick Lang Date: Thu, 28 Nov 2024 17:53:15 +0100 Subject: [PATCH 5/6] test(libretranslate-provider): prevent logging after test completion --- providers/libretranslate/lib/__tests__/client.test.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/providers/libretranslate/lib/__tests__/client.test.js b/providers/libretranslate/lib/__tests__/client.test.js index 7b34b92b..29a28bef 100644 --- a/providers/libretranslate/lib/__tests__/client.test.js +++ b/providers/libretranslate/lib/__tests__/client.test.js @@ -71,10 +71,10 @@ describe('libretranslate client', () => { server.use(http.get(`${VALID_URL}/languages`, languagesHandler)) }) - it('sets LocaleInformation default values', () => { + it('sets LocaleInformation default values', async () => { server.use( http.get(`${INVALID_URL}/languages`, async () => { - await new Promise((r) => setTimeout(r, 500)) + await new Promise((r) => setTimeout(r, 200)) return new HttpResponse(null, { status: 500 }) }) @@ -82,6 +82,9 @@ describe('libretranslate client', () => { const client = new Client(INVALID_URL) expect(client.localeInformation).toBeDefined() expect(client.localeInformation.length).toBe(30) + + // wait until sever response is resolved, prevents logging after test completion + await new Promise((r) => setTimeout(r, 200)) }) it('sets LocaleInformation according to server response', async () => { From 199cac0e02ac2b66bea4007a4967925f2a9bcc42 Mon Sep 17 00:00:00 2001 From: Felix Haase Date: Thu, 28 Nov 2024 21:15:34 +0100 Subject: [PATCH 6/6] ci(unittests): update codecov action --- .github/workflows/unittest.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index eccffaad..1f5ffcec 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -14,9 +14,10 @@ jobs: cache: 'yarn' - run: yarn - run: yarn test - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v5 with: - token: ${{ secrets.CODECOV_TOKEN }} files: ./plugin/coverage/clover.xml,./providers/deepl/coverage/clover.xml,./providers/libretranslate/coverage/clover.xml flags: unittests name: codecov-umbrella + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}