feat: prepare 2.2.0 with UI and execution fixes
Add dark theme, richer Markdown and readable plugin results. Improve Android input evidence, response integrity and diagnostics. Unify lifecycle, guidance receipts and evidence sources across clients. Keep direct action dispatch without an added AI quota approval layer. Align version metadata at 2.2.0 and bundle Helper 1.2.2. Validation: 3063 backend tests before the version bump; 44 after. Frontend: 317 tests and production build passed.
This commit is contained in:
1 parent
83bcfd54d5
commit
fac4ccb760
146 files changed
+5689
-2033
No files matched your search
@@ -361,7 +361,7 @@ async def test_launch_app_failure_when_top_task_is_another_app(
|
||||
assert success is False
|
||||
assert f"Failed to launch {SETTINGS}" in error_msg
|
||||
assert mock_controller.launch_app.call_count == 2
|
||||
assert mock_controller.terminate_app.call_count == 1
|
||||
mock_controller.terminate_app.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -399,12 +399,13 @@ async def test_launch_timeout_message_names_foreground_package_and_task(
|
||||
@patch("artemis.utils.app_launch_utils.get_foreground_task")
|
||||
@patch("artemis.utils.app_launch_utils.UnifiedMobileController")
|
||||
@patch("artemis.utils.app_launch_utils.get_current_foreground_package_async")
|
||||
async def test_launch_app_null_focus_keeps_polling_without_reading_task(
|
||||
async def test_launch_app_null_focus_without_task_evidence_keeps_polling(
|
||||
mock_get_foreground, mock_controller_cls, mock_get_task, mock_context
|
||||
):
|
||||
"""mCurrentFocus=null is a loading state: no task lookup, then success once focused."""
|
||||
"""Unknown focus and task state remain loading until a focused window appears."""
|
||||
_controller(mock_controller_cls)
|
||||
mock_get_foreground.side_effect = [None, None, YOUTUBE]
|
||||
mock_get_task.return_value = None
|
||||
|
||||
success, error_msg = await launch_app_with_retries(
|
||||
mock_context, YOUTUBE, max_retries=1, max_poll_seconds=3
|
||||
@@ -412,7 +413,67 @@ async def test_launch_app_null_focus_keeps_polling_without_reading_task(
|
||||
|
||||
assert success is True
|
||||
assert error_msg is None
|
||||
mock_get_task.assert_not_called()
|
||||
assert mock_get_task.call_count == 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"dump, ready",
|
||||
[
|
||||
(DUMP_SETTINGS_TASK_WITH_SEARCH_ON_TOP, True),
|
||||
(DUMP_NO_RESUMED, False),
|
||||
(DUMP_HOME, False),
|
||||
("", False),
|
||||
],
|
||||
ids=["resumed-app", "visible-only", "other-app", "unknown"],
|
||||
)
|
||||
async def test_null_focus_requires_resumed_foreground_task_evidence(mock_context, dump, ready):
|
||||
with (
|
||||
patch("artemis.utils.app_launch_utils.UnifiedMobileController") as controller_cls,
|
||||
patch(
|
||||
"artemis.utils.app_launch_utils.get_current_foreground_package_async",
|
||||
new_callable=AsyncMock,
|
||||
return_value=None,
|
||||
),
|
||||
patch(
|
||||
"artemis.utils.app_launch_utils.get_foreground_task",
|
||||
return_value=parse_foreground_task(dump),
|
||||
),
|
||||
patch("artemis.utils.app_launch_utils.asyncio.sleep", new_callable=AsyncMock),
|
||||
):
|
||||
controller = _controller(controller_cls)
|
||||
success, detail = await launch_app_with_retries(
|
||||
mock_context, SETTINGS, max_retries=2, max_poll_seconds=1
|
||||
)
|
||||
assert success is ready
|
||||
if ready:
|
||||
assert detail is None
|
||||
controller.launch_app.assert_awaited_once_with(SETTINGS)
|
||||
else:
|
||||
assert "Current foreground: None" in detail
|
||||
assert controller.launch_app.await_count == 2
|
||||
controller.terminate_app.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_initial_launch_skips_relaunch_with_null_focus_and_resumed_app_task(mock_context):
|
||||
with (
|
||||
patch(
|
||||
"artemis.utils.app_launch_utils.get_current_foreground_package_async",
|
||||
new_callable=AsyncMock,
|
||||
return_value=None,
|
||||
),
|
||||
patch(
|
||||
"artemis.utils.app_launch_utils.get_foreground_task",
|
||||
return_value=parse_foreground_task(DUMP_SETTINGS_TASK_WITH_SEARCH_ON_TOP),
|
||||
),
|
||||
patch(
|
||||
"artemis.utils.app_launch_utils.launch_app_with_retries", new_callable=AsyncMock
|
||||
) as launch,
|
||||
):
|
||||
result = await _handle_initial_app_launch(mock_context, SETTINGS)
|
||||
assert result.locked_app_initial_launch_success is True
|
||||
launch.assert_not_awaited()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -467,6 +528,7 @@ async def test_transient_launch_failure_is_bounded_and_keeps_cause(mock_context)
|
||||
assert result is False
|
||||
assert detail == "device offline"
|
||||
assert controller.launch_app.await_count == 3
|
||||
controller.terminate_app.assert_not_called()
|
||||
poll.assert_not_called()
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user