diff --git a/api/scripts/modulix/get-modules-csv.js b/api/scripts/modulix/get-modules-csv.js index 5ffef15661a..05e39b0575a 100644 --- a/api/scripts/modulix/get-modules-csv.js +++ b/api/scripts/modulix/get-modules-csv.js @@ -11,7 +11,7 @@ export async function getModulesListAsCsv(modules) { { label: 'Module', value: 'slug' }, { label: 'ModuleTotalElements', - value: (row) => row.grains.map((grain) => grain.components.length).reduce((partialSum, a) => partialSum + a, 0), + value: (row) => _getTotalElementsCount(row.grains), }, { label: 'ModuleLink', value: (row) => `https://app.recette.pix.fr/modules/${row.slug}` }, { label: 'ModuleLevel', value: 'details.level' }, @@ -45,6 +45,28 @@ export async function getModulesListAsCsv(modules) { }); } +export function _getTotalElementsCount(grains) { + let totalElements = 0; + for (const grain of grains) { + for (const component of grain.components) { + switch (component.type) { + case 'element': + totalElements += 1; + break; + case 'stepper': + for (const step of component.steps) { + totalElements += step.elements.length; + } + break; + default: + throw new Error(`Component type "${component.type}" is not available`); + } + } + } + + return totalElements; +} + // Only run the following if the file is called directly if (import.meta.url.startsWith('file:')) { const modulePath = fileURLToPath(import.meta.url); diff --git a/api/tests/devcomp/acceptance/scripts/get-modules-csv_test.js b/api/tests/devcomp/acceptance/scripts/get-modules-csv_test.js index cb3013a2a53..44dd5a80c4b 100644 --- a/api/tests/devcomp/acceptance/scripts/get-modules-csv_test.js +++ b/api/tests/devcomp/acceptance/scripts/get-modules-csv_test.js @@ -410,6 +410,6 @@ describe('Acceptance | Script | Get Modules as CSV', function () { expect(modulesListAsCsv).to.be.a('string'); expect(modulesListAsCsv).to .equal(`\ufeff"Module"\t"ModuleTotalElements"\t"ModuleLink"\t"ModuleLevel"\t"ModuleTotalGrains"\t"ModuleTotalLessons"\t"ModuleTotalActivities"\t"ModuleTotalChallenges"\t"ModuleTotalDiscoveries"\t"ModuleTotalSummaries"\t"ModuleDuration"\t"ModuleIsBeta" -"didacticiel-modulix"\t11\t"https://app.recette.pix.fr/modules/didacticiel-modulix"\t"Débutant"\t8\t1\t4\t1\t1\t1\t"=TEXT(5/24/60; ""mm:ss"")"\t"=TRUE"`); +"didacticiel-modulix"\t13\t"https://app.recette.pix.fr/modules/didacticiel-modulix"\t"Débutant"\t9\t1\t5\t1\t1\t1\t"=TEXT(5/24/60; ""mm:ss"")"\t"=TRUE"`); }); }); diff --git a/api/tests/devcomp/unit/scripts/get-modules-csv_test.js b/api/tests/devcomp/unit/scripts/get-modules-csv_test.js new file mode 100644 index 00000000000..827953a1759 --- /dev/null +++ b/api/tests/devcomp/unit/scripts/get-modules-csv_test.js @@ -0,0 +1,147 @@ +import { _getTotalElementsCount } from '../../../../scripts/modulix/get-modules-csv.js'; +import { catchErrSync, expect } from '../../../test-helper.js'; + +describe('Unit | Scripts | Get Modules as CSV', function () { + describe('#getTotalElements', function () { + it('should count elements inside component "element"', function () { + // given + const grains = [ + { + components: [ + { + type: 'element', + element: { + id: '84726001-1665-457d-8f13-4a74dc4768ea', + type: 'text', + content: + '

On commence avec les leçons.
Les leçons sont des textes, des images ou des vidéos. Les leçons sont là pour vous expliquer des concepts ou des méthodes.

', + }, + }, + { + type: 'element', + element: { + id: 'a2372bf4-86a4-4ecc-a188-b51f4f98bca2', + type: 'text', + content: + '

Voici un texte de leçon. Parfois, il y a des émojis pour aider à la lecture .
Et là, voici une image !

', + }, + }, + { + type: 'element', + element: { + id: '8d7687c8-4a02-4d7e-bf6c-693a6d481c78', + type: 'image', + url: 'https://images.pix.fr/modulix/didacticiel/ordi-spatial.svg', + alt: "Dessin détaillé dans l'alternative textuelle", + alternativeText: "Dessin d'un ordinateur dans un univers spatial.", + }, + }, + ], + }, + ]; + + // when + const result = _getTotalElementsCount(grains); + + //then + expect(result).to.equal(3); + }); + + it('should count elements inside stepper', function () { + // given + const grains = [ + { + components: [ + { + type: 'stepper', + steps: [ + { + elements: [ + { + id: '342183f7-af51-4e4e-ab4c-ebed1e195063', + type: 'text', + content: '

À la fin de cette vidéo, une question sera posée sur les compétences Pix.

', + }, + ], + }, + { + elements: [ + { + id: '342183f7-af51-4e4e-ab4c-ebed1e195063', + type: 'text', + content: '

À la fin de cette vidéo, une question sera posée sur les compétences Pix.

', + }, + ], + }, + ], + }, + ], + }, + ]; + + // when + const result = _getTotalElementsCount(grains); + + //then + expect(result).to.equal(2); + }); + + it('should not filter non existing element type', function () { + // given + const grains = [ + { + components: [ + { + type: 'stepper', + steps: [ + { + elements: [ + { + type: 'non-existing-element-type', + }, + ], + }, + ], + }, + ], + }, + { + components: [ + { + type: 'element', + element: { + type: 'non-existing-element-type', + }, + }, + ], + }, + ]; + + // when + const result = _getTotalElementsCount(grains); + + // then + expect(result).to.equal(2); + }); + + it('should throw if component type is not available', function () { + // given + const grains = [ + { + components: [ + { + type: 'non-existing-component-type', + }, + ], + }, + ]; + + // when + const err = catchErrSync(_getTotalElementsCount)(grains); + + // then + expect(err).to.be.an.instanceOf(Error); + expect(err.message).to.equal('Component type "non-existing-component-type" is not available'); + }); + }); +});