diff --git a/api/scripts/modulix/get-elements-csv.js b/api/scripts/modulix/get-elements-csv.js index 0b78d529af4..59663ff8bf5 100644 --- a/api/scripts/modulix/get-elements-csv.js +++ b/api/scripts/modulix/get-elements-csv.js @@ -32,7 +32,18 @@ if (import.meta.url.startsWith('file:')) { } export function getElements(modules) { - const ELEMENT_TYPES = ['download', 'embed', 'image', 'qcm', 'qcu', 'qrocm', 'separator', 'text', 'video']; + const ELEMENT_TYPES = [ + 'download', + 'embed', + 'flashcards', + 'image', + 'qcm', + 'qcu', + 'qrocm', + 'separator', + 'text', + 'video', + ]; const elements = []; for (const module of modules) { 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/src/devcomp/infrastructure/datasources/learning-content/modules/didacticiel-modulix.json b/api/src/devcomp/infrastructure/datasources/learning-content/modules/didacticiel-modulix.json index 1f416a3c11e..e6ff40a7c47 100644 --- a/api/src/devcomp/infrastructure/datasources/learning-content/modules/didacticiel-modulix.json +++ b/api/src/devcomp/infrastructure/datasources/learning-content/modules/didacticiel-modulix.json @@ -41,7 +41,7 @@ { "id": "f312c33d-e7c9-4a69-9ba0-913957b8f7dd", "type": "discovery", - "title": "Voici une leçon", + "title": "Voici un grain de découverte", "components": [ { "type": "element", diff --git a/api/tests/devcomp/acceptance/scripts/get-elements_test.js b/api/tests/devcomp/acceptance/scripts/get-elements_test.js index 410bb102c78..5d0501e3860 100644 --- a/api/tests/devcomp/acceptance/scripts/get-elements_test.js +++ b/api/tests/devcomp/acceptance/scripts/get-elements_test.js @@ -18,7 +18,9 @@ describe('Acceptance | Script | Get Elements as CSV', function () { expect(elementsListAsJs).to.be.an('array'); expect( elementsListAsJs.every((element) => - ['download', 'embed', 'image', 'qcm', 'qcu', 'qrocm', 'separator', 'text', 'video'].includes(element.type), + ['download', 'embed', 'flashcards', 'image', 'qcm', 'qcu', 'qrocm', 'separator', 'text', 'video'].includes( + element.type, + ), ), ).to.be.true; }); @@ -46,17 +48,18 @@ describe('Acceptance | Script | Get Elements as CSV', function () { expect(elementsListAsCsv).to.be.a('string'); expect(elementsListAsCsv).to .equal(`\ufeff"ElementId"\t"ElementType"\t"ElementPosition"\t"ElementGrainPosition"\t"ElementGrainId"\t"ElementGrainTitle"\t"ElementModuleSlug" -"e9aef60c-f18a-471e-85c7-e50b4731b86b"\t"text"\t1\t1\t"f312c33d-e7c9-4a69-9ba0-913957b8f7dd"\t"Voici une leçon"\t"didacticiel-modulix" -"048e5319-5e81-44cc-ad71-c6c0d3be611f"\t"separator"\t2\t1\t"f312c33d-e7c9-4a69-9ba0-913957b8f7dd"\t"Voici une leçon"\t"didacticiel-modulix" -"8d7687c8-4a02-4d7e-bf6c-693a6d481c78"\t"image"\t3\t1\t"f312c33d-e7c9-4a69-9ba0-913957b8f7dd"\t"Voici une leçon"\t"didacticiel-modulix" -"901ccbaa-f4e6-4322-b863-8e8eab08a33a"\t"download"\t4\t2\t"b14df125-82d5-4d55-a660-7b34cd9ea1ab"\t"Un fichier à télécharger"\t"didacticiel-modulix" -"31106aeb-8346-44a6-8ed4-ebaa2106a373"\t"qcu"\t5\t2\t"b14df125-82d5-4d55-a660-7b34cd9ea1ab"\t"Un fichier à télécharger"\t"didacticiel-modulix" -"3a9f2269-99ba-4631-b6fd-6802c88d5c26"\t"video"\t6\t3\t"73ac3644-7637-4cee-86d4-1a75f53f0b9c"\t"Vidéo de présentation de Pix"\t"didacticiel-modulix" -"71de6394-ff88-4de3-8834-a40057a50ff4"\t"qcu"\t7\t4\t"533c69b8-a836-41be-8ffc-8d4636e31224"\t"Voici un vrai-faux"\t"didacticiel-modulix" -"79dc17f9-142b-4e19-bcbe-bfde4e170d3f"\t"qcu"\t8\t4\t"533c69b8-a836-41be-8ffc-8d4636e31224"\t"Voici un vrai-faux"\t"didacticiel-modulix" -"30701e93-1b4d-4da4-b018-fa756c07d53f"\t"qcm"\t9\t5\t"0be0f5eb-4cb6-47c2-b9d3-cb2ceb4cd21c"\t"Les 3 piliers de Pix"\t"didacticiel-modulix" -"c23436d4-6261-49f1-b50d-13a547529c29"\t"qrocm"\t10\t6\t"4ce2a31a-6584-4dae-87c6-d08b58d0f3b9"\t"Connaissez-vous bien Pix"\t"didacticiel-modulix" -"0e3315fd-98ad-492f-9046-4aa867495d84"\t"embed"\t11\t7\t"46577fb1-aadb-49ba-b3fd-721a11da8eb4"\t"Embed non-auto"\t"didacticiel-modulix"`); +"47823e8f-a4af-44d6-96f7-5b6fc7bc6b51"\t"flashcards"\t1\t1\t"f312c33d-e7c9-4a69-9ba0-913957b8f7dd"\t"Voici une leçon"\t"didacticiel-modulix" +"e9aef60c-f18a-471e-85c7-e50b4731b86b"\t"text"\t2\t1\t"f312c33d-e7c9-4a69-9ba0-913957b8f7dd"\t"Voici une leçon"\t"didacticiel-modulix" +"048e5319-5e81-44cc-ad71-c6c0d3be611f"\t"separator"\t3\t1\t"f312c33d-e7c9-4a69-9ba0-913957b8f7dd"\t"Voici une leçon"\t"didacticiel-modulix" +"8d7687c8-4a02-4d7e-bf6c-693a6d481c78"\t"image"\t4\t1\t"f312c33d-e7c9-4a69-9ba0-913957b8f7dd"\t"Voici une leçon"\t"didacticiel-modulix" +"901ccbaa-f4e6-4322-b863-8e8eab08a33a"\t"download"\t5\t2\t"b14df125-82d5-4d55-a660-7b34cd9ea1ab"\t"Un fichier à télécharger"\t"didacticiel-modulix" +"31106aeb-8346-44a6-8ed4-ebaa2106a373"\t"qcu"\t6\t2\t"b14df125-82d5-4d55-a660-7b34cd9ea1ab"\t"Un fichier à télécharger"\t"didacticiel-modulix" +"3a9f2269-99ba-4631-b6fd-6802c88d5c26"\t"video"\t7\t3\t"73ac3644-7637-4cee-86d4-1a75f53f0b9c"\t"Vidéo de présentation de Pix"\t"didacticiel-modulix" +"71de6394-ff88-4de3-8834-a40057a50ff4"\t"qcu"\t8\t4\t"533c69b8-a836-41be-8ffc-8d4636e31224"\t"Voici un vrai-faux"\t"didacticiel-modulix" +"79dc17f9-142b-4e19-bcbe-bfde4e170d3f"\t"qcu"\t9\t4\t"533c69b8-a836-41be-8ffc-8d4636e31224"\t"Voici un vrai-faux"\t"didacticiel-modulix" +"30701e93-1b4d-4da4-b018-fa756c07d53f"\t"qcm"\t10\t5\t"0be0f5eb-4cb6-47c2-b9d3-cb2ceb4cd21c"\t"Les 3 piliers de Pix"\t"didacticiel-modulix" +"c23436d4-6261-49f1-b50d-13a547529c29"\t"qrocm"\t11\t6\t"4ce2a31a-6584-4dae-87c6-d08b58d0f3b9"\t"Connaissez-vous bien Pix"\t"didacticiel-modulix" +"0e3315fd-98ad-492f-9046-4aa867495d84"\t"embed"\t12\t7\t"46577fb1-aadb-49ba-b3fd-721a11da8eb4"\t"Embed non-auto"\t"didacticiel-modulix"`); }); }); }); 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 23d795190bc..44dd5a80c4b 100644 --- a/api/tests/devcomp/acceptance/scripts/get-modules-csv_test.js +++ b/api/tests/devcomp/acceptance/scripts/get-modules-csv_test.js @@ -338,6 +338,67 @@ describe('Acceptance | Script | Get Modules as CSV', function () { }, ], }, + { + id: '59e051bd-103f-41fa-8358-5028eaa38c57\n', + type: 'activity', + title: 'Des flashcards pour mémoriser', + components: [ + { + type: 'element', + element: { + id: '47823e8f-a4af-44d6-96f7-5b6fc7bc6b51', + type: 'flashcards', + instruction: + '

Lisez la question, essayez de trouver la réponse puis retourner la carte en cliquant dessus.
Cela permet de tester votre mémoire 🎯

', + title: 'Introduction à la poésie', + introImage: { + url: 'https://images.pix.fr/modulix/didacticiel/intro-flashcards.png', + }, + cards: [ + { + id: 'e1de6394-ff88-4de3-8834-a40057a50ff4', + recto: { + image: { + url: 'https://images.pix.fr/modulix/didacticiel/icon.svg', + }, + text: 'Qui a écrit « Le Dormeur du Val ? »', + }, + verso: { + image: { + url: 'https://images.pix.fr/modulix/didacticiel/chaton.jpg', + }, + text: '

Arthur Rimbaud

', + }, + }, + { + id: '48d0cd29-1e08-4b18-b15a-411ab83e5d3c', + recto: { + text: "Comment s'appelait la fille de Victor Hugo, évoquée dans le poème « Demain dès l'aube » ?", + }, + verso: { + text: '

Léopoldine

', + }, + }, + { + id: '2611784c-cf3f-4445-998d-d02fa568da0c', + recto: { + image: { + url: 'https://images.pix.fr/modulix/didacticiel/icon.svg', + }, + text: "Quel animal a des yeux « mêlés de métal et d'agathe » selon Charles Baudelaire ?", + }, + verso: { + image: { + url: 'https://images.pix.fr/modulix/didacticiel/chaton.jpg', + }, + text: '

Le chat

', + }, + }, + ], + }, + }, + ], + }, ], }, ]; @@ -349,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'); + }); + }); +});