09e9f3545f
Test / Code Quality (push) Has been cancelled
Test / Test (macos-latest, Python 3.10) (push) Has been cancelled
Test / Test (macos-latest, Python 3.11) (push) Has been cancelled
Test / Test (macos-latest, Python 3.12) (push) Has been cancelled
Test / Test (macos-latest, Python 3.13) (push) Has been cancelled
Test / Test (macos-latest, Python 3.14) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.10) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.11) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.12) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.13) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.14) (push) Has been cancelled
Test / Test (windows-latest, Python 3.10) (push) Has been cancelled
Test / Test (windows-latest, Python 3.11) (push) Has been cancelled
Test / Test (windows-latest, Python 3.12) (push) Has been cancelled
Test / Test (windows-latest, Python 3.13) (push) Has been cancelled
Test / Test (windows-latest, Python 3.14) (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
dependency-audit / pip-audit (push) Has been cancelled
77 lines
3.0 KiB
Python
77 lines
3.0 KiB
Python
"""Cassette-backed coverage for the unified ``client.mind_maps`` API (#1256).
|
|
|
|
Exercises the new interactive (studio-artifact) path end-to-end against real
|
|
recorded wire data: ``mind_maps.list()`` recognizes the interactive mind map
|
|
(``LIST_ARTIFACTS`` + ``GET_NOTES_AND_MIND_MAPS``) and ``mind_maps.get_tree(...)``
|
|
reads its node tree via ``GET_INTERACTIVE_HTML`` (the tree lives at ``[0][9][3]``).
|
|
|
|
Recording
|
|
---------
|
|
Uses an existing notebook that already contains an interactive mind map (no
|
|
mutation, minimal cassette). To re-record::
|
|
|
|
export NOTEBOOKLM_MINDMAP_NOTEBOOK_ID=f7d1e2b6-2334-4016-b81d-aded7b3fa9b6
|
|
export NOTEBOOKLM_VCR_RECORD=1
|
|
uv run pytest tests/integration/test_mind_maps_vcr.py -v
|
|
|
|
After recording, re-run the repo's cassette sanitizer (cookies/tokens) — the
|
|
interactive HTML blob at ``[0][9][0]`` is stubbed to keep the cassette small;
|
|
only the ``[0][9][3]`` tree is needed for replay.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from notebooklm import NotebookLMClient
|
|
from notebooklm.rpc.types import RPCMethod
|
|
from notebooklm.types import MindMapKind
|
|
from tests.integration.conftest import get_vcr_auth, skip_no_cassettes
|
|
from tests.vcr_config import notebooklm_vcr
|
|
|
|
pytestmark = [pytest.mark.vcr, skip_no_cassettes]
|
|
|
|
NOTEBOOK_ID = os.environ.get(
|
|
"NOTEBOOKLM_MINDMAP_NOTEBOOK_ID",
|
|
"f7d1e2b6-2334-4016-b81d-aded7b3fa9b6",
|
|
)
|
|
|
|
CASSETTE_NAME = "mind_maps_interactive.yaml"
|
|
CASSETTE_PATH = Path(__file__).parent.parent / "cassettes" / CASSETTE_NAME
|
|
|
|
|
|
class TestMindMapsInteractive:
|
|
@pytest.mark.vcr
|
|
@pytest.mark.asyncio
|
|
@notebooklm_vcr.use_cassette(CASSETTE_NAME)
|
|
async def test_list_recognizes_and_reads_interactive_mind_map(self) -> None:
|
|
auth = await get_vcr_auth()
|
|
async with NotebookLMClient(auth) as client:
|
|
maps = await client.mind_maps.list(NOTEBOOK_ID)
|
|
interactive = [m for m in maps if m.kind == MindMapKind.INTERACTIVE]
|
|
assert interactive, "expected at least one interactive mind map in the notebook"
|
|
|
|
tree = await client.mind_maps.get_tree(
|
|
NOTEBOOK_ID, interactive[0].id, kind=MindMapKind.INTERACTIVE
|
|
)
|
|
|
|
assert isinstance(tree, dict)
|
|
assert "children" in tree or "nodes" in tree, f"missing tree keys: {list(tree)[:5]}"
|
|
|
|
def test_cassette_records_interactive_rpcs(self) -> None:
|
|
"""The cassette must include the LIST_ARTIFACTS + GET_INTERACTIVE_HTML RPCs."""
|
|
import yaml
|
|
|
|
assert CASSETTE_PATH.exists(), (
|
|
f"cassette missing: {CASSETTE_PATH}. Re-record with NOTEBOOKLM_VCR_RECORD=1."
|
|
)
|
|
data = yaml.safe_load(CASSETTE_PATH.read_text())
|
|
uris = " ".join(i["request"]["uri"] for i in data["interactions"])
|
|
# Reference the method-ID source of truth so re-recording with changed
|
|
# RPC IDs can't silently make these assertions tautological.
|
|
assert RPCMethod.LIST_ARTIFACTS.value in uris
|
|
assert RPCMethod.GET_INTERACTIVE_HTML.value in uris
|