"""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 ")