"""Инвентарь UI страницы /recipes — источник правды для контракт- и E2E-тестов.""" from __future__ import annotations from pathlib import Path from typing import Dict, List, Tuple PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent STATIC = PROJECT_ROOT / "static" # Ключевые DOM id (dashboard + editor + mobile) DOM_IDS: List[str] = [ "wespZootechNavMount", "recipesMobileNav", "recipesMobileNavTitle", "recipesDashboard", "dispensersCol", "periodsCol", "recipesCol", "dispensersList", "periodsList", "recipesList", "recipesCardHeaderText", "createRecipeBtn", "recipeEdit", "recipeEditSkeletonPanel", "recipeForm", "recipeName", "headsCount", "mixingTime", "tripPercent", "ingredientsTable", "ingredientsTableBody", "unloadingGroupsCard", "unloadingGroupsTableBody", "componentSelectionCard", "targetComponentSelect", "ingredientMobileSheet", "unloadingGroupMobileSheet", "recipeHelpModal", ] # data-action → файл(ы), где должен быть handler DATA_ACTION_HANDLERS: Dict[str, List[str]] = { "mobile-dashboard-back": ["static/js/pages/recipes-page.js"], "open-recipe-help": ["static/js/pages/recipes-page.js"], "close-recipe-help": ["static/js/pages/recipes-page.js"], "logout": ["static/js/pages/recipes-page.js", "static/js/wesp-zootech-nav.js"], "add-ingredient": ["static/js/modules/recipes/recipe-editor.js"], "toggle-unloading-link": ["static/js/modules/recipes/recipe-editor.js"], "add-unloading-group": ["static/js/modules/recipes/recipe-editor.js"], "show-recipe-edit-off": ["static/js/modules/recipes/recipe-editor.js"], "print-all-recipes": ["static/js/modules/recipes/recipe-editor.js"], "print-recipe": ["static/js/modules/recipes/recipe-editor.js"], "save-and-exit": ["static/js/modules/recipes/recipe-editor.js"], "move-group-up": ["static/js/modules/recipes/recipe-editor.js"], "move-group-down": ["static/js/modules/recipes/recipe-editor.js"], "remove-unloading-group": ["static/js/modules/recipes/recipe-editor.js"], "move-ingredient-up": ["static/js/modules/recipes/recipe-editor.js"], "move-ingredient-down": ["static/js/modules/recipes/recipe-editor.js"], "remove-ingredient": ["static/js/modules/recipes/recipe-editor.js"], "open-ingredient-sheet": ["static/js/modules/recipes/recipe-editor.js"], "close-ingredient-sheet": ["static/js/modules/recipes/recipe-editor.js"], "open-unloading-group-sheet": ["static/js/modules/recipes/recipe-editor.js"], "close-unloading-group-sheet": ["static/js/modules/recipes/recipe-editor.js"], "group-type-change": ["static/js/modules/recipes/recipe-editor.js"], "group-value-change": ["static/js/modules/recipes/recipe-editor.js"], "ingredient-change": ["static/js/modules/recipes/recipe-editor.js"], "dry-matter-percent-change": ["static/js/modules/recipes/recipe-editor.js"], "recalculate-weights": ["static/js/modules/recipes/recipe-editor.js"], "recalculate-total-weight": ["static/js/modules/recipes/recipe-editor.js"], "select-dispenser": ["static/js/modules/recipes/dispenser-selector.js"], "select-recipe": ["static/js/modules/recipes/dispenser-selector.js"], "select-period": ["static/js/modules/recipes/dispenser-selector.js"], "copy-recipe": ["static/js/modules/recipes/dispenser-selector.js"], "delete-recipe": ["static/js/modules/recipes/dispenser-selector.js"], "unskip-recipe-today": ["static/js/modules/recipes/dispenser-selector.js"], "unskip-ingredient-parts-today": ["static/js/modules/recipes/dispenser-selector.js"], "unskip-group-parts-today": ["static/js/modules/recipes/dispenser-selector.js"], "paste-recipe": ["static/js/modules/recipes/dispenser-selector.js"], "create-recipe": ["static/js/modules/recipes/dispenser-selector.js"], "move-recipe-up": ["static/js/modules/recipes/dispenser-selector.js"], "move-recipe-down": ["static/js/modules/recipes/dispenser-selector.js"], "recipe-drag-handle": ["static/js/modules/recipes/dispenser-selector.js"], "open-settings": ["static/js/modules/recipes/sync-panel.js", "static/js/wesp-zootech-nav.js"], "close-settings": ["static/js/modules/recipes/sync-panel.js"], "toggle-credentials-form": ["static/js/modules/recipes/sync-panel.js"], "toggle-sync-form": ["static/js/modules/recipes/sync-panel.js"], "change-credentials": ["static/js/modules/recipes/sync-panel.js"], "sync-edit-client": ["static/js/modules/recipes/sync-panel.js"], "sync-delete-client": ["static/js/modules/recipes/sync-panel.js"], "sync-save-client": ["static/js/modules/recipes/sync-panel.js"], "sync-cancel-edit": ["static/js/modules/recipes/sync-panel.js"], } # data-action → уровень теста, который должен покрывать action (e2e | api | contract) ACTION_COVERAGE_TARGET: Dict[str, str] = { "mobile-dashboard-back": "e2e", "open-recipe-help": "e2e", "close-recipe-help": "e2e", "logout": "e2e", "add-ingredient": "e2e", "toggle-unloading-link": "e2e", "add-unloading-group": "contract", "show-recipe-edit-off": "contract", "print-all-recipes": "e2e", "print-recipe": "e2e", "save-and-exit": "e2e", "move-group-up": "api", "move-group-down": "api", "remove-unloading-group": "contract", "move-ingredient-up": "api", "move-ingredient-down": "api", "remove-ingredient": "e2e", "open-ingredient-sheet": "e2e", "close-ingredient-sheet": "e2e", "open-unloading-group-sheet": "contract", "close-unloading-group-sheet": "contract", "group-type-change": "e2e", "group-value-change": "contract", "ingredient-change": "contract", "dry-matter-percent-change": "e2e", "recalculate-weights": "contract", "recalculate-total-weight": "contract", "select-dispenser": "e2e", "select-recipe": "e2e", "select-period": "e2e", "copy-recipe": "e2e", "delete-recipe": "e2e", "unskip-recipe-today": "api", "unskip-ingredient-parts-today": "api", "unskip-group-parts-today": "api", "paste-recipe": "e2e", "create-recipe": "e2e", "move-recipe-up": "e2e", "move-recipe-down": "e2e", "recipe-drag-handle": "e2e", "open-settings": "e2e", "close-settings": "e2e", "toggle-credentials-form": "e2e", "toggle-sync-form": "e2e", "change-credentials": "contract", "sync-edit-client": "contract", "sync-delete-client": "contract", "sync-save-client": "contract", "sync-cancel-edit": "contract", } # fetch URL patterns в JS страницы рецептов API_ENDPOINTS: List[Tuple[str, List[str]]] = [ ("/api/feed_dispensers", ["static/js/pages/recipes-data-controller.js"]), ("/api/feed_dispensers/", ["static/js/pages/recipes-data-controller.js", "static/js/pages/recipes-operations-controller.js"]), ("/api/periods/", ["static/js/pages/recipes-data-controller.js", "static/js/pages/recipes-operations-controller.js"]), ("/api/recipes/calculate", ["static/recipes.html"]), ("/api/recipes/", ["static/recipes.html", "static/js/pages/recipes-operations-controller.js", "static/js/pages/recipes-editor-controller.js"]), ("/api/auth/check", ["static/recipes.html", "static/js/pages/recipes-auth-settings.js"]), ("/api/auth/logout", ["static/js/pages/recipes-auth-settings.js"]), ("/api/auth/change_credentials", ["static/js/pages/recipes-auth-settings.js"]), ("/api/sync/clients", ["static/js/pages/recipes-auth-settings.js"]), ] # CSS анимации / transition-классы CSS_ANIMATION_MARKERS: List[Tuple[str, List[str]]] = [ ("dashboard-skeleton-shimmer", ["static/css/wesp-recipes-skeleton.css"]), ("dashboard-list-skeleton--exit", ["static/css/wesp-recipes-skeleton.css"]), ("recipe-form--enter", ["static/css/wesp-recipes-editor.css", "static/recipes.html"]), ("dashboard-mobile-step-", ["static/css/wesp-recipes-mobile.css", "static/js/pages/recipes-data-controller.js"]), ] # Скелетон-templates SKELETON_TEMPLATE_IDS: List[str] = [ "recipe-card-skeleton-inner", "recipe-card-skeleton-inner--mill", "dashboard-list-skeleton-dispensers", "dashboard-list-skeleton-periods", ] # Mill-ветки в JS/HTML MILL_MARKERS: List[Tuple[str, List[str]]] = [ ("loadMillRecipes", ["static/js/pages/recipes-data-controller.js"]), ("getCurrentDispenserType() === \"mill\"", [ "static/js/pages/recipes-data-controller.js", "static/js/pages/recipes-operations-controller.js", "static/js/pages/recipes-editor-controller.js", ]), ("deleted_ingredient_ids", ["static/recipes.html"]), ("deleted_unloading_group_ids", ["static/recipes.html"]), ("target_component_id", ["static/recipes.html", "static/js/pages/recipes-editor-controller.js"]), ("unlinkFromPeriodOnly", ["static/js/pages/recipes-operations-controller.js"]), ] # Скрипты, импортируемые из recipes.html (type=module) RECIPES_PAGE_SCRIPTS: List[str] = [ "recipes-boot.js", "recipes-page.js", "recipes-data-controller.js", "recipes-operations-controller.js", "recipes-editor-controller.js", "recipes-auth-settings.js", "recipe-list-dnd.js", "recipe-period-transfer.js", "recipe-mobile-sheet-gestures.js", ] # Модули, подключаемые через recipes-page.js RECIPES_PAGE_NESTED_MODULES: List[str] = [ "recipe-editor.js", "dispenser-selector.js", "sync-panel.js", ]