Files
raycast-api/tests/test_live_app.py
T

80 lines
2.5 KiB
Python

"""Integration tests against the real Raycast.app, if present.
These tests are gated on `RAYCAST_APP_PATH` (or, as a developer convenience,
the `Raycast Beta.app` sitting next to the repo). They prove that discovery
gives us the same signing_secret HANDOFF.md documents — i.e. that the AST
patterns we match against survive on the actual minified bundle, not just the
synthetic fixture.
Skipped automatically if no app is found, so CI without an .app stays green.
"""
from __future__ import annotations
import os
from pathlib import Path
import pytest
from raycast_api.config import Config
EXPECTED_SECRET = "6bc455473576ce2cd6f70426caff867aabbe3f7291c1a79681af5e8ce0ca1408"
def _app_path() -> Path | None:
env = os.environ.get("RAYCAST_APP_PATH")
candidates: list[Path] = []
if env:
candidates.append(Path(env))
candidates.extend(
[
Path(__file__).resolve().parents[2] / "Raycast Beta.app",
Path("/Applications/Raycast Beta.app"),
Path("/Applications/Raycast.app"),
]
)
for p in candidates:
if p.is_dir():
return p
return None
pytestmark = pytest.mark.local_app
@pytest.fixture
def real_app() -> Path:
app = _app_path()
if app is None:
pytest.skip("No local Raycast.app found (set RAYCAST_APP_PATH to override)")
raise AssertionError("unreachable")
return app
def test_discover_secret(real_app: Path, isolated_cache: Path) -> None:
cfg = Config.discover_from_app(real_app)
assert len(cfg.signature_secret) == 64
assert all(c in "0123456789abcdef" for c in cfg.signature_secret)
if cfg.signature_secret != EXPECTED_SECRET:
pytest.skip(
f"Local Raycast secret ({cfg.signature_secret[-8:]}) doesn't match HANDOFF "
f"({EXPECTED_SECRET[-8:]}) — likely a different Raycast version. Discovery shape OK."
)
def test_discover_signing_spec_shape(real_app: Path, isolated_cache: Path) -> None:
cfg = Config.discover_from_app(real_app)
spec = cfg.signing_spec
assert spec.join_char == "."
assert spec.body_hash_algorithm == "SHA-256"
assert spec.hmac_algorithm == "SHA-256"
assert spec.key_encoding == "utf-8"
ranges = {(r.start, r.end, r.shift) for r in spec.rot_ranges}
assert ranges == {(65, 90, 13), (97, 122, 13), (48, 57, 5)}
def test_app_version_and_ua(real_app: Path, isolated_cache: Path) -> None:
cfg = Config.discover_from_app(real_app)
assert cfg.app_version
assert cfg.user_agent.startswith(f"Raycast/{cfg.app_version} (x-macOS Version ")