// Rôle : vérifie les invariants statiques des toolboxes et de leurs outils. import { readFile } from "node:fs/promises"; import { test } from "node:test"; import assert from "node:assert/strict"; test("toolbox storage, cards and pages are wired", async () => { const source = await readFile("website/src/main.jsx", "utf8"); const toolboxCard = await readFile("website/src/features/toolboxes/ToolboxCard.jsx", "utf8"); const toolboxPages = await readFile("website/src/features/toolboxes/ToolboxPages.jsx", "utf8"); const toolboxActions = await readFile("website/src/features/toolboxes/useToolboxActions.js", "utf8"); const toolboxStorage = await readFile("website/src/features/toolboxes/storage/toolboxStorage.js", "utf8"); const indexedToolboxesHook = await readFile("website/src/features/toolboxes/storage/useIndexedToolboxes.js", "utf8"); const storageQuota = await readFile("website/src/components/StorageQuota.jsx", "utf8"); const importButton = await readFile("website/src/components/ImportButton.jsx", "utf8"); const reorderHook = await readFile("website/src/hooks/usePointerReorder.js", "utf8"); const groupedReorderHook = await readFile("website/src/hooks/useGroupedReorder.js", "utf8"); const inlineEditHook = await readFile("website/src/hooks/useInlineEdit.js", "utf8"); const draftFormHook = await readFile("website/src/hooks/useDraftForm.js", "utf8"); assert.match(`${indexedToolboxesHook}\n${toolboxPages}`, /indexedDbStorage\.js/); assert.match(source, /features\/toolboxes\/storage\/useIndexedToolboxes\.js/); assert.match(source, /features\/toolboxes\/useToolboxActions\.js/); assert.match(indexedToolboxesHook, /export function useIndexedToolboxes/); assert.match(indexedToolboxesHook, /getStorageEstimate/); assert.match(toolboxActions, /export function useToolboxActions/); assert.match(toolboxActions, /importAllToolboxesPayload/); assert.match(toolboxActions, /async function addImageFiles/); assert.match(`${source}\n${toolboxActions}`, /features\/toolboxes\/storage\/toolboxStorage\.js/); assert.match(toolboxStorage, /TOOLBOX_ICON_FILES/); assert.match(toolboxStorage, /export function normalizeToolboxIcon/); assert.match(toolboxStorage, /export function createGlobalExportPayload/); assert.match(toolboxStorage, /qtyTarget/); assert.match(toolboxStorage, /qtyCurrent/); assert.match(toolboxStorage, /hideCompletedSections/); assert.match(toolboxStorage, /hideCompletedSectionsFully/); assert.match(toolboxStorage, /hideWhenComplete/); assert.match(toolboxStorage, /collapsed/); assert.match(toolboxStorage, /module\.scrollable/); assert.match(toolboxStorage, /export function normalizeLinksData/); assert.match(toolboxStorage, /export function normalizeCountersData/); assert.match(toolboxStorage, /export function normalizeCombosData/); assert.match(toolboxStorage, /export function normalizeCalculatorData/); assert.match(toolboxStorage, /export function normalizeTableData/); assert.match(toolboxStorage, /export function normalizeTimerData/); assert.match(toolboxStorage, /export function normalizeTaskPlannerData/); assert.match(toolboxStorage, /export function normalizeEquipmentPlannerData/); assert.match(toolboxStorage, /export function summarizeEquipmentPlannerData/); assert.match(toolboxStorage, /export function normalizeImageAnnotationData/); assert.match(toolboxStorage, /export function compactModuleDataForStorage\(type, value\)/); assert.match(toolboxStorage, /scrollResults/); assert.match(toolboxCard, /DEFAULT_TOOLBOX_ICON/); assert.match(toolboxCard, /export function ToolboxCard/); assert.match(toolboxCard, /export function ToolboxIconPicker/); assert.match(toolboxCard, /export function ToolboxGameIcon/); assert.match(toolboxCard, /toolbox-card-drag-handle/); assert.match(toolboxCard, /reorder\.getItemProps/); assert.match(toolboxCard, /toolbox-card-cover-link/); assert.match(toolboxCard, /toolbox-icon-cover/); assert.match(toolboxPages, /\.\/ToolboxCard\.jsx/); assert.match(toolboxPages, /updateToolboxOrder/); assert.match(toolboxPages, /useGroupedReorder/); assert.match(toolboxPages, /useInlineEdit/); assert.match(toolboxPages, /getContentEditableProps/); assert.match(toolboxPages, /orientation: "horizontal"/); assert.match(toolboxPages, /components\/StorageQuota\.jsx/); assert.match(toolboxPages, /components\/ImportButton\.jsx/); assert.match(toolboxPages, /import-icon-button/); assert.match(toolboxPages, /getToolboxGame\(toolbox\)/); assert.match(toolboxPages, /Vers la page de jeu/); assert.match(toolboxPages, /Vers la toolbox complète/); assert.match(toolboxPages, /#\/games\/\$\{toolboxGame\.id\}/); assert.match(toolboxPages, /#\/toolbox\/\$\{toolbox\.id\}/); assert.match(toolboxPages, /setDrawerGameId\(""\)/); assert.match(toolboxPages, /moduleColumns/); assert.match(toolboxPages, /normalizeCombosData/); assert.match(toolboxPages, /function ToolboxView/); assert.doesNotMatch(toolboxPages, /usePointerReorder/); assert.match(storageQuota, /export function StorageQuota/); assert.match(storageQuota, /role="progressbar"/); assert.match(importButton, /export function ImportButton/); assert.match(importButton, /accept="application\/json"/); assert.match(reorderHook, /export function usePointerReorder/); assert.match(reorderHook, /setPointerCapture/); assert.match(reorderHook, /elementsFromPoint/); assert.match(reorderHook, /elementFromPoint/); assert.match(groupedReorderHook, /export function useGroupedReorder/); assert.match(groupedReorderHook, /usePointerReorder/); assert.match(groupedReorderHook, /export function getGroupedEntries/); assert.match(groupedReorderHook, /export function applyGroupedReorderOperation/); assert.match(groupedReorderHook, /data-reorder-orientation/); assert.match(groupedReorderHook, /operation\.sourceParentId === operation\.targetParentId/); assert.match(inlineEditHook, /export function useInlineEdit/); assert.match(inlineEditHook, /skipCommitRef/); assert.match(inlineEditHook, /blurOnEscape/); assert.match(inlineEditHook, /commitOnEnter/); assert.match(inlineEditHook, /getContentEditableProps/); assert.match(draftFormHook, /export function useDraftForm/); assert.match(draftFormHook, /getFieldProps/); assert.match(draftFormHook, /handleSubmit/); assert.match(draftFormHook, /preventDefault/); }); test("toolbox module registry and modules expose expected behavior", async () => { const source = await readFile("website/src/main.jsx", "utf8"); const moduleRegistry = await readFile("website/src/features/toolboxes/modules/index.jsx", "utf8"); const notepadModule = await readFile("website/src/features/toolboxes/modules/NotepadModule.jsx", "utf8"); const combosModule = await readFile("website/src/features/toolboxes/modules/CombosModule.jsx", "utf8"); const calculatorModule = await readFile("website/src/features/toolboxes/modules/CalculatorModule.jsx", "utf8"); const tableModule = await readFile("website/src/features/toolboxes/modules/TableModule.jsx", "utf8"); const tableFormulaEngine = await readFile("website/src/features/toolboxes/modules/tableFormulaEngine.js", "utf8"); const timerModule = await readFile("website/src/features/toolboxes/modules/TimerModule.jsx", "utf8"); const taskPlannerModule = await readFile("website/src/features/toolboxes/modules/TaskPlannerModule.jsx", "utf8"); const equipmentPlannerModule = await readFile("website/src/features/toolboxes/modules/EquipmentPlannerModule.jsx", "utf8"); const checklistModule = await readFile("website/src/features/toolboxes/modules/ChecklistModule.jsx", "utf8"); const imagesModule = await readFile("website/src/features/toolboxes/modules/ImagesModule.jsx", "utf8"); const imageAnnotationModule = await readFile("website/src/features/toolboxes/modules/ImageAnnotationModule.jsx", "utf8"); const linksModule = await readFile("website/src/features/toolboxes/modules/LinksModule.jsx", "utf8"); const textImportModal = await readFile("website/src/features/toolboxes/modules/TextImportModal.jsx", "utf8"); const textExchangeActions = await readFile("website/src/features/toolboxes/modules/TextExchangeActions.jsx", "utf8"); const textExchangeHook = await readFile("website/src/features/toolboxes/modules/useTextExchange.js", "utf8"); const countersModule = await readFile("website/src/features/toolboxes/modules/CountersModule.jsx", "utf8"); const textImport = await readFile("website/src/features/toolboxes/modules/textImport.js", "utf8"); const imageViewer = await readFile("website/src/components/ImageViewer.jsx", "utf8"); assert.match(moduleRegistry, /export const TOOLBOX_MODULES/); assert.match(moduleRegistry, /export function AddToolControls/); assert.match(moduleRegistry, /export function ToolboxModules/); assert.match(moduleRegistry, /MODULE_COMPONENTS/); assert.match(moduleRegistry, /notepad:/); assert.match(moduleRegistry, /checklist:/); assert.match(moduleRegistry, /images:/); assert.match(moduleRegistry, /links:/); assert.match(moduleRegistry, /counters:/); assert.match(moduleRegistry, /combos:/); assert.match(moduleRegistry, /CombosModule/); assert.match(moduleRegistry, /calculator:/); assert.match(moduleRegistry, /table:/); assert.match(moduleRegistry, /table: \{ label: "Tableau", icon: "table", Component: TableModule, editable: true, scrollable: true \}/); assert.match(moduleRegistry, /timer:/); assert.match(moduleRegistry, /taskPlanner:/); assert.match(moduleRegistry, /equipmentPlanner:/); assert.match(moduleRegistry, /Planificateur d'équipements/); assert.match(moduleRegistry, /imageAnnotation:/); assert.match(moduleRegistry, /Annotation d'images/); assert.match(moduleRegistry, /editable: false/); assert.match(moduleRegistry, /module-edit-button/); assert.match(moduleRegistry, /itemReorder\.startDrag/); assert.match(moduleRegistry, /onPointerDown/); assert.match(moduleRegistry, /useGroupedReorder/); assert.match(moduleRegistry, /useInlineEdit/); assert.match(moduleRegistry, /getContentEditableProps/); assert.match(moduleRegistry, /tool-add-card/); assert.match(moduleRegistry, /tool-quick-add-button/); assert.match(moduleRegistry, /tool-add-quick-toggle/); assert.match(moduleRegistry, /scrollable: true/); assert.match(moduleRegistry, /module-content/); assert.match(moduleRegistry, /module-scroll-button/); assert.match(moduleRegistry, /Icon name="dropdown"/); assert.match(moduleRegistry, /CompactDropdown/); assert.doesNotMatch(source, /