import pytest from unittest.mock import AsyncMock, patch # Assuming there's an API client that the CLI uses # For integration tests, we want to mock the backend API responses, # but not the internal workings of the CLI's API client itself. # We'll mock the `post` method of the API client. # A simple mock for the API client's post method class MockApiClient: def __init__(self): self.responses = [] self.call_count = 0 async def post(self, url, json): self.call_count += 1 if self.responses: return self.responses.pop(0) # Default response if no specific mock is set return {"success": False, "error": "No mock response set"} @pytest.fixture def mock_api_client(): return MockApiClient() @pytest.mark.asyncio async def test_complete_mfa_flow(mock_api_client): # Simulate a scenario where initial login requires MFA mock_api_client.responses = [ # First response: MFA required {"success": False, "mfa_required": True, "mfa_challenge_id": "challenge123", "mfa_type": "sms"}, # Second response: MFA completed successfully {"success": True, "session_id": "session456", "access_token": "token789", "expires_in": 3600} ] # Mock the api_client in cli/src/api_client.py with patch('src.api_client.client', new=mock_api_client): # This part assumes a function in the CLI main that handles the auth flow # For now, let's just directly call the mock client to simulate the interaction # Later, this would be replaced by calling the actual CLI authentication logic. # Step 1: Initiate authentication (CLI would call api_client.post) init_resp = await mock_api_client.post("/api/garmin/login", json={"username": "mfa_user", "password": "pass"}) assert init_resp["mfa_required"] == True assert "mfa_challenge_id" in init_resp assert init_resp["mfa_type"] == "sms" # Simulate user entering MFA code mfa_code = "123456" # input(f"Enter {init_resp['mfa_type']} code: ") # Step 2: Complete MFA (CLI would call api_client.post again, likely to a different endpoint) # The quickstart mentioned "/api/garmin/login/mfa-complete", # but for this integration test, let's keep it simple and just use the same mock. # The important part is the *sequence* of calls and responses. completion_payload = { "mfa_code": mfa_code, "challenge_id": init_resp["mfa_challenge_id"] } mfa_resp = await mock_api_client.post("/api/garmin/login/mfa-complete", json=completion_payload) assert mfa_resp["success"] == True assert "access_token" in mfa_resp assert mock_api_client.call_count == 2