Skip to content

Commit 163d4ca

Browse files
committed
test(cli): add integration coverage for source delete flows
1 parent 077bd65 commit 163d4ca

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

tests/integration/cli_vcr/test_sources.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,23 @@ def test_source_content(self, runner, mock_auth_for_vcr, mock_context, command,
7878
with notebooklm_vcr.use_cassette(cassette):
7979
result = runner.invoke(cli, ["source", command, "test_source_id"])
8080
assert_command_success(result)
81+
82+
83+
class TestSourceDeleteCommand:
84+
"""Test delete command paths that can reuse existing VCR coverage."""
85+
86+
@notebooklm_vcr.use_cassette("sources_delete.yaml")
87+
def test_source_delete_full_uuid(self, runner, mock_auth_for_vcr, mock_context):
88+
"""Delete source by full UUID works with real client."""
89+
result = runner.invoke(
90+
cli,
91+
[
92+
"source",
93+
"delete",
94+
"ff503bfa-5e39-4281-a1d8-2a66c7b86724",
95+
"-n",
96+
"06f0c5bd-108f-4c8b-8911-34b2acc656de",
97+
"-y",
98+
],
99+
)
100+
assert_command_success(result, allow_no_context=False)
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
"""Integration tests for source delete CLI flows."""
2+
3+
import json
4+
from pathlib import Path
5+
from unittest.mock import AsyncMock, patch
6+
7+
import pytest
8+
from click.testing import CliRunner
9+
from pytest_httpx import HTTPXMock
10+
11+
from notebooklm.notebooklm_cli import cli
12+
from notebooklm.rpc import RPCMethod
13+
14+
15+
@pytest.fixture
16+
def runner() -> CliRunner:
17+
"""Create a Click test runner."""
18+
return CliRunner()
19+
20+
21+
@pytest.fixture
22+
def mock_auth():
23+
"""Mock authentication for CLI integration tests."""
24+
with (
25+
patch(
26+
"notebooklm.cli.helpers.load_auth_from_storage",
27+
return_value={
28+
"SID": "test",
29+
"HSID": "test",
30+
"SSID": "test",
31+
"APISID": "test",
32+
"SAPISID": "test",
33+
},
34+
),
35+
patch("notebooklm.cli.helpers.fetch_tokens", new_callable=AsyncMock) as mock_fetch,
36+
):
37+
mock_fetch.return_value = ("csrf_token", "session_id")
38+
yield
39+
40+
41+
@pytest.fixture
42+
def mock_context(tmp_path: Path):
43+
"""Provide a canonical notebook UUID so CLI skips notebook-list resolution."""
44+
context_file = tmp_path / "context.json"
45+
context_file.write_text(
46+
json.dumps({"notebook_id": "06f0c5bd-108f-4c8b-8911-34b2acc656de"}),
47+
encoding="utf-8",
48+
)
49+
50+
with patch("notebooklm.cli.helpers.get_context_path", return_value=context_file):
51+
yield context_file
52+
53+
54+
def _build_source_list_response(build_rpc_response, source_id: str, title: str) -> str:
55+
"""Build a GET_NOTEBOOK response containing a single source."""
56+
return build_rpc_response(
57+
RPCMethod.GET_NOTEBOOK,
58+
[
59+
[
60+
"Test Notebook",
61+
[
62+
[
63+
[source_id],
64+
title,
65+
[None, 11, [1704067200, 0], None, 5, None, None, None],
66+
[None, 2],
67+
]
68+
],
69+
"06f0c5bd-108f-4c8b-8911-34b2acc656de",
70+
"📘",
71+
None,
72+
[None, None, None, None, None, [1704067200, 0]],
73+
]
74+
],
75+
)
76+
77+
78+
class TestCliSourceDeleteIntegration:
79+
"""Integration coverage for CLI source delete flows."""
80+
81+
def test_source_delete_by_title(
82+
self, runner, mock_auth, mock_context, httpx_mock: HTTPXMock, build_rpc_response
83+
):
84+
httpx_mock.add_response(
85+
content=_build_source_list_response(
86+
build_rpc_response,
87+
"ff503bfa-5e39-4281-a1d8-2a66c7b86724",
88+
"VCR Delete Test Source",
89+
).encode()
90+
)
91+
httpx_mock.add_response(
92+
content=build_rpc_response(RPCMethod.DELETE_SOURCE, [True]).encode()
93+
)
94+
95+
result = runner.invoke(
96+
cli,
97+
["source", "delete-by-title", "VCR Delete Test Source", "-y"],
98+
)
99+
100+
assert result.exit_code == 0
101+
assert "Deleted source" in result.output
102+
103+
def test_source_delete_title_suggests_delete_by_title(
104+
self, runner, mock_auth, mock_context, httpx_mock: HTTPXMock, build_rpc_response
105+
):
106+
httpx_mock.add_response(
107+
content=_build_source_list_response(
108+
build_rpc_response,
109+
"ff503bfa-5e39-4281-a1d8-2a66c7b86724",
110+
"VCR Delete Test Source",
111+
).encode()
112+
)
113+
114+
result = runner.invoke(
115+
cli,
116+
["source", "delete", "VCR Delete Test Source", "-y"],
117+
)
118+
119+
assert result.exit_code == 1
120+
assert "delete-by-title" in result.output

0 commit comments

Comments
 (0)