Harden toolbox static checks
All checks were successful
Deploy Sokko G / deploy (push) Successful in 14s

This commit is contained in:
Shinuwa 2026-08-14 09:25:31 +02:00
parent 348f6f278b
commit 97253acb00
5 changed files with 53 additions and 8 deletions

View file

@ -41,7 +41,7 @@ export default [
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_"
}],
"react-refresh/only-export-components": "off"
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }]
}
},
{

View file

@ -2,6 +2,8 @@
import { readFile } from "node:fs/promises";
import { test } from "node:test";
import assert from "node:assert/strict";
import { SOCKET_SHAPES, formatValue, getSocketItemName, setItemCategory } from "../website/src/features/toolboxes/modules/equipmentPlannerOptions.js";
import { applyDueResets, getTaskParentMap, getTaskTreeIds, moveTask } from "../website/src/features/toolboxes/modules/taskPlannerUtils.js";
test("toolbox storage, cards and pages are wired", async () => {
const source = await readFile("website/src/main.jsx", "utf8");
@ -111,7 +113,10 @@ test("toolbox module registry and modules expose expected behavior", async () =>
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 taskPlannerItems = await readFile("website/src/features/toolboxes/modules/TaskPlannerItems.jsx", "utf8");
const taskPlannerUtils = await readFile("website/src/features/toolboxes/modules/taskPlannerUtils.js", "utf8");
const equipmentPlannerModule = await readFile("website/src/features/toolboxes/modules/EquipmentPlannerModule.jsx", "utf8");
const equipmentPlannerOptions = await readFile("website/src/features/toolboxes/modules/equipmentPlannerOptions.js", "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");
@ -253,17 +258,20 @@ test("toolbox module registry and modules expose expected behavior", async () =>
assert.match(taskPlannerModule, /export function TaskPlannerModule/);
assert.match(taskPlannerModule, /normalizeTaskPlannerData/);
assert.match(taskPlannerModule, /applyDueResets/);
assert.match(taskPlannerModule, /relations/);
assert.match(taskPlannerModule, /prerequisite/);
assert.match(taskPlannerModule, /categoryOrder/);
assert.match(taskPlannerModule, /categoryLabel/);
assert.match(taskPlannerModule, /task-planner-warning/);
assert.match(taskPlannerModule, /TaskPlannerBranch/);
assert.match(taskPlannerModule, /useGroupedReorder/);
assert.match(taskPlannerModule, /useInlineEdit/);
assert.match(taskPlannerModule, /useDraftForm/);
assert.match(taskPlannerModule, /commitOnEnter: false/);
assert.match(taskPlannerModule, /TextExchangeActions/);
assert.match(taskPlannerModule, /reorderFeatures/);
assert.match(taskPlannerItems, /export function TaskPlannerBranch/);
assert.match(taskPlannerItems, /function TaskPlannerItem/);
assert.match(taskPlannerItems, /task-planner-warning/);
assert.match(taskPlannerItems, /useInlineEdit/);
assert.match(taskPlannerItems, /commitOnEnter: false/);
assert.match(taskPlannerItems, /categoryLabel/);
assert.match(taskPlannerItems, /prerequisite/);
assert.match(taskPlannerUtils, /export function getTaskParentMap/);
assert.match(taskPlannerUtils, /export function applyDueResets/);
assert.doesNotMatch(taskPlannerModule, /canMoveItem:/);
assert.doesNotMatch(taskPlannerModule, /canMoveGroup:/);
assert.match(equipmentPlannerModule, /export function EquipmentPlannerModule/);
@ -274,6 +282,8 @@ test("toolbox module registry and modules expose expected behavior", async () =>
assert.match(equipmentPlannerModule, /useGroupedReorder/);
assert.match(equipmentPlannerModule, /reorderFeatures/);
assert.match(equipmentPlannerModule, /TextExchangeActions/);
assert.match(equipmentPlannerOptions, /export const EQUIPMENT_ICONS/);
assert.match(equipmentPlannerOptions, /export function formatValue/);
assert.match(checklistModule, /export function ChecklistModule/);
assert.match(checklistModule, /TextExchangeActions/);
assert.match(checklistModule, /editing &&/);
@ -354,3 +364,35 @@ test("toolbox module registry and modules expose expected behavior", async () =>
assert.match(imageViewer, /<Icon name="zoom"/);
assert.match(imageViewer, /annotation-marker-list themed-scrollbar/);
});
test("task planner helpers keep hierarchy, reorder and reset behavior stable", () => {
const tasks = [
{ id: "a", title: "A", type: "daily", checked: true, checkedAt: Date.UTC(2026, 0, 1, 7) },
{ id: "b", title: "B", type: "unique", checked: false },
{ id: "c", title: "C", type: "weekly", checked: true, checkedAt: Date.UTC(2026, 0, 1, 7) }
];
const relations = [{ id: "r1", fromTaskId: "b", toTaskId: "a", prerequisite: false }];
const parentMap = getTaskParentMap(tasks, relations);
assert.equal(parentMap.get("b"), "a");
assert.deepEqual(getTaskTreeIds(["a"], tasks, parentMap), ["a", "b"]);
assert.deepEqual(moveTask(tasks, "c", "a").map((task) => task.id), ["c", "a", "b"]);
const resetData = applyDueResets({
tasks,
relations,
resetTime: "06:00",
weeklyResetDay: 4,
categoryOrder: [],
lastResetAt: Date.UTC(2026, 0, 1, 5)
}, Date.UTC(2026, 0, 2, 8));
assert.equal(resetData.tasks.find((task) => task.id === "a").checked, false);
});
test("equipment planner options expose stable formatting and socket helpers", () => {
assert.deepEqual(SOCKET_SHAPES, ["ball", "jewel"]);
assert.equal(formatValue(1.23456), "1.235");
assert.deepEqual(setItemCategory({ id: "item" }, "DPS"), { id: "item", category: "DPS" });
assert.deepEqual(setItemCategory({ id: "item", category: "DPS" }, ""), { id: "item" });
assert.equal(getSocketItemName({ socketItems: [{ id: "gem", name: "Ruby" }] }, "gem"), "Ruby");
});

View file

@ -1,4 +1,5 @@
// Rôle : copie des données filtrées au format compatible avec l'import checklist.
/* eslint-disable react-refresh/only-export-components -- expose aussi les formatters publics testés pour l'import checklist. */
import { useState } from "react";
import { Icon } from "../../components/Icon.jsx";

View file

@ -1,4 +1,5 @@
// Rôle : affiche une toolbox dans la liste, avec actions rapides et icône personnalisable.
/* eslint-disable react-refresh/only-export-components -- expose aussi les helpers publics de rendu des cartes toolbox. */
import { CompactDropdown } from "../../components/CompactDropdown.jsx";
import { Icon } from "../../components/Icon.jsx";
import {

View file

@ -1,4 +1,5 @@
// Rôle : point d'entrée React, assemble données, routes, shell et overlays.
/* eslint-disable react-refresh/only-export-components -- point d'entrée Vite sans export de composant. */
import { lazy, Suspense, useCallback, useEffect, useState } from "react";
import { createRoot } from "react-dom/client";
import "./styles/main.scss";