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
94 lines
4.6 KiB
Python
94 lines
4.6 KiB
Python
"""CLI integration tests for settings commands.
|
|
|
|
Extends the CLI VCR coverage to the global language / settings surface.
|
|
The canonical command in this repo is ``notebooklm
|
|
language set <code>`` (registered as the ``language`` group with ``set``
|
|
subcommand; see ``src/notebooklm/cli/language_cmd.py``). The task brief uses
|
|
the conceptual name ``settings set-language``; the test exercises the
|
|
real exposed name without touching the CLI implementation.
|
|
|
|
The CLI ``language set <code>`` flow (server-authoritative since #1309):
|
|
|
|
1. Validates ``<code>`` against the local ``SUPPORTED_LANGUAGES`` table.
|
|
2. Unless ``--local`` is passed, calls
|
|
``client.settings.set_output_language(<code>)`` — a single
|
|
``SET_USER_SETTINGS`` (rpcids ``hT54vc``) RPC — routed through the standard
|
|
error envelope so a failed sync hard-fails instead of silently degrading.
|
|
3. Writes the language to ``config.json`` only after the server confirms
|
|
(or immediately, with no RPC, when ``--local`` is passed).
|
|
|
|
The dedicated CLI cassette ``cli_settings_set_language.yaml`` captures
|
|
exactly that single-RPC chain (plus the bootstrap homepage GET). It is
|
|
NOT the same as the existing ``settings_set_output_language.yaml``
|
|
cassette, which carries an additional ``GET_USER_SETTINGS`` preflight and
|
|
a second ``SET_USER_SETTINGS`` to restore the original language — neither
|
|
of which the CLI emits.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from notebooklm.notebooklm_cli import cli
|
|
|
|
from .conftest import assert_command_success, notebooklm_vcr, parse_json_output, skip_no_cassettes
|
|
|
|
pytestmark = [pytest.mark.vcr, skip_no_cassettes]
|
|
|
|
|
|
class TestLanguageSetCommand:
|
|
"""Test ``notebooklm language set <code>``."""
|
|
|
|
def test_language_set(self, runner, mock_auth_for_vcr, tmp_path, monkeypatch):
|
|
"""``language set en`` writes locally and syncs the single SET RPC.
|
|
|
|
Redirects ``NOTEBOOKLM_HOME`` to ``tmp_path`` so the test never touches
|
|
the real user's ``~/.notebooklm/config.json``. ``get_home_dir`` honors
|
|
``$NOTEBOOKLM_HOME`` first; using ``HOME`` would be a no-op on Windows
|
|
where ``Path.home()`` consults ``%USERPROFILE%`` instead.
|
|
"""
|
|
monkeypatch.setenv("NOTEBOOKLM_HOME", str(tmp_path))
|
|
with notebooklm_vcr.use_cassette("cli_settings_set_language.yaml"):
|
|
result = runner.invoke(cli, ["language", "set", "en"])
|
|
assert_command_success(result, allow_no_context=False)
|
|
|
|
# The local config should now hold the chosen language.
|
|
config_path = tmp_path / "config.json"
|
|
assert config_path.exists(), "language set must persist config.json locally"
|
|
import json as _json
|
|
|
|
config = _json.loads(config_path.read_text(encoding="utf-8"))
|
|
assert config.get("language") == "en"
|
|
|
|
def test_language_set_json(self, runner, mock_auth_for_vcr, tmp_path, monkeypatch):
|
|
"""``language set en --json`` emits machine-readable success payload."""
|
|
monkeypatch.setenv("NOTEBOOKLM_HOME", str(tmp_path))
|
|
with notebooklm_vcr.use_cassette("cli_settings_set_language.yaml"):
|
|
result = runner.invoke(cli, ["language", "set", "en", "--json"])
|
|
assert_command_success(result, allow_no_context=False)
|
|
|
|
data = parse_json_output(result.output)
|
|
assert isinstance(data, dict), f"Expected JSON object, got: {result.output!r}"
|
|
assert data.get("language") == "en"
|
|
# ``synced_to_server`` is True when the RPC returned a value;
|
|
# the cassette response carries one so this should be True.
|
|
assert data.get("synced_to_server") is True
|
|
|
|
def test_language_set_local_skips_rpc(self, runner, mock_auth_for_vcr, tmp_path, monkeypatch):
|
|
"""``--local`` skips the server sync — no cassette needed.
|
|
|
|
This is the negative-VCR control: with ``--local`` the command MUST
|
|
NOT make any RPC, so we deliberately avoid loading a cassette. If the
|
|
command ever regresses and tries to sync, VCR (in ``record_mode="none"``)
|
|
will raise on the unmatched POST, failing the test loudly.
|
|
"""
|
|
monkeypatch.setenv("NOTEBOOKLM_HOME", str(tmp_path))
|
|
# No ``with notebooklm_vcr.use_cassette(...):`` — any HTTP traffic here
|
|
# is a regression. CliRunner traps the exception and surfaces it via
|
|
# ``result.exception`` / non-zero exit code.
|
|
result = runner.invoke(cli, ["language", "set", "ja", "--local", "--json"])
|
|
assert_command_success(result, allow_no_context=False)
|
|
|
|
data = parse_json_output(result.output)
|
|
assert isinstance(data, dict)
|
|
assert data.get("language") == "ja"
|
|
assert data.get("synced_to_server") is False
|