"""Served HTML /recipes: auth, структура, скрипты, preload.""" from __future__ import annotations import os import re import tempfile import unittest from app import create_app, db from app.models import Component, FeedDispenser, Recipe from app.services.setup_state import mark_setup_complete from config import TestingConfig from tests.helpers.recipes_ui_inventory import DOM_IDS, RECIPES_PAGE_SCRIPTS class RecipesPageServedConfig(TestingConfig): _TMP_DIR = tempfile.mkdtemp(prefix="wesp-recipes-served-") 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 = "recipes-served-admin" AUTH_PASSWORD = "recipes-served-secret" def _drain(resp) -> None: try: resp.get_data() finally: close = getattr(resp, "close", None) if callable(close): close() class RecipesPageServedTests(unittest.TestCase): def setUp(self) -> None: self.app = create_app(RecipesPageServedConfig) 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": "recipes-served-admin", "password": "recipes-served-secret"}, ) self.assertEqual(resp.status_code, 200) _drain(resp) def test_recipes_redirects_without_session(self) -> None: resp = self.client.get("/recipes", follow_redirects=False) self.assertEqual(resp.status_code, 302) self.assertIn("/login", resp.headers.get("Location", "")) _drain(resp) def test_recipes_served_with_key_dom_after_login(self) -> None: self._login() resp = self.client.get("/recipes") self.assertEqual(resp.status_code, 200) body = resp.get_data(as_text=True) for dom_id in DOM_IDS[:12]: with self.subTest(dom_id=dom_id): self.assertIn(f'id="{dom_id}"', body) _drain(resp) def test_recipes_page_includes_module_scripts(self) -> None: self._login() body = self.client.get("/recipes").get_data(as_text=True) for script in RECIPES_PAGE_SCRIPTS: with self.subTest(script=script): self.assertRegex(body, re.escape(script)) def test_recipes_page_preload_module_chain(self) -> None: self._login() body = self.client.get("/recipes").get_data(as_text=True) self.assertIn("recipes-boot.js", body) self.assertIn("recipes-data-controller.js", body) def test_api_feed_dispensers_returns_seeded_mill_for_page(self) -> None: self._login() mill = FeedDispenser( id="mill-served-1", name="Цех served", farm="F", operator="O", type="mill", content_hash="", ) comp = Component( id="comp-served-1", name="Зерно", type="grain", dry_matter=50.0, protein=0.0, energy=0.0, price=0.0, ) recipe = Recipe( id="recipe-served-1", name="Рецепт served", heads_per_trip=5, mixing_time=3, trip_percent=100.0, target_component_id=comp.id, content_hash="", ) db.session.add_all([mill, comp, recipe]) db.session.commit() dispensers = self.client.get("/api/feed_dispensers") self.assertEqual(dispensers.status_code, 200) rows = dispensers.get_json() mill_rows = [r for r in rows if r.get("id") == mill.id] self.assertEqual(len(mill_rows), 1) self.assertEqual(mill_rows[0]["type"], "mill") recipes = self.client.get(f"/api/feed_dispensers/{mill.id}/recipes") self.assertEqual(recipes.status_code, 200) recipe_ids = [r["id"] for r in recipes.get_json()] self.assertIn(recipe.id, recipe_ids) if __name__ == "__main__": unittest.main()