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:
Chujiang
2026-02-19 07:58:39 +08:00
committed by GitHub
parent fede37b496
commit 6676cae249
2 changed files with 69 additions and 51 deletions

View File

@@ -1,5 +1,6 @@
import json import json
from datetime import datetime from datetime import datetime
from typing import Any
from json_repair import repair_json from json_repair import repair_json
from litellm.types.utils import ModelResponse from litellm.types.utils import ModelResponse
@@ -32,7 +33,7 @@ class OpenHandsJSONEncoder(json.JSONEncoder):
_json_encoder = OpenHandsJSONEncoder() _json_encoder = OpenHandsJSONEncoder()
def dumps(obj, **kwargs): def dumps(obj, **kwargs) -> str:
"""Serialize an object to str format""" """Serialize an object to str format"""
if not kwargs: if not kwargs:
return _json_encoder.encode(obj) return _json_encoder.encode(obj)
@@ -47,7 +48,7 @@ def dumps(obj, **kwargs):
return json.dumps(obj, **encoder_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""" """Create a JSON object from str"""
try: try:
return json.loads(json_str, **kwargs) return json.loads(json_str, **kwargs)

View File

@@ -6,10 +6,13 @@ then ensures the GitHub token is set in Settings → Integrations and that the
home screen shows the repository selector. home screen shows the repository selector.
""" """
import logging
import os import os
from playwright.sync_api import Page, expect from playwright.sync_api import Page, expect
logger = logging.getLogger(__name__)
def test_github_token_configuration(page: Page, base_url: str): 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' base_url = 'http://localhost:12000'
# Navigate to the OpenHands application # 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.goto(base_url)
page.wait_for_load_state('networkidle', timeout=30000) page.wait_for_load_state('networkidle', timeout=30000)
# Take initial screenshot # Take initial screenshot
page.screenshot(path='test-results/token_01_initial_load.png') 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) # Step 1.5: Handle any initial modals that might appear (LLM API key configuration)
try: try:
# Check for AI Provider Configuration modal # Check for AI Provider Configuration modal
config_modal = page.locator('text=AI Provider Configuration') config_modal = page.locator('text=AI Provider Configuration')
if config_modal.is_visible(timeout=5000): 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 # Fill in the LLM API key if available
llm_api_key_input = page.locator('[data-testid="llm-api-key-input"]') llm_api_key_input = page.locator('[data-testid="llm-api-key-input"]')
if llm_api_key_input.is_visible(timeout=3000): if llm_api_key_input.is_visible(timeout=3000):
llm_api_key = os.getenv('LLM_API_KEY', 'test-key') llm_api_key = os.getenv('LLM_API_KEY', 'test-key')
llm_api_key_input.fill(llm_api_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 # Click the Save button
save_button = page.locator('button:has-text("Save")') save_button = page.locator('button:has-text("Save")')
if save_button.is_visible(timeout=3000): if save_button.is_visible(timeout=3000):
save_button.click() save_button.click()
page.wait_for_timeout(2000) page.wait_for_timeout(2000)
print('Saved LLM API key configuration') logger.info('Saved LLM API key configuration')
# Check for Privacy Preferences modal # Check for Privacy Preferences modal
privacy_modal = page.locator('text=Your Privacy Preferences') privacy_modal = page.locator('text=Your Privacy Preferences')
if privacy_modal.is_visible(timeout=5000): 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")') confirm_button = page.locator('button:has-text("Confirm Preferences")')
if confirm_button.is_visible(timeout=3000): if confirm_button.is_visible(timeout=3000):
confirm_button.click() confirm_button.click()
page.wait_for_timeout(2000) page.wait_for_timeout(2000)
print('Confirmed privacy preferences') logger.info('Confirmed privacy preferences')
except Exception as e: 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') 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 # 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: try:
# First, check if we're already on the home screen with repository selection # 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') connect_to_provider = page.locator('text=Connect to a Repository')
if connect_to_provider.is_visible(timeout=3000): 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) # Check if we need to configure a provider (GitHub token)
navigate_to_settings_button = page.locator( 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): 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 # Click the Settings button to navigate to the settings page
navigate_to_settings_button.click() 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 page.wait_for_timeout(3000) # Wait for navigation to complete
# We should now be on the /settings/integrations page # 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 # Check if we're on the settings page with the integrations tab
settings_screen = page.locator('[data-testid="settings-screen"]') settings_screen = page.locator('[data-testid="settings-screen"]')
if settings_screen.is_visible(timeout=5000): 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 # Make sure we're on the Integrations tab
integrations_tab = page.locator('text=Integrations') integrations_tab = page.locator('text=Integrations')
if integrations_tab.is_visible(timeout=3000): if integrations_tab.is_visible(timeout=3000):
# Check if we need to click the tab # Check if we need to click the tab
if not page.url.endswith('/settings/integrations'): if not page.url.endswith('/settings/integrations'):
print('Clicking Integrations tab...') logger.info('Clicking Integrations tab...')
integrations_tab.click() integrations_tab.click()
page.wait_for_load_state('networkidle') page.wait_for_load_state('networkidle')
page.wait_for_timeout(2000) page.wait_for_timeout(2000)
@@ -118,7 +125,7 @@ def test_github_token_configuration(page: Page, base_url: str):
'[data-testid="github-token-input"]' '[data-testid="github-token-input"]'
) )
if github_token_input.is_visible(timeout=5000): 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 # Fill in the GitHub token from environment variable
github_token = os.getenv('GITHUB_TOKEN', '') 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 # Clear the field first, then fill it
github_token_input.clear() github_token_input.clear()
github_token_input.fill(github_token) github_token_input.fill(github_token)
print( logger.info(
f'Filled GitHub token from environment variable (length: {len(github_token)})' f'Filled GitHub token from environment variable (length: {len(github_token)})'
) )
# Verify the token was filled # Verify the token was filled
filled_value = github_token_input.input_value() filled_value = github_token_input.input_value()
if filled_value: if filled_value:
print( logger.info(
f'Token field now contains value of length: {len(filled_value)}' f'Token field now contains value of length: {len(filled_value)}'
) )
else: else:
print( logger.warning(
'WARNING: Token field appears to be empty after filling' '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): if save_button.is_visible(timeout=3000):
# Check if button is enabled # Check if button is enabled
is_disabled = save_button.is_disabled() is_disabled = save_button.is_disabled()
print( logger.info(
f'Save Changes button found, disabled: {is_disabled}' f'Save Changes button found, disabled: {is_disabled}'
) )
if not is_disabled: if not is_disabled:
print('Clicking Save Changes button...') logger.info('Clicking Save Changes button...')
save_button.click() save_button.click()
# Wait for the save operation to complete # 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', 'document.querySelector(\'[data-testid="submit-button"]\').disabled === true',
timeout=10000, timeout=10000,
) )
print( logger.info(
'Save operation completed - form is now clean' 'Save operation completed - form is now clean'
) )
except Exception: except Exception:
print( logger.warning(
'Save operation completed (timeout waiting for form clean state)' 'Save operation completed (timeout waiting for form clean state)'
) )
# Navigate back to home page after successful save # 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.goto(base_url)
page.wait_for_load_state('networkidle') page.wait_for_load_state('networkidle')
page.wait_for_timeout( page.wait_for_timeout(
5000 5000
) # Wait longer for providers to be updated ) # Wait longer for providers to be updated
else: else:
print( logger.warning(
'Save Changes button is disabled - form may be invalid' 'Save Changes button is disabled - form may be invalid'
) )
else: else:
print('Save Changes button not found') logger.warning('Save Changes button not found')
else: else:
print('No GitHub token found in environment variables') logger.warning(
'No GitHub token found in environment variables'
)
else: 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 # Take a screenshot to see what's on the page
page.screenshot(path='test-results/token_02_settings_debug.png') 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: else:
print('Settings screen not found') logger.warning('Settings screen not found')
else: else:
# Branch 2: GitHub token is already configured, repository selection is available # Branch 2: GitHub token is already configured, repository selection is available
print( logger.info(
'GitHub token is already configured, repository selection is available' 'GitHub token is already configured, repository selection is available'
) )
# Check if we need to update the token by going to settings manually # Check if we need to update the token by going to settings manually
settings_button = page.locator('button:has-text("Settings")') settings_button = page.locator('button:has-text("Settings")')
if settings_button.is_visible(timeout=3000): if settings_button.is_visible(timeout=3000):
print( logger.info(
'Settings button found, clicking to navigate to settings page...' 'Settings button found, clicking to navigate to settings page...'
) )
settings_button.click() settings_button.click()
@@ -213,7 +226,7 @@ def test_github_token_configuration(page: Page, base_url: str):
# Navigate to the Integrations tab # Navigate to the Integrations tab
integrations_tab = page.locator('text=Integrations') integrations_tab = page.locator('text=Integrations')
if integrations_tab.is_visible(timeout=3000): if integrations_tab.is_visible(timeout=3000):
print('Clicking Integrations tab...') logger.info('Clicking Integrations tab...')
integrations_tab.click() integrations_tab.click()
page.wait_for_load_state('networkidle') page.wait_for_load_state('networkidle')
page.wait_for_timeout(2000) page.wait_for_timeout(2000)
@@ -223,7 +236,7 @@ def test_github_token_configuration(page: Page, base_url: str):
'[data-testid="github-token-input"]' '[data-testid="github-token-input"]'
) )
if github_token_input.is_visible(timeout=5000): 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 # Fill in the GitHub token from environment variable
github_token = os.getenv('GITHUB_TOKEN', '') 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 # Clear the field first, then fill it
github_token_input.clear() github_token_input.clear()
github_token_input.fill(github_token) github_token_input.fill(github_token)
print( logger.info(
f'Filled GitHub token from environment variable (length: {len(github_token)})' 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) save_button.is_visible(timeout=3000)
and not save_button.is_disabled() and not save_button.is_disabled()
): ):
print('Clicking Save Changes button...') logger.info('Clicking Save Changes button...')
save_button.click() save_button.click()
page.wait_for_timeout(3000) page.wait_for_timeout(3000)
# Navigate back to home page # Navigate back to home page
print('Navigating back to home page...') logger.info('Navigating back to home page...')
page.goto(base_url) page.goto(base_url)
page.wait_for_load_state('networkidle') page.wait_for_load_state('networkidle')
page.wait_for_timeout(3000) page.wait_for_timeout(3000)
else: else:
print( logger.warning(
'GitHub token input field not found, going back to home page' 'GitHub token input field not found, going back to home page'
) )
page.goto(base_url) page.goto(base_url)
page.wait_for_load_state('networkidle') page.wait_for_load_state('networkidle')
else: 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.goto(base_url)
page.wait_for_load_state('networkidle') page.wait_for_load_state('networkidle')
else: else:
print('Settings button not found, continuing with existing token') logger.info(
'Settings button not found, continuing with existing token'
)
else: 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') 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: 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') 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 # 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 # Wait for the home screen to load
home_screen = page.locator('[data-testid="home-screen"]') home_screen = page.locator('[data-testid="home-screen"]')
expect(home_screen).to_be_visible(timeout=15000) 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 # Look for the repository dropdown/selector
repo_dropdown = page.locator('[data-testid="repo-dropdown"]') repo_dropdown = page.locator('[data-testid="repo-dropdown"]')
expect(repo_dropdown).to_be_visible(timeout=15000) 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 # 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') page.screenshot(path='test-results/token_05_success.png')
print('Screenshot saved: token_05_success.png') logger.info('Screenshot saved: token_05_success.png')