Интегрирован wesp в сайт
CI / quality (push) Canceled after 0s

This commit is contained in:
влад
2026-07-17 12:57:18 +03:00
parent 5dfa06ddbe
commit 355c0ef9f1
883 changed files with 194576 additions and 177 deletions
+125
View File
@@ -0,0 +1,125 @@
"""UI-контракты кормоцеха: HTML/JS и страницы (без браузерного раннера)."""
from __future__ import annotations
import os
import re
import tempfile
import unittest
from pathlib import Path
from app import create_app, db
from app.services.setup_state import mark_setup_complete
from config import TestingConfig
PROJECT_ROOT = Path(__file__).resolve().parent.parent
STATIC = PROJECT_ROOT / "static"
class FeedMillUiConfig(TestingConfig):
_TMP_DIR = tempfile.mkdtemp(prefix="wesp-feed-mill-ui-")
SQLALCHEMY_DATABASE_URI = f"sqlite:///{os.path.join(_TMP_DIR, 'recipes_test.db')}"
SQLALCHEMY_BINDS = {"reports": f"sqlite:///{os.path.join(_TMP_DIR, 'reports_test.db')}"}
AUTH_LOGIN = "mill-ui-admin"
AUTH_PASSWORD = "mill-ui-secret"
def _drain_response(resp) -> None:
try:
resp.get_data()
finally:
close = getattr(resp, "close", None)
if callable(close):
close()
class FeedMillUiTests(unittest.TestCase):
def setUp(self) -> None:
self.app = create_app(FeedMillUiConfig)
self.client = self.app.test_client()
self.ctx = self.app.app_context()
self.ctx.push()
db.create_all()
mark_setup_complete(self.app)
def tearDown(self) -> None:
db.session.remove()
db.drop_all()
self.ctx.pop()
def _login(self) -> None:
resp = self.client.post(
"/api/auth/login", json={"login": "mill-ui-admin", "password": "mill-ui-secret"}
)
self.assertEqual(resp.status_code, 200)
def test_feed_dispensers_page_requires_auth(self) -> None:
resp = self.client.get("/feed_dispensers", follow_redirects=False)
self.assertIn(resp.status_code, (302, 401, 403))
def test_feed_dispensers_and_recipes_pages_ok_when_authed(self) -> None:
self._login()
for path in ("/feed_dispensers", "/recipes"):
resp = self.client.get(path)
_drain_response(resp)
self.assertEqual(resp.status_code, 200, path)
self.assertIn(b"<!DOCTYPE html>", resp.data or b"")
def test_feed_dispensers_html_mill_modal_and_create_payload(self) -> None:
html = (STATIC / "feed_dispensers.html").read_text(encoding="utf-8")
self.assertIn("Добавить кормоцех", html)
self.assertIn('id="addMillModalLabel"', html)
self.assertIn("type: 'mill'", html)
self.assertIn("dispenser-card--mill", html)
self.assertIn("!isMill", html)
self.assertIn("managePeriods", html)
def test_recipes_data_controller_mill_branch(self) -> None:
js = (STATIC / "js" / "pages" / "recipes-data-controller.js").read_text(encoding="utf-8")
self.assertIn('getCurrentDispenserType() === "mill"', js)
self.assertIn("loadMillRecipes", js)
self.assertIn('millRecipesList', js)
self.assertIn('dispenser.type === "mill"', js)
self.assertIn('? "recipes" : "periods"', js)
def test_recipes_operations_mill_uses_global_delete(self) -> None:
js = (STATIC / "js" / "pages" / "recipes-operations-controller.js").read_text(
encoding="utf-8"
)
self.assertIn('getCurrentDispenserType() === "mill"', js)
self.assertIn("unlinkFromPeriodOnly", js)
self.assertIn("/api/recipes/", js)
# mill: DELETE глобальный, не unlink из периода
self.assertRegex(
js,
r"unlinkFromPeriodOnly\s*=\s*Boolean\(periodId\s*&&\s*dispenserId\s*&&\s*!isMill\)",
)
def test_recipes_editor_mill_target_component(self) -> None:
js = (STATIC / "js" / "pages" / "recipes-editor-controller.js").read_text(encoding="utf-8")
self.assertIn('getCurrentDispenserType() === "mill"', js)
self.assertIn("target_component", js)
def test_recipe_period_transfer_excludes_mill(self) -> None:
js = (STATIC / "js" / "modules" / "recipes" / "recipe-period-transfer.js").read_text(
encoding="utf-8"
)
self.assertIn('dataset.dispenserType === "mill"', js)
mill_skips = len(re.findall(r'dispenserType\s*===\s*["\']mill["\']', js))
self.assertGreaterEqual(mill_skips, 2)
def test_recipes_html_legacy_mill_flow_present(self) -> None:
html = (STATIC / "recipes.html").read_text(encoding="utf-8")
self.assertIn("currentDispenserType = 'dispenser'", html)
self.assertIn("currentDispenserType === 'mill'", html)
self.assertIn("target_component_id", html)
self.assertIn("Загрузка рецептов кормоцеха", html)
def test_recipe_skeleton_mill_label(self) -> None:
js = (STATIC / "js" / "modules" / "recipes" / "recipe-skeleton.js").read_text(encoding="utf-8")
self.assertIn("mill:", js)
self.assertIn("Загрузка рецептов", js)
if __name__ == "__main__":
unittest.main()