361 lines
19 KiB
JavaScript
361 lines
19 KiB
JavaScript
// Rôle : vérifie les conventions statiques des styles Sass.
|
|
import { readFile } from "node:fs/promises";
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
async function readJoinedStyles(paths) {
|
|
return (await Promise.all(paths.map((path) => readFile(path, "utf8")))).join("\n");
|
|
}
|
|
|
|
function countLines(source) {
|
|
return source.trimEnd().split("\n").length;
|
|
}
|
|
|
|
test("style entrypoint and theme layers are wired", async () => {
|
|
const styles = await readFile("website/src/styles/main.scss", "utf8");
|
|
const styleNebula = await readFile("website/src/styles/_nebula.scss", "utf8");
|
|
const styleTokens = await readFile("website/src/styles/_tokens.scss", "utf8");
|
|
const styleBase = await readFile("website/src/styles/_base.scss", "utf8");
|
|
const styleMixins = await readFile("website/src/styles/_mixins.scss", "utf8");
|
|
const styleShell = await readFile("website/src/styles/_shell.scss", "utf8");
|
|
const styleCards = await readFile("website/src/styles/_cards.scss", "utf8");
|
|
const styleSurfaces = await readFile("website/src/styles/design-system/_surfaces.scss", "utf8");
|
|
const styleControls = await readFile("website/src/styles/design-system/_controls.scss", "utf8");
|
|
const styleAttributes = await readFile("website/src/styles/design-system/_attributes.scss", "utf8");
|
|
const styleControlsPatterns = await readFile("website/src/styles/design-system/controls/_patterns.scss", "utf8");
|
|
const styleAttributesPatterns = await readFile("website/src/styles/design-system/attributes/_patterns.scss", "utf8");
|
|
const styleControlsButtons = await readFile("website/src/styles/design-system/controls/_buttons.scss", "utf8");
|
|
const styleAttributesButtons = await readFile("website/src/styles/design-system/attributes/_buttons.scss", "utf8");
|
|
const goalTreeBranch = await readFile("website/src/features/toolboxes/modules/GoalTreeBranch.jsx", "utf8");
|
|
const ndsPatternConsumers = await readJoinedStyles([
|
|
"website/src/pages/HomePage.jsx",
|
|
"website/src/pages/LibraryPage.jsx",
|
|
"website/src/pages/AboutPage.jsx",
|
|
"website/src/features/games/GamesPage.jsx",
|
|
"website/src/features/games/GameFiltersPanel.jsx",
|
|
"website/src/features/games/diablo4/Diablo4AffixCard.jsx",
|
|
"website/src/features/toolboxes/ToolboxCard.jsx",
|
|
"website/src/features/toolboxes/ToolboxPages.jsx",
|
|
"website/src/components/AppOverlays.jsx",
|
|
"website/src/components/StorageQuota.jsx",
|
|
"website/src/components/ToolboxModals.jsx",
|
|
"website/src/features/toolboxes/modules/AddToolControls.jsx",
|
|
"website/src/features/toolboxes/modules/TextImportModal.jsx"
|
|
]);
|
|
const styleHome = await readJoinedStyles([
|
|
"website/src/styles/_home.scss",
|
|
"website/src/styles/home/_shared.scss",
|
|
"website/src/styles/home/_onboarding.scss",
|
|
"website/src/styles/home/_library.scss",
|
|
"website/src/styles/home/library/_page.scss",
|
|
"website/src/styles/home/library/_summary.scss",
|
|
"website/src/styles/home/library/_toc.scss",
|
|
"website/src/styles/home/library/_tool-cards.scss",
|
|
"website/src/styles/home/library/_examples.scss",
|
|
"website/src/styles/home/library/_previews.scss",
|
|
"website/src/styles/home/_story.scss",
|
|
"website/src/styles/home/_about.scss",
|
|
"website/src/styles/home/about/_page.scss",
|
|
"website/src/styles/home/about/_story.scss",
|
|
"website/src/styles/home/about/_contribute.scss",
|
|
"website/src/styles/home/about/_tools.scss",
|
|
"website/src/styles/home/about/_reminders.scss",
|
|
"website/src/styles/home/_stats.scss"
|
|
]);
|
|
const styleToolboxesEntry = await readFile("website/src/styles/_toolboxes.scss", "utf8");
|
|
const styleToolboxesCore = await readFile("website/src/styles/toolboxes/_core.scss", "utf8");
|
|
const styleToolboxLayout = await readJoinedStyles([
|
|
"website/src/styles/toolboxes/_layout.scss",
|
|
"website/src/styles/toolboxes/layout/_header.scss",
|
|
"website/src/styles/toolboxes/layout/_icon-picker.scss",
|
|
"website/src/styles/toolboxes/layout/_cover-editor.scss",
|
|
"website/src/styles/toolboxes/layout/_tutorial.scss",
|
|
"website/src/styles/toolboxes/layout/_add-tools.scss",
|
|
"website/src/styles/toolboxes/layout/_preferences.scss",
|
|
"website/src/styles/toolboxes/layout/_modules.scss"
|
|
]);
|
|
const styleToolboxShell = await readFile("website/src/styles/toolboxes/_module-shell.scss", "utf8");
|
|
const styleToolboxTextExchange = await readFile("website/src/styles/toolboxes/_text-exchange.scss", "utf8");
|
|
const styleToolboxNotepad = await readFile("website/src/styles/toolboxes/_notepad.scss", "utf8");
|
|
const styleToolboxChecklist = await readFile("website/src/styles/toolboxes/_checklist.scss", "utf8");
|
|
const styleToolboxCalculator = await readFile("website/src/styles/toolboxes/_calculator.scss", "utf8");
|
|
const styleToolboxCalculatorResults = await readFile("website/src/styles/toolboxes/_calculator-results.scss", "utf8");
|
|
const styleToolboxTable = await readFile("website/src/styles/toolboxes/_table.scss", "utf8");
|
|
const styleToolboxCombos = await readJoinedStyles([
|
|
"website/src/styles/toolboxes/_combos.scss",
|
|
"website/src/styles/toolboxes/combos/_editor.scss",
|
|
"website/src/styles/toolboxes/combos/_palette.scss",
|
|
"website/src/styles/toolboxes/combos/_list.scss",
|
|
"website/src/styles/toolboxes/combos/_sequence.scss",
|
|
"website/src/styles/toolboxes/combos/_tokens.scss",
|
|
"website/src/styles/toolboxes/combos/_hold.scss"
|
|
]);
|
|
const styleToolboxImages = await readFile("website/src/styles/toolboxes/_images.scss", "utf8");
|
|
const styleToolboxGoalTree = await readJoinedStyles([
|
|
"website/src/styles/toolboxes/_goal-tree.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_editor.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_view.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_nodes.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-card.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-content.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-actions.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-drag.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-responsive.scss"
|
|
]);
|
|
const styleToolboxCalendar = await readJoinedStyles([
|
|
"website/src/styles/toolboxes/_calendar.scss",
|
|
"website/src/styles/toolboxes/calendar/_base.scss",
|
|
"website/src/styles/toolboxes/calendar/_form.scss",
|
|
"website/src/styles/toolboxes/calendar/_form-layout.scss",
|
|
"website/src/styles/toolboxes/calendar/_date-picker.scss",
|
|
"website/src/styles/toolboxes/calendar/_event-controls.scss",
|
|
"website/src/styles/toolboxes/calendar/_form-actions.scss",
|
|
"website/src/styles/toolboxes/calendar/_week.scss",
|
|
"website/src/styles/toolboxes/calendar/_month.scss",
|
|
"website/src/styles/toolboxes/calendar/_responsive.scss"
|
|
]);
|
|
const styleToolboxSharedControls = await readJoinedStyles([
|
|
"website/src/styles/toolboxes/_shared-controls.scss",
|
|
"website/src/styles/toolboxes/shared-controls/_selects.scss",
|
|
"website/src/styles/toolboxes/shared-controls/_split-controls.scss",
|
|
"website/src/styles/toolboxes/shared-controls/_split-tree.scss",
|
|
"website/src/styles/toolboxes/shared-controls/_mix-tags.scss",
|
|
"website/src/styles/toolboxes/shared-controls/_entries.scss"
|
|
]);
|
|
const styleOverlays = await readJoinedStyles([
|
|
"website/src/styles/_overlays.scss",
|
|
"website/src/styles/overlays/_image-viewer.scss",
|
|
"website/src/styles/overlays/_drawers.scss",
|
|
"website/src/styles/overlays/_modals.scss",
|
|
"website/src/styles/overlays/_notifications.scss",
|
|
"website/src/styles/overlays/_tool-add.scss"
|
|
]);
|
|
const styleIcons = await readJoinedStyles([
|
|
"website/src/styles/_icons.scss",
|
|
"website/src/styles/icons/_base.scss",
|
|
"website/src/styles/icons/_navigation.scss",
|
|
"website/src/styles/icons/_toolbox.scss",
|
|
"website/src/styles/icons/_actions.scss",
|
|
"website/src/styles/icons/_equipment.scss"
|
|
]);
|
|
const styleGames = await readJoinedStyles([
|
|
"website/src/styles/_games.scss",
|
|
"website/src/styles/games/_home-cards.scss",
|
|
"website/src/styles/games/_heading.scss",
|
|
"website/src/styles/games/_lists.scss",
|
|
"website/src/styles/games/_filters.scss",
|
|
"website/src/styles/games/_cards.scss"
|
|
]);
|
|
const styleMhwilds = await readFile("website/src/styles/_mhwilds.scss", "utf8");
|
|
const styleResponsive = await readFile("website/src/styles/_responsive.scss", "utf8");
|
|
|
|
assert.match(styles, /@use "tokens"/);
|
|
assert.match(styles, /@use "nebula"/);
|
|
assert.match(styles, /@use "toolboxes"/);
|
|
assert.match(styleToolboxesEntry, /@use "toolboxes\/core"/);
|
|
assert.match(styleToolboxesCore, /@use "layout"/);
|
|
assert.match(styleToolboxesCore, /@use "module-shell"/);
|
|
assert.match(styleToolboxesCore, /@use "task-planner"/);
|
|
assert.match(styleToolboxesCore, /@use "equipment-planner"/);
|
|
assert.match(styleToolboxesCore, /@use "shared-controls"/);
|
|
assert.match(styles, /@use "mhwilds"/);
|
|
assert.match(styles, /@use "diablo4"/);
|
|
assert.match(styleTokens, /--gradient-brand/);
|
|
assert.match(styleBase, /:is\(/);
|
|
assert.doesNotMatch(styleBase, /\.card-icon-button/);
|
|
assert.doesNotMatch(styleBase, /\.drawer-action-button/);
|
|
assert.doesNotMatch(styleBase, /\.import-icon-button/);
|
|
assert.match(styleBase, /themed-scrollbar/);
|
|
assert.match(styleBase, /body\.is-modal-open/);
|
|
assert.match(styleNebula, /@function star-field/);
|
|
assert.match(styleNebula, /body::after/);
|
|
assert.match(styleHome, /\.dialogue-line i/);
|
|
assert.match(styleHome, /font-style: italic/);
|
|
assert.match(styleHome, /\.about-page/);
|
|
assert.doesNotMatch(styleHome, /\.nebula-panel\s*\{/);
|
|
assert.match(styleHome, /\.home-onboarding-layout/);
|
|
assert.match(styleHome, /\.home-onboarding-slider figcaption/);
|
|
assert.match(styleHome, /\.home-onboarding-dots/);
|
|
assert.match(styleHome, /\.about-story-section/);
|
|
assert.match(styleHome, /\.about-tools-list/);
|
|
assert.match(styleHome, /\.about-tool-item \.module-icon/);
|
|
assert.match(styleMixins, /@mixin gold-panel-frame/);
|
|
assert.match(styleShell, /\.sidebar-about-link/);
|
|
assert.match(styleShell, /\.sidebar-mascot/);
|
|
assert.match(styleToolboxShell, /\.module-icon-abacus/);
|
|
assert.match(styleToolboxShell, /\.module-icon-calculator/);
|
|
assert.match(styleToolboxShell, /\.module-icon-columns/);
|
|
assert.match(styleToolboxShell, /\.module-icon-table/);
|
|
assert.match(styleToolboxCalculator, /\.calculator-module/);
|
|
assert.match(styleToolboxTable, /\.table-module/);
|
|
assert.match(styleToolboxTable, /\.table-cell-input\.is-selected/);
|
|
assert.match(styleToolboxTable, /\.table-cell-input\.is-move-target/);
|
|
assert.match(styleToolboxGoalTree, /\.goal-tree-node-card/);
|
|
assert.match(styleToolboxGoalTree, /\.goal-tree-node-content-row/);
|
|
assert.match(styleToolboxGoalTree, /\.goal-tree-node.is-drop-target/);
|
|
assert.match(styleToolboxCalendar, /\.calendar-event-form/);
|
|
assert.match(styleToolboxCalendar, /\.calendar-month-date-picker/);
|
|
assert.match(styleToolboxCalendar, /\.calendar-alert-mode-switch/);
|
|
assert.match(styles, /@use "design-system\/attributes"/);
|
|
assert.match(styleToolboxLayout, /\.toolbox-icon-picker/);
|
|
assert.match(styleToolboxLayout, /border-radius: inherit/);
|
|
assert.match(styleToolboxLayout, /\.toolbox-icon-picker-button\.has-custom-cover img/);
|
|
assert.match(styleToolboxLayout, /grid-column: 1 \/ -1/);
|
|
assert.match(styleToolboxLayout, /@use "layout\/cover-editor"/);
|
|
assert.match(styleToolboxLayout, /\.toolbox-cover-editor/);
|
|
assert.match(styleToolboxLayout, /\.toolbox-cover-crop-frame/);
|
|
assert.match(styleToolboxLayout, /aspect-ratio: 620 \/ 248/);
|
|
assert.match(styleToolboxLayout, /\.toolbox-game-icon/);
|
|
assert.match(styleToolboxLayout, /\.toolbox-hero-link/);
|
|
assert.match(styleToolboxLayout, /\.toolbox-actions-row/);
|
|
assert.match(styleToolboxTextExchange, /\.text-import-actions/);
|
|
assert.match(styleToolboxTextExchange, /\.text-import-modal-dialog/);
|
|
assert.doesNotMatch(styleToolboxNotepad, /lecture seule/);
|
|
assert.match(styleIcons, /ui-icon-drag/);
|
|
assert.match(styleIcons, /ui-icon-dropdown/);
|
|
assert.match(styleIcons, /ui-icon-enter/);
|
|
assert.match(styleIcons, /ui-icon-calculator/);
|
|
assert.match(styleIcons, /ui-icon-scrollable/);
|
|
assert.match(styleIcons, /ui-icon-hide/);
|
|
assert.match(styleIcons, /ui-icon-eye-open/);
|
|
assert.match(styleIcons, /ui-icon-eye-closed/);
|
|
assert.match(styleIcons, /ui-icon-chevron-down/);
|
|
assert.match(styleIcons, /ui-icon-chevron-up/);
|
|
assert.match(styleIcons, /ui-icon-flip/);
|
|
assert.match(styleIcons, /ui-icon-add/);
|
|
assert.match(styleIcons, /ui-icon-add-row/);
|
|
assert.match(styleIcons, /ui-icon-add-column/);
|
|
assert.match(styleIcons, /ui-icon-remove-row/);
|
|
assert.match(styleIcons, /ui-icon-remove-column/);
|
|
assert.match(styleIcons, /ui-icon-table/);
|
|
assert.match(styleIcons, /ui-icon-map/);
|
|
assert.match(styleIcons, /ui-icon-grab/);
|
|
assert.match(styleIcons, /ui-icon-shield/);
|
|
assert.match(styleIcons, /ui-icon-gun/);
|
|
assert.match(styleToolboxShell, /module-icon-chest-armor/);
|
|
assert.match(styleToolboxCombos, /\.combo-hold-controls/);
|
|
assert.match(styleToolboxCombos, /\.combo-input-direction/);
|
|
assert.match(styleToolboxCombos, /\.combo-device-n64\.combo-value-stick-up/);
|
|
assert.match(styleToolboxCombos, /\.combo-device-n64\.combo-value-up/);
|
|
assert.match(styleToolboxCombos, /\.combo-value-grab \.ui-icon/);
|
|
assert.match(styleToolboxChecklist, /\.timer-alert-mode-button/);
|
|
assert.match(styleToolboxSharedControls, /\.timer-alert-mode-switch\.is-blocked/);
|
|
assert.match(styleToolboxCalculatorResults, /\.calculator-result/);
|
|
assert.match(styleToolboxSharedControls, /\.tool-split-scroll-toggle/);
|
|
assert.match(styleToolboxImages, /\.annotation-marker/);
|
|
assert.match(styleGames, /\.game-home-card/);
|
|
assert.match(styleGames, /\.game-layout/);
|
|
assert.match(styleGames, /\.game-grid/);
|
|
assert.match(styleGames, /\.filter-panel/);
|
|
assert.match(styleSurfaces, /@mixin card-surface/);
|
|
assert.match(styleSurfaces, /@mixin card-surface-hover/);
|
|
assert.match(styleSurfaces, /@mixin card-cover-divider/);
|
|
assert.match(styleControls, /@forward "controls\/patterns"/);
|
|
assert.match(styleAttributes, /@use "attributes\/patterns"/);
|
|
assert.match(styleControlsPatterns, /@mixin panel-surface/);
|
|
assert.match(styleControlsPatterns, /@mixin toast-pattern/);
|
|
assert.match(styleAttributesPatterns, /\.nds-panel/);
|
|
assert.match(styleAttributesPatterns, /\.nds-card/);
|
|
assert.match(styleAttributesPatterns, /\.nds-tool-panel/);
|
|
assert.match(styleAttributesPatterns, /\.nds-badge/);
|
|
assert.match(styleAttributesPatterns, /\.nds-chip/);
|
|
assert.match(styleAttributesPatterns, /\.nds-empty-state/);
|
|
assert.match(styleAttributesPatterns, /\.nds-inline-notice/);
|
|
assert.match(styleAttributesPatterns, /\.nds-progress/);
|
|
assert.match(styleAttributesPatterns, /\.nds-filter-panel/);
|
|
assert.match(styleAttributesPatterns, /\.nds-modal/);
|
|
assert.match(styleAttributesPatterns, /\.nds-drawer-panel/);
|
|
assert.match(styleAttributesPatterns, /\.nds-toast/);
|
|
assert.match(ndsPatternConsumers, /nds-page-hero/);
|
|
assert.match(ndsPatternConsumers, /nds-panel/);
|
|
assert.match(ndsPatternConsumers, /nds-card/);
|
|
assert.match(ndsPatternConsumers, /nds-card-cover/);
|
|
assert.match(ndsPatternConsumers, /nds-tool-panel/);
|
|
assert.match(ndsPatternConsumers, /nds-filter-panel/);
|
|
assert.match(ndsPatternConsumers, /nds-chip/);
|
|
assert.match(ndsPatternConsumers, /nds-badge/);
|
|
assert.match(ndsPatternConsumers, /nds-empty-state/);
|
|
assert.match(ndsPatternConsumers, /nds-inline-notice/);
|
|
assert.match(ndsPatternConsumers, /nds-progress/);
|
|
assert.match(ndsPatternConsumers, /nds-modal/);
|
|
assert.match(ndsPatternConsumers, /nds-drawer-panel/);
|
|
assert.match(ndsPatternConsumers, /nds-toast/);
|
|
assert.doesNotMatch(styleCards, /@use "design-system\/surfaces"/);
|
|
assert.doesNotMatch(styleCards, /controls\.card-pattern/);
|
|
assert.match(styleGames, /@use "\.\.\/design-system\/surfaces"/);
|
|
assert.match(styleGames, /surfaces\.card-surface/);
|
|
assert.match(styleGames, /surfaces\.card-cover-divider/);
|
|
assert.match(styleMhwilds, /\.mhwilds-card/);
|
|
assert.match(styleMhwilds, /\.mhwilds-flip-indicator/);
|
|
assert.match(styleMhwilds, /@use "design-system\/surfaces"/);
|
|
assert.match(styleMhwilds, /surfaces\.card-surface/);
|
|
assert.match(styleMhwilds, /surfaces\.card-cover-divider/);
|
|
assert.doesNotMatch(styleMhwilds, /\.game-(home-card|layout|grid)/);
|
|
assert.doesNotMatch(styleCards, /\.compact-data-card\s*\{/);
|
|
assert.doesNotMatch(
|
|
[
|
|
goalTreeBranch,
|
|
styleToolboxGoalTree,
|
|
styleControlsButtons,
|
|
styleAttributesButtons
|
|
].join("\n"),
|
|
/(?:data-size="tiny"|icon-button(?:-icon)?\(tiny\)|\$size == tiny)/
|
|
);
|
|
assert.match(styleOverlays, /overscroll-behavior: contain/);
|
|
assert.match(styleResponsive, /@media \(max-width: 760px\)/);
|
|
});
|
|
|
|
test("large sass files stay split by stable responsibility", async () => {
|
|
const orchestrators = [
|
|
"website/src/styles/home/_library.scss",
|
|
"website/src/styles/home/_about.scss",
|
|
"website/src/styles/_overlays.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_nodes.scss",
|
|
"website/src/styles/_icons.scss",
|
|
"website/src/styles/toolboxes/calendar/_form.scss"
|
|
];
|
|
const partials = [
|
|
"website/src/styles/home/library/_page.scss",
|
|
"website/src/styles/home/library/_summary.scss",
|
|
"website/src/styles/home/library/_toc.scss",
|
|
"website/src/styles/home/library/_tool-cards.scss",
|
|
"website/src/styles/home/library/_examples.scss",
|
|
"website/src/styles/home/library/_previews.scss",
|
|
"website/src/styles/home/about/_page.scss",
|
|
"website/src/styles/home/about/_story.scss",
|
|
"website/src/styles/home/about/_contribute.scss",
|
|
"website/src/styles/home/about/_tools.scss",
|
|
"website/src/styles/home/about/_reminders.scss",
|
|
"website/src/styles/overlays/_image-viewer.scss",
|
|
"website/src/styles/overlays/_drawers.scss",
|
|
"website/src/styles/overlays/_modals.scss",
|
|
"website/src/styles/overlays/_notifications.scss",
|
|
"website/src/styles/overlays/_tool-add.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-card.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-content.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-actions.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-drag.scss",
|
|
"website/src/styles/toolboxes/goal-tree/_node-responsive.scss",
|
|
"website/src/styles/icons/_base.scss",
|
|
"website/src/styles/icons/_navigation.scss",
|
|
"website/src/styles/icons/_toolbox.scss",
|
|
"website/src/styles/icons/_actions.scss",
|
|
"website/src/styles/icons/_equipment.scss",
|
|
"website/src/styles/toolboxes/calendar/_form-layout.scss",
|
|
"website/src/styles/toolboxes/calendar/_date-picker.scss",
|
|
"website/src/styles/toolboxes/calendar/_event-controls.scss",
|
|
"website/src/styles/toolboxes/calendar/_form-actions.scss"
|
|
];
|
|
|
|
for (const path of orchestrators) {
|
|
const source = await readFile(path, "utf8");
|
|
assert.ok(source.startsWith("// Rôle :"), `${path} must keep a role header`);
|
|
assert.ok(countLines(source) <= 120, `${path} should remain an orchestrator`);
|
|
}
|
|
|
|
for (const path of partials) {
|
|
const source = await readFile(path, "utf8");
|
|
assert.ok(source.startsWith("// Rôle :"), `${path} must keep a role header`);
|
|
assert.ok(countLines(source) <= 300, `${path} should stay scoped to one responsibility`);
|
|
}
|
|
});
|