mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-03-22 05:37:20 +08:00
fix: add missing type hints and improve test logging (#12810)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from json_repair import repair_json
|
||||
from litellm.types.utils import ModelResponse
|
||||
@@ -32,7 +33,7 @@ class OpenHandsJSONEncoder(json.JSONEncoder):
|
||||
_json_encoder = OpenHandsJSONEncoder()
|
||||
|
||||
|
||||
def dumps(obj, **kwargs):
|
||||
def dumps(obj, **kwargs) -> str:
|
||||
"""Serialize an object to str format"""
|
||||
if not kwargs:
|
||||
return _json_encoder.encode(obj)
|
||||
@@ -47,7 +48,7 @@ def dumps(obj, **kwargs):
|
||||
return json.dumps(obj, **encoder_kwargs)
|
||||
|
||||
|
||||
def loads(json_str, **kwargs):
|
||||
def loads(json_str: str, **kwargs) -> Any:
|
||||
"""Create a JSON object from str"""
|
||||
try:
|
||||
return json.loads(json_str, **kwargs)
|
||||
|
||||
@@ -6,10 +6,13 @@ then ensures the GitHub token is set in Settings → Integrations and that the
|
||||
home screen shows the repository selector.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
from playwright.sync_api import Page, expect
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_github_token_configuration(page: Page, base_url: str):
|
||||
"""
|
||||
@@ -28,51 +31,51 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
base_url = 'http://localhost:12000'
|
||||
|
||||
# Navigate to the OpenHands application
|
||||
print(f'Step 1: Navigating to OpenHands application at {base_url}...')
|
||||
logger.info(f'Step 1: Navigating to OpenHands application at {base_url}...')
|
||||
page.goto(base_url)
|
||||
page.wait_for_load_state('networkidle', timeout=30000)
|
||||
|
||||
# Take initial screenshot
|
||||
page.screenshot(path='test-results/token_01_initial_load.png')
|
||||
print('Screenshot saved: token_01_initial_load.png')
|
||||
logger.info('Screenshot saved: token_01_initial_load.png')
|
||||
|
||||
# Step 1.5: Handle any initial modals that might appear (LLM API key configuration)
|
||||
try:
|
||||
# Check for AI Provider Configuration modal
|
||||
config_modal = page.locator('text=AI Provider Configuration')
|
||||
if config_modal.is_visible(timeout=5000):
|
||||
print('AI Provider Configuration modal detected')
|
||||
logger.info('AI Provider Configuration modal detected')
|
||||
|
||||
# Fill in the LLM API key if available
|
||||
llm_api_key_input = page.locator('[data-testid="llm-api-key-input"]')
|
||||
if llm_api_key_input.is_visible(timeout=3000):
|
||||
llm_api_key = os.getenv('LLM_API_KEY', 'test-key')
|
||||
llm_api_key_input.fill(llm_api_key)
|
||||
print(f'Filled LLM API key (length: {len(llm_api_key)})')
|
||||
logger.info(f'Filled LLM API key (length: {len(llm_api_key)})')
|
||||
|
||||
# Click the Save button
|
||||
save_button = page.locator('button:has-text("Save")')
|
||||
if save_button.is_visible(timeout=3000):
|
||||
save_button.click()
|
||||
page.wait_for_timeout(2000)
|
||||
print('Saved LLM API key configuration')
|
||||
logger.info('Saved LLM API key configuration')
|
||||
|
||||
# Check for Privacy Preferences modal
|
||||
privacy_modal = page.locator('text=Your Privacy Preferences')
|
||||
if privacy_modal.is_visible(timeout=5000):
|
||||
print('Privacy Preferences modal detected')
|
||||
logger.info('Privacy Preferences modal detected')
|
||||
confirm_button = page.locator('button:has-text("Confirm Preferences")')
|
||||
if confirm_button.is_visible(timeout=3000):
|
||||
confirm_button.click()
|
||||
page.wait_for_timeout(2000)
|
||||
print('Confirmed privacy preferences')
|
||||
logger.info('Confirmed privacy preferences')
|
||||
except Exception as e:
|
||||
print(f'Error handling initial modals: {e}')
|
||||
logger.error(f'Error handling initial modals: {e}')
|
||||
page.screenshot(path='test-results/token_01_5_modal_error.png')
|
||||
print('Screenshot saved: token_01_5_modal_error.png')
|
||||
logger.info('Screenshot saved: token_01_5_modal_error.png')
|
||||
|
||||
# Step 2: Check if GitHub token is already configured or needs to be set
|
||||
print('Step 2: Checking if GitHub token is configured...')
|
||||
logger.info('Step 2: Checking if GitHub token is configured...')
|
||||
|
||||
try:
|
||||
# First, check if we're already on the home screen with repository selection
|
||||
@@ -80,7 +83,7 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
connect_to_provider = page.locator('text=Connect to a Repository')
|
||||
|
||||
if connect_to_provider.is_visible(timeout=3000):
|
||||
print('Found "Connect to a Repository" section')
|
||||
logger.info('Found "Connect to a Repository" section')
|
||||
|
||||
# Check if we need to configure a provider (GitHub token)
|
||||
navigate_to_settings_button = page.locator(
|
||||
@@ -88,7 +91,9 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
)
|
||||
|
||||
if navigate_to_settings_button.is_visible(timeout=3000):
|
||||
print('GitHub token not configured. Need to navigate to settings...')
|
||||
logger.info(
|
||||
'GitHub token not configured. Need to navigate to settings...'
|
||||
)
|
||||
|
||||
# Click the Settings button to navigate to the settings page
|
||||
navigate_to_settings_button.click()
|
||||
@@ -96,19 +101,21 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
page.wait_for_timeout(3000) # Wait for navigation to complete
|
||||
|
||||
# We should now be on the /settings/integrations page
|
||||
print('Navigated to settings page, looking for GitHub token input...')
|
||||
logger.info(
|
||||
'Navigated to settings page, looking for GitHub token input...'
|
||||
)
|
||||
|
||||
# Check if we're on the settings page with the integrations tab
|
||||
settings_screen = page.locator('[data-testid="settings-screen"]')
|
||||
if settings_screen.is_visible(timeout=5000):
|
||||
print('Settings screen is visible')
|
||||
logger.info('Settings screen is visible')
|
||||
|
||||
# Make sure we're on the Integrations tab
|
||||
integrations_tab = page.locator('text=Integrations')
|
||||
if integrations_tab.is_visible(timeout=3000):
|
||||
# Check if we need to click the tab
|
||||
if not page.url.endswith('/settings/integrations'):
|
||||
print('Clicking Integrations tab...')
|
||||
logger.info('Clicking Integrations tab...')
|
||||
integrations_tab.click()
|
||||
page.wait_for_load_state('networkidle')
|
||||
page.wait_for_timeout(2000)
|
||||
@@ -118,7 +125,7 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
'[data-testid="github-token-input"]'
|
||||
)
|
||||
if github_token_input.is_visible(timeout=5000):
|
||||
print('Found GitHub token input field')
|
||||
logger.info('Found GitHub token input field')
|
||||
|
||||
# Fill in the GitHub token from environment variable
|
||||
github_token = os.getenv('GITHUB_TOKEN', '')
|
||||
@@ -126,18 +133,18 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
# Clear the field first, then fill it
|
||||
github_token_input.clear()
|
||||
github_token_input.fill(github_token)
|
||||
print(
|
||||
logger.info(
|
||||
f'Filled GitHub token from environment variable (length: {len(github_token)})'
|
||||
)
|
||||
|
||||
# Verify the token was filled
|
||||
filled_value = github_token_input.input_value()
|
||||
if filled_value:
|
||||
print(
|
||||
logger.info(
|
||||
f'Token field now contains value of length: {len(filled_value)}'
|
||||
)
|
||||
else:
|
||||
print(
|
||||
logger.warning(
|
||||
'WARNING: Token field appears to be empty after filling'
|
||||
)
|
||||
|
||||
@@ -146,12 +153,12 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
if save_button.is_visible(timeout=3000):
|
||||
# Check if button is enabled
|
||||
is_disabled = save_button.is_disabled()
|
||||
print(
|
||||
logger.info(
|
||||
f'Save Changes button found, disabled: {is_disabled}'
|
||||
)
|
||||
|
||||
if not is_disabled:
|
||||
print('Clicking Save Changes button...')
|
||||
logger.info('Clicking Save Changes button...')
|
||||
save_button.click()
|
||||
|
||||
# Wait for the save operation to complete
|
||||
@@ -164,46 +171,52 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
'document.querySelector(\'[data-testid="submit-button"]\').disabled === true',
|
||||
timeout=10000,
|
||||
)
|
||||
print(
|
||||
logger.info(
|
||||
'Save operation completed - form is now clean'
|
||||
)
|
||||
except Exception:
|
||||
print(
|
||||
logger.warning(
|
||||
'Save operation completed (timeout waiting for form clean state)'
|
||||
)
|
||||
|
||||
# Navigate back to home page after successful save
|
||||
print('Navigating back to home page...')
|
||||
logger.info('Navigating back to home page...')
|
||||
page.goto(base_url)
|
||||
page.wait_for_load_state('networkidle')
|
||||
page.wait_for_timeout(
|
||||
5000
|
||||
) # Wait longer for providers to be updated
|
||||
else:
|
||||
print(
|
||||
logger.warning(
|
||||
'Save Changes button is disabled - form may be invalid'
|
||||
)
|
||||
else:
|
||||
print('Save Changes button not found')
|
||||
logger.warning('Save Changes button not found')
|
||||
else:
|
||||
print('No GitHub token found in environment variables')
|
||||
logger.warning(
|
||||
'No GitHub token found in environment variables'
|
||||
)
|
||||
else:
|
||||
print('GitHub token input field not found on settings page')
|
||||
logger.warning(
|
||||
'GitHub token input field not found on settings page'
|
||||
)
|
||||
# Take a screenshot to see what's on the page
|
||||
page.screenshot(path='test-results/token_02_settings_debug.png')
|
||||
print('Debug screenshot saved: token_02_settings_debug.png')
|
||||
logger.info(
|
||||
'Debug screenshot saved: token_02_settings_debug.png'
|
||||
)
|
||||
else:
|
||||
print('Settings screen not found')
|
||||
logger.warning('Settings screen not found')
|
||||
else:
|
||||
# Branch 2: GitHub token is already configured, repository selection is available
|
||||
print(
|
||||
logger.info(
|
||||
'GitHub token is already configured, repository selection is available'
|
||||
)
|
||||
|
||||
# Check if we need to update the token by going to settings manually
|
||||
settings_button = page.locator('button:has-text("Settings")')
|
||||
if settings_button.is_visible(timeout=3000):
|
||||
print(
|
||||
logger.info(
|
||||
'Settings button found, clicking to navigate to settings page...'
|
||||
)
|
||||
settings_button.click()
|
||||
@@ -213,7 +226,7 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
# Navigate to the Integrations tab
|
||||
integrations_tab = page.locator('text=Integrations')
|
||||
if integrations_tab.is_visible(timeout=3000):
|
||||
print('Clicking Integrations tab...')
|
||||
logger.info('Clicking Integrations tab...')
|
||||
integrations_tab.click()
|
||||
page.wait_for_load_state('networkidle')
|
||||
page.wait_for_timeout(2000)
|
||||
@@ -223,7 +236,7 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
'[data-testid="github-token-input"]'
|
||||
)
|
||||
if github_token_input.is_visible(timeout=5000):
|
||||
print('Found GitHub token input field')
|
||||
logger.info('Found GitHub token input field')
|
||||
|
||||
# Fill in the GitHub token from environment variable
|
||||
github_token = os.getenv('GITHUB_TOKEN', '')
|
||||
@@ -231,7 +244,7 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
# Clear the field first, then fill it
|
||||
github_token_input.clear()
|
||||
github_token_input.fill(github_token)
|
||||
print(
|
||||
logger.info(
|
||||
f'Filled GitHub token from environment variable (length: {len(github_token)})'
|
||||
)
|
||||
|
||||
@@ -243,52 +256,56 @@ def test_github_token_configuration(page: Page, base_url: str):
|
||||
save_button.is_visible(timeout=3000)
|
||||
and not save_button.is_disabled()
|
||||
):
|
||||
print('Clicking Save Changes button...')
|
||||
logger.info('Clicking Save Changes button...')
|
||||
save_button.click()
|
||||
page.wait_for_timeout(3000)
|
||||
|
||||
# Navigate back to home page
|
||||
print('Navigating back to home page...')
|
||||
logger.info('Navigating back to home page...')
|
||||
page.goto(base_url)
|
||||
page.wait_for_load_state('networkidle')
|
||||
page.wait_for_timeout(3000)
|
||||
else:
|
||||
print(
|
||||
logger.warning(
|
||||
'GitHub token input field not found, going back to home page'
|
||||
)
|
||||
page.goto(base_url)
|
||||
page.wait_for_load_state('networkidle')
|
||||
else:
|
||||
print('Integrations tab not found, going back to home page')
|
||||
logger.warning(
|
||||
'Integrations tab not found, going back to home page'
|
||||
)
|
||||
page.goto(base_url)
|
||||
page.wait_for_load_state('networkidle')
|
||||
else:
|
||||
print('Settings button not found, continuing with existing token')
|
||||
logger.info(
|
||||
'Settings button not found, continuing with existing token'
|
||||
)
|
||||
else:
|
||||
print('Could not find "Connect to a Repository" section')
|
||||
logger.warning('Could not find "Connect to a Repository" section')
|
||||
|
||||
page.screenshot(path='test-results/token_03_after_settings.png')
|
||||
print('Screenshot saved: token_03_after_settings.png')
|
||||
logger.info('Screenshot saved: token_03_after_settings.png')
|
||||
|
||||
except Exception as e:
|
||||
print(f'Error checking GitHub token configuration: {e}')
|
||||
logger.error(f'Error checking GitHub token configuration: {e}')
|
||||
page.screenshot(path='test-results/token_04_error.png')
|
||||
print('Screenshot saved: token_04_error.png')
|
||||
logger.info('Screenshot saved: token_04_error.png')
|
||||
|
||||
# Step 3: Verify we're back on the home screen with repository selection available
|
||||
print('Step 3: Verifying repository selection is available...')
|
||||
logger.info('Step 3: Verifying repository selection is available...')
|
||||
|
||||
# Wait for the home screen to load
|
||||
home_screen = page.locator('[data-testid="home-screen"]')
|
||||
expect(home_screen).to_be_visible(timeout=15000)
|
||||
print('Home screen is visible')
|
||||
logger.info('Home screen is visible')
|
||||
|
||||
# Look for the repository dropdown/selector
|
||||
repo_dropdown = page.locator('[data-testid="repo-dropdown"]')
|
||||
expect(repo_dropdown).to_be_visible(timeout=15000)
|
||||
print('Repository dropdown is visible')
|
||||
logger.info('Repository dropdown is visible')
|
||||
|
||||
# Success - we've verified the GitHub token configuration
|
||||
print('GitHub token configuration verified successfully')
|
||||
logger.info('GitHub token configuration verified successfully')
|
||||
page.screenshot(path='test-results/token_05_success.png')
|
||||
print('Screenshot saved: token_05_success.png')
|
||||
logger.info('Screenshot saved: token_05_success.png')
|
||||
|
||||
Reference in New Issue
Block a user