feat: 添加 WebUI 静态资源包提示和相关错误处理逻辑
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
@@ -10,54 +11,42 @@ def test_ensure_static_path_ready_uses_existing_static_path(tmp_path) -> None:
|
||||
static_path.mkdir()
|
||||
(static_path / "index.html").write_text("<html></html>", encoding="utf-8")
|
||||
|
||||
with (
|
||||
patch.object(webui_app, "_resolve_static_path", return_value=static_path),
|
||||
patch.object(webui_app, "_try_build_dashboard") as build_mock,
|
||||
):
|
||||
with patch.object(webui_app, "_resolve_static_path", return_value=static_path):
|
||||
result = webui_app._ensure_static_path_ready()
|
||||
|
||||
assert result == static_path
|
||||
build_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_ensure_static_path_ready_retries_after_auto_build(tmp_path) -> None:
|
||||
static_path = tmp_path / "dist"
|
||||
static_path.mkdir()
|
||||
(static_path / "index.html").write_text("<html></html>", encoding="utf-8")
|
||||
|
||||
with (
|
||||
patch.object(webui_app, "_resolve_static_path", side_effect=[None, static_path]),
|
||||
patch.object(
|
||||
webui_app,
|
||||
"_try_build_dashboard",
|
||||
return_value=webui_app.DashboardAutoRecoveryResult(succeeded=True),
|
||||
) as build_mock,
|
||||
):
|
||||
result = webui_app._ensure_static_path_ready()
|
||||
|
||||
assert result == static_path
|
||||
build_mock.assert_called_once_with()
|
||||
|
||||
|
||||
def test_ensure_static_path_ready_logs_manual_hint_when_auto_build_fails() -> None:
|
||||
def test_ensure_static_path_ready_logs_install_hint_when_static_assets_are_missing() -> None:
|
||||
with (
|
||||
patch.object(webui_app, "_resolve_static_path", return_value=None),
|
||||
patch.object(
|
||||
webui_app,
|
||||
"_try_build_dashboard",
|
||||
return_value=webui_app.DashboardAutoRecoveryResult(
|
||||
succeeded=False,
|
||||
manual_recovery_command=webui_app._MANUAL_BUILD_COMMAND,
|
||||
),
|
||||
),
|
||||
patch.object(webui_app.logger, "warning") as warning_mock,
|
||||
):
|
||||
result = webui_app._ensure_static_path_ready()
|
||||
|
||||
assert result is None
|
||||
warning_mock.assert_any_call(webui_app.t("startup.webui_auto_recovery_failed"))
|
||||
warning_mock.assert_any_call(webui_app.t("startup.webui_static_assets_unavailable"))
|
||||
warning_mock.assert_any_call(
|
||||
webui_app.t("startup.webui_manual_build_hint", command=webui_app._MANUAL_BUILD_COMMAND)
|
||||
webui_app.t("startup.webui_dashboard_package_hint", command=webui_app._MANUAL_INSTALL_COMMAND)
|
||||
)
|
||||
|
||||
|
||||
def test_ensure_static_path_ready_logs_index_error_when_static_path_is_invalid(tmp_path) -> None:
|
||||
static_path = tmp_path / "dist"
|
||||
static_path.mkdir()
|
||||
|
||||
with (
|
||||
patch.object(webui_app, "_resolve_static_path", return_value=static_path),
|
||||
patch.object(webui_app.logger, "warning") as warning_mock,
|
||||
):
|
||||
result = webui_app._ensure_static_path_ready()
|
||||
|
||||
assert result is None
|
||||
warning_mock.assert_any_call(
|
||||
webui_app.t("startup.webui_index_missing", index_path=static_path / "index.html")
|
||||
)
|
||||
warning_mock.assert_any_call(
|
||||
webui_app.t("startup.webui_dashboard_package_hint", command=webui_app._MANUAL_INSTALL_COMMAND)
|
||||
)
|
||||
|
||||
|
||||
@@ -73,43 +62,21 @@ def test_setup_static_files_does_not_duplicate_warning_when_static_path_is_unava
|
||||
warning_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_get_dashboard_build_command_defaults_to_npm(tmp_path) -> None:
|
||||
(tmp_path / "package.json").write_text("{}", encoding="utf-8")
|
||||
def test_resolve_static_path_prefers_installed_dashboard_package(monkeypatch, tmp_path) -> None:
|
||||
package_dist = tmp_path / "site-packages" / "maibot_dashboard" / "dist"
|
||||
package_dist.mkdir(parents=True)
|
||||
|
||||
with patch.object(
|
||||
webui_app.shutil,
|
||||
"which",
|
||||
side_effect=lambda tool_name: "/usr/bin/npm" if tool_name == "npm" else None,
|
||||
):
|
||||
command = webui_app._get_dashboard_build_command(tmp_path)
|
||||
class _DashboardModule:
|
||||
@staticmethod
|
||||
def get_dist_path() -> Path:
|
||||
return package_dist
|
||||
|
||||
assert command == ["npm", "run", "build"]
|
||||
monkeypatch.setattr(webui_app, "_get_project_root", lambda: tmp_path)
|
||||
|
||||
with patch.object(webui_app, "import_module", return_value=_DashboardModule()):
|
||||
resolved_path = webui_app._resolve_static_path()
|
||||
|
||||
def test_try_build_dashboard_installs_missing_dependencies_before_build(monkeypatch, tmp_path) -> None:
|
||||
(tmp_path / "package.json").write_text("{}", encoding="utf-8")
|
||||
run_results = [
|
||||
webui_app.CompletedProcess(args=["npm", "install", "--no-package-lock"], returncode=0, stdout="", stderr=""),
|
||||
webui_app.CompletedProcess(args=["npm", "run", "build"], returncode=0, stdout="", stderr=""),
|
||||
]
|
||||
|
||||
monkeypatch.setattr(webui_app, "_get_dashboard_root", lambda: tmp_path)
|
||||
monkeypatch.setattr(webui_app, "_should_auto_install_dashboard_dependencies", lambda dashboard_root: True)
|
||||
|
||||
with (
|
||||
patch.object(webui_app, "_get_dashboard_build_command", return_value=["npm", "run", "build"]),
|
||||
patch.object(webui_app, "run", side_effect=run_results) as run_mock,
|
||||
):
|
||||
result = webui_app._try_build_dashboard()
|
||||
|
||||
assert result.succeeded is True
|
||||
assert run_mock.call_count == 2
|
||||
install_call = run_mock.call_args_list[0]
|
||||
build_call = run_mock.call_args_list[1]
|
||||
assert install_call.args[0] == ["npm", "install", "--no-package-lock"]
|
||||
assert install_call.kwargs["cwd"] == tmp_path
|
||||
assert build_call.args[0] == ["npm", "run", "build"]
|
||||
assert build_call.kwargs["cwd"] == tmp_path
|
||||
assert resolved_path == package_dist
|
||||
|
||||
|
||||
def test_resolve_static_path_uses_dashboard_dist(monkeypatch, tmp_path) -> None:
|
||||
|
||||
Reference in New Issue
Block a user