From ab18383bf4b1f85f0f2a4659370b81034f54ca0e Mon Sep 17 00:00:00 2001 From: Gros Frumos Date: Thu, 19 Mar 2026 21:53:31 +0200 Subject: [PATCH] kin: KIN-122-backend_dev --- scripts/rebuild-frontend.sh | 9 ++++ tests/test_kin_122_regression.py | 86 ++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 tests/test_kin_122_regression.py diff --git a/scripts/rebuild-frontend.sh b/scripts/rebuild-frontend.sh index b21ae1c..d95cd56 100755 --- a/scripts/rebuild-frontend.sh +++ b/scripts/rebuild-frontend.sh @@ -15,6 +15,15 @@ FRONTEND_DIR="$PROJECT_ROOT/web/frontend" echo "[rebuild-frontend] Building frontend in $FRONTEND_DIR ..." cd "$FRONTEND_DIR" + +# KIN-122: auto npm install if package.json is newer than node_modules (or node_modules missing). +# This handles the case where agents add new imports/dependencies to package.json. +if [ ! -d "node_modules" ] || [ "package.json" -nt "node_modules" ]; then + echo "[rebuild-frontend] package.json changed or node_modules missing — running npm install ..." + npm install + echo "[rebuild-frontend] npm install complete." +fi + npm run build echo "[rebuild-frontend] Build complete." diff --git a/tests/test_kin_122_regression.py b/tests/test_kin_122_regression.py new file mode 100644 index 0000000..c0cbea3 --- /dev/null +++ b/tests/test_kin_122_regression.py @@ -0,0 +1,86 @@ +""" +KIN-122 regression: rebuild-frontend.sh должен запускать npm install +перед npm run build, если package.json изменился (новее node_modules). +""" + +import os +import stat +from pathlib import Path + +SCRIPT_PATH = Path(__file__).parent.parent / "scripts" / "rebuild-frontend.sh" + + +class TestKIN122RebuildFrontendNpmInstall: + """Структурные тесты: скрипт содержит условный npm install перед npm run build.""" + + def test_script_exists(self): + assert SCRIPT_PATH.is_file(), f"rebuild-frontend.sh not found at {SCRIPT_PATH}" + + def test_script_is_executable(self): + mode = SCRIPT_PATH.stat().st_mode + assert mode & stat.S_IXUSR, "rebuild-frontend.sh должен быть исполняемым" + + def test_script_contains_npm_install_conditional(self): + """Скрипт должен содержать условный блок npm install (KIN-122).""" + content = SCRIPT_PATH.read_text() + assert "npm install" in content, ( + "rebuild-frontend.sh должен содержать 'npm install'" + ) + + def test_script_npm_install_guarded_by_condition(self): + """npm install должен быть внутри if-блока, а не вызываться безусловно.""" + content = SCRIPT_PATH.read_text() + lines = content.splitlines() + + # Найти строку с npm install + npm_install_line_idx = next( + (i for i, line in enumerate(lines) if "npm install" in line and "if" not in line), + None, + ) + assert npm_install_line_idx is not None, "Строка с 'npm install' не найдена" + + # Должен быть if-блок выше + preceding = "\n".join(lines[:npm_install_line_idx]) + assert "if" in preceding, ( + "npm install должен быть внутри условного блока" + ) + + def test_script_checks_node_modules_existence(self): + """Условие должно проверять наличие node_modules.""" + content = SCRIPT_PATH.read_text() + assert "node_modules" in content, ( + "Скрипт должен проверять наличие node_modules" + ) + + def test_script_checks_package_json_mtime(self): + """Условие должно сравнивать mtime package.json с node_modules (флаг -nt).""" + content = SCRIPT_PATH.read_text() + assert "-nt" in content, ( + "Скрипт должен использовать '-nt' для сравнения mtime package.json и node_modules" + ) + + def test_npm_install_before_npm_run_build(self): + """npm install должен стоять раньше npm run build в скрипте.""" + content = SCRIPT_PATH.read_text() + install_pos = content.find("npm install") + build_pos = content.find("npm run build") + assert install_pos != -1, "npm install не найден в скрипте" + assert build_pos != -1, "npm run build не найден в скрипте" + assert install_pos < build_pos, ( + "npm install должен стоять раньше npm run build" + ) + + def test_npm_run_build_always_runs(self): + """npm run build должен вызываться вне условного блока — всегда выполняется.""" + content = SCRIPT_PATH.read_text() + lines = content.splitlines() + + # Найти строку с npm run build (не внутри if-блока) + # Ищем строку, которая содержит "npm run build" и не является частью if-условия + build_lines = [ + line for line in lines + if "npm run build" in line and line.strip().startswith("npm run build") + ] + assert len(build_lines) >= 1, ( + "npm run build должен быть безусловным вызовом" + )