2026-05-12 21:34:14 -07:00
|
|
|
import subprocess
|
|
|
|
|
import sys
|
test(cli, download): add 17 gap-coverage tests for Phase 7
CLI: clear-cache (existing + missing), path (ok + error), fetch happy
path, no/unknown subcommand error paths. Calls cli.main() directly
instead of subprocess to keep tests fast and capture stderr cleanly.
Download: cache hit skips HTTP, tar.gz extraction, comment/blank
checksum lines, unknown archive format, missing entry after extract,
unsupported platform. Also covers pure helpers _parse_owner_repo,
_sha256_file, and _github_token env precedence.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 12:35:57 +02:00
|
|
|
from pathlib import Path
|
2026-05-12 21:34:14 -07:00
|
|
|
|
2026-05-14 11:21:10 +02:00
|
|
|
import pytest
|
2026-05-12 21:34:14 -07:00
|
|
|
|
test(cli, download): add 17 gap-coverage tests for Phase 7
CLI: clear-cache (existing + missing), path (ok + error), fetch happy
path, no/unknown subcommand error paths. Calls cli.main() directly
instead of subprocess to keep tests fast and capture stderr cleanly.
Download: cache hit skips HTTP, tar.gz extraction, comment/blank
checksum lines, unknown archive format, missing entry after extract,
unsupported platform. Also covers pure helpers _parse_owner_repo,
_sha256_file, and _github_token env precedence.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 12:35:57 +02:00
|
|
|
from invisible_playwright import cli
|
|
|
|
|
|
2026-05-14 11:21:10 +02:00
|
|
|
|
|
|
|
|
@pytest.mark.unit
|
2026-05-12 21:34:14 -07:00
|
|
|
def test_version_subcommand():
|
|
|
|
|
r = subprocess.run(
|
2026-05-14 11:21:10 +02:00
|
|
|
[sys.executable, "-m", "invisible_playwright", "version"],
|
2026-05-12 21:34:14 -07:00
|
|
|
capture_output=True, text=True, check=True,
|
|
|
|
|
)
|
|
|
|
|
assert "firefox-" in r.stdout
|
2026-05-14 11:21:10 +02:00
|
|
|
assert "invisible_playwright" in r.stdout.lower()
|
2026-05-12 21:34:14 -07:00
|
|
|
|
|
|
|
|
|
2026-05-14 11:21:10 +02:00
|
|
|
@pytest.mark.unit
|
2026-05-12 21:34:14 -07:00
|
|
|
def test_help_subcommand():
|
|
|
|
|
r = subprocess.run(
|
2026-05-14 11:21:10 +02:00
|
|
|
[sys.executable, "-m", "invisible_playwright", "--help"],
|
2026-05-12 21:34:14 -07:00
|
|
|
capture_output=True, text=True,
|
|
|
|
|
)
|
|
|
|
|
assert r.returncode == 0
|
|
|
|
|
assert "fetch" in r.stdout
|
|
|
|
|
assert "path" in r.stdout
|
|
|
|
|
assert "clear-cache" in r.stdout
|
test(cli, download): add 17 gap-coverage tests for Phase 7
CLI: clear-cache (existing + missing), path (ok + error), fetch happy
path, no/unknown subcommand error paths. Calls cli.main() directly
instead of subprocess to keep tests fast and capture stderr cleanly.
Download: cache hit skips HTTP, tar.gz extraction, comment/blank
checksum lines, unknown archive format, missing entry after extract,
unsupported platform. Also covers pure helpers _parse_owner_repo,
_sha256_file, and _github_token env precedence.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 12:35:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
# CL1: clear-cache with existing cache prints "removed:" + path
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
def test_clear_cache_with_existing_cache(tmp_path, monkeypatch, capsys):
|
|
|
|
|
cache = tmp_path / "existing-cache"
|
|
|
|
|
cache.mkdir()
|
|
|
|
|
(cache / "marker").write_text("x")
|
|
|
|
|
monkeypatch.setattr("invisible_playwright.cli.cache_root", lambda: cache)
|
|
|
|
|
|
|
|
|
|
rc = cli.main(["clear-cache"])
|
|
|
|
|
|
|
|
|
|
captured = capsys.readouterr()
|
|
|
|
|
assert rc == 0
|
|
|
|
|
assert captured.out.startswith("removed:")
|
|
|
|
|
assert str(cache) in captured.out
|
|
|
|
|
assert not cache.exists()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# CL2: clear-cache with no cache prints "nothing to remove:"
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
def test_clear_cache_with_no_cache(tmp_path, monkeypatch, capsys):
|
|
|
|
|
cache = tmp_path / "missing-cache"
|
|
|
|
|
assert not cache.exists()
|
|
|
|
|
monkeypatch.setattr("invisible_playwright.cli.cache_root", lambda: cache)
|
|
|
|
|
|
|
|
|
|
rc = cli.main(["clear-cache"])
|
|
|
|
|
|
|
|
|
|
captured = capsys.readouterr()
|
|
|
|
|
assert rc == 0
|
|
|
|
|
assert captured.out.startswith("nothing to remove:")
|
|
|
|
|
assert str(cache) in captured.out
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# CL3: path when binary exists prints path, exit 0
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
def test_path_subcommand_when_binary_exists(tmp_path, monkeypatch, capsys):
|
|
|
|
|
fake_binary = tmp_path / "firefox.exe"
|
|
|
|
|
fake_binary.write_text("x")
|
|
|
|
|
monkeypatch.setattr("invisible_playwright.cli.ensure_binary", lambda: fake_binary)
|
|
|
|
|
|
|
|
|
|
rc = cli.main(["path"])
|
|
|
|
|
|
|
|
|
|
captured = capsys.readouterr()
|
|
|
|
|
assert rc == 0
|
|
|
|
|
assert str(fake_binary) in captured.out
|
|
|
|
|
assert captured.err == ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# CL4: path when binary missing prints to stderr, exit 1
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
def test_path_subcommand_when_binary_missing(monkeypatch, capsys):
|
|
|
|
|
def boom():
|
|
|
|
|
raise RuntimeError("download failed")
|
|
|
|
|
monkeypatch.setattr("invisible_playwright.cli.ensure_binary", boom)
|
|
|
|
|
|
|
|
|
|
rc = cli.main(["path"])
|
|
|
|
|
|
|
|
|
|
captured = capsys.readouterr()
|
|
|
|
|
assert rc == 1
|
|
|
|
|
assert "error:" in captured.err
|
|
|
|
|
assert "download failed" in captured.err
|
|
|
|
|
assert captured.out == ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# CL5: no subcommand → argparse error, exit != 0
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
def test_no_subcommand_errors():
|
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
|
|
|
cli.main([])
|
|
|
|
|
assert exc_info.value.code != 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# CL6: unknown subcommand → argparse error
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
def test_unknown_subcommand_errors():
|
|
|
|
|
with pytest.raises(SystemExit) as exc_info:
|
|
|
|
|
cli.main(["bogus"])
|
|
|
|
|
assert exc_info.value.code != 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Extra: fetch happy path with mocked ensure_binary
|
|
|
|
|
@pytest.mark.unit
|
|
|
|
|
def test_fetch_subcommand_prints_path(tmp_path, monkeypatch, capsys):
|
|
|
|
|
fake_binary = tmp_path / "firefox.exe"
|
|
|
|
|
fake_binary.write_text("x")
|
|
|
|
|
monkeypatch.setattr("invisible_playwright.cli.ensure_binary", lambda: fake_binary)
|
|
|
|
|
|
|
|
|
|
rc = cli.main(["fetch"])
|
|
|
|
|
|
|
|
|
|
captured = capsys.readouterr()
|
|
|
|
|
assert rc == 0
|
|
|
|
|
assert str(fake_binary) in captured.out
|