Spaces:
Sleeping
Sleeping
| # test_ui_consistency.py | |
| """ | |
| Tests for UI consistency components across all verification modes. | |
| Validates that standardized components provide consistent styling, | |
| formatting, and behavior across all interfaces. | |
| Requirements: 12.1, 12.2, 12.3, 12.4, 12.5 | |
| """ | |
| import pytest | |
| from datetime import datetime | |
| from typing import Dict, Any | |
| from src.interface.ui_consistency_components import ( | |
| StandardizedComponents, | |
| ClassificationDisplay, | |
| ProgressDisplay, | |
| ErrorDisplay, | |
| SessionDisplay, | |
| HelpDisplay, | |
| UITheme, | |
| format_timestamp, | |
| format_file_size, | |
| truncate_text, | |
| format_duration | |
| ) | |
| class TestStandardizedComponents: | |
| """Test standardized UI component creation.""" | |
| def test_create_primary_button(self): | |
| """Test primary button creation with consistent styling.""" | |
| button = StandardizedComponents.create_primary_button("Test Button", "π₯", "lg") | |
| assert button.value == "π₯ Test Button" | |
| assert button.variant == "primary" | |
| assert button.size == "lg" | |
| def test_create_secondary_button(self): | |
| """Test secondary button creation with consistent styling.""" | |
| button = StandardizedComponents.create_secondary_button("Test Button", "βοΈ", "sm") | |
| assert button.value == "βοΈ Test Button" | |
| assert button.variant == "secondary" | |
| assert button.size == "sm" | |
| def test_create_stop_button(self): | |
| """Test stop button creation with consistent styling.""" | |
| button = StandardizedComponents.create_stop_button("Stop", "β") | |
| assert button.value == "β Stop" | |
| assert button.variant == "stop" | |
| def test_create_navigation_button(self): | |
| """Test navigation button creation with consistent styling.""" | |
| button = StandardizedComponents.create_navigation_button("Back") | |
| assert button.value == "β Back" | |
| assert button.size == "sm" | |
| assert button.variant == "secondary" | |
| def test_create_export_button(self): | |
| """Test export button creation for different formats.""" | |
| csv_button = StandardizedComponents.create_export_button("csv") | |
| json_button = StandardizedComponents.create_export_button("json") | |
| xlsx_button = StandardizedComponents.create_export_button("xlsx") | |
| assert csv_button.value == "π Export CSV" | |
| assert json_button.value == "π Export JSON" | |
| assert xlsx_button.value == "π Export XLSX" | |
| # All should be secondary buttons with small size | |
| for button in [csv_button, json_button, xlsx_button]: | |
| assert button.variant == "secondary" | |
| assert button.size == "sm" | |
| class TestClassificationDisplay: | |
| """Test classification display formatting consistency.""" | |
| def test_format_classification_badge(self): | |
| """Test classification badge formatting.""" | |
| green_badge = ClassificationDisplay.format_classification_badge("green") | |
| yellow_badge = ClassificationDisplay.format_classification_badge("yellow") | |
| red_badge = ClassificationDisplay.format_classification_badge("red") | |
| unknown_badge = ClassificationDisplay.format_classification_badge("unknown") | |
| assert "π’" in green_badge and "GREEN" in green_badge | |
| assert "π‘" in yellow_badge and "YELLOW" in yellow_badge | |
| assert "π΄" in red_badge and "RED" in red_badge | |
| assert "β" in unknown_badge and "UNKNOWN" in unknown_badge | |
| # Test case insensitivity | |
| assert ClassificationDisplay.format_classification_badge("GREEN") == green_badge | |
| assert ClassificationDisplay.format_classification_badge("Red") == red_badge | |
| def test_format_classification_html_badge(self): | |
| """Test HTML classification badge formatting.""" | |
| html_badge = ClassificationDisplay.format_classification_html_badge("green") | |
| assert "<span" in html_badge | |
| assert "π’" in html_badge | |
| assert "GREEN" in html_badge | |
| assert UITheme.GREEN_BG in html_badge | |
| assert UITheme.GREEN_TEXT in html_badge | |
| def test_format_confidence_display(self): | |
| """Test confidence display formatting.""" | |
| high_confidence = ClassificationDisplay.format_confidence_display(0.95) | |
| medium_confidence = ClassificationDisplay.format_confidence_display(0.75) | |
| low_confidence = ClassificationDisplay.format_confidence_display(0.45) | |
| assert "95%" in high_confidence and "π―" in high_confidence | |
| assert "75%" in medium_confidence and "π" in medium_confidence | |
| assert "45%" in low_confidence and "β οΈ" in low_confidence | |
| def test_format_indicators_display(self): | |
| """Test indicators display formatting.""" | |
| # Test with indicators | |
| indicators = ["hopelessness", "despair", "isolation"] | |
| formatted = ClassificationDisplay.format_indicators_display(indicators) | |
| assert "π" in formatted | |
| assert "hopelessness" in formatted | |
| assert "despair" in formatted | |
| assert "isolation" in formatted | |
| # Test with no indicators | |
| empty_formatted = ClassificationDisplay.format_indicators_display([]) | |
| assert "π" in empty_formatted | |
| assert "No specific indicators" in empty_formatted | |
| # Test with many indicators (should truncate) | |
| many_indicators = [f"indicator_{i}" for i in range(10)] | |
| truncated = ClassificationDisplay.format_indicators_display(many_indicators) | |
| assert "+5 more" in truncated | |
| def test_create_classification_radio(self): | |
| """Test classification radio button creation.""" | |
| radio = ClassificationDisplay.create_classification_radio() | |
| assert len(radio.choices) == 3 | |
| assert any("GREEN" in choice[0] for choice in radio.choices) | |
| assert any("YELLOW" in choice[0] for choice in radio.choices) | |
| assert any("RED" in choice[0] for choice in radio.choices) | |
| # Check values | |
| values = [choice[1] for choice in radio.choices] | |
| assert "green" in values | |
| assert "yellow" in values | |
| assert "red" in values | |
| class TestProgressDisplay: | |
| """Test progress display formatting consistency.""" | |
| def test_format_progress_display(self): | |
| """Test progress display formatting.""" | |
| progress = ProgressDisplay.format_progress_display(5, 10, "Test Mode") | |
| assert "π" in progress | |
| assert "5 of 10" in progress | |
| assert "50%" in progress | |
| # Test with zero total | |
| zero_progress = ProgressDisplay.format_progress_display(0, 0, "Test Mode") | |
| assert "Ready to start" in zero_progress | |
| assert "Test Mode" in zero_progress | |
| def test_format_accuracy_display(self): | |
| """Test accuracy display formatting.""" | |
| high_accuracy = ProgressDisplay.format_accuracy_display(9, 10) | |
| medium_accuracy = ProgressDisplay.format_accuracy_display(7, 10) | |
| low_accuracy = ProgressDisplay.format_accuracy_display(5, 10) | |
| assert "90.0%" in high_accuracy and "π―" in high_accuracy | |
| assert "70.0%" in medium_accuracy and "β οΈ" in medium_accuracy # 70% is below 75% threshold | |
| assert "50.0%" in low_accuracy and "β οΈ" in low_accuracy | |
| # Test with zero total | |
| zero_accuracy = ProgressDisplay.format_accuracy_display(0, 0) | |
| assert "No verifications yet" in zero_accuracy | |
| def test_format_processing_speed_display(self): | |
| """Test processing speed display formatting.""" | |
| speed = ProgressDisplay.format_processing_speed_display(10, 2.0) | |
| assert "β‘" in speed | |
| assert "5.0 messages/min" in speed | |
| # Test with zero values | |
| zero_speed = ProgressDisplay.format_processing_speed_display(0, 0) | |
| assert "Calculating..." in zero_speed | |
| def test_create_progress_html_bar(self): | |
| """Test HTML progress bar creation.""" | |
| html_bar = ProgressDisplay.create_progress_html_bar(3, 10) | |
| assert "<div" in html_bar | |
| assert "30.0%" in html_bar # The implementation uses float formatting | |
| assert UITheme.PRIMARY_COLOR in html_bar | |
| # Test with zero total | |
| zero_bar = ProgressDisplay.create_progress_html_bar(0, 0) | |
| assert "0%" in zero_bar | |
| class TestErrorDisplay: | |
| """Test error display formatting consistency.""" | |
| def test_format_error_message(self): | |
| """Test error message formatting.""" | |
| error_msg = ErrorDisplay.format_error_message("Test error", "error") | |
| warning_msg = ErrorDisplay.format_error_message("Test warning", "warning") | |
| info_msg = ErrorDisplay.format_error_message("Test info", "info") | |
| success_msg = ErrorDisplay.format_error_message("Test success", "success") | |
| assert "β" in error_msg and "Test error" in error_msg | |
| assert "β οΈ" in warning_msg and "Test warning" in warning_msg | |
| assert "βΉοΈ" in info_msg and "Test info" in info_msg | |
| assert "β " in success_msg and "Test success" in success_msg | |
| def test_create_error_html_display(self): | |
| """Test HTML error display creation.""" | |
| suggestions = ["Try this", "Or this"] | |
| html_error = ErrorDisplay.create_error_html_display( | |
| "Test error message", | |
| "error", | |
| suggestions | |
| ) | |
| assert "<div" in html_error | |
| assert "Test error message" in html_error | |
| assert "Try this" in html_error | |
| assert "Or this" in html_error | |
| assert UITheme.FONT_FAMILY in html_error | |
| # Test without suggestions | |
| simple_error = ErrorDisplay.create_error_html_display("Simple error", "warning") | |
| assert "Simple error" in simple_error | |
| assert "Suggestions:" not in simple_error | |
| class TestSessionDisplay: | |
| """Test session display formatting consistency.""" | |
| def test_format_session_info(self): | |
| """Test session information formatting.""" | |
| session_data = { | |
| 'verifier_name': 'Test User', | |
| 'mode_type': 'manual_input', | |
| 'dataset_name': 'Test Dataset', | |
| 'verified_count': 5, | |
| 'total_messages': 10, | |
| 'is_complete': False, | |
| 'accuracy': 80.0, | |
| 'created_at': datetime(2025, 1, 1, 12, 0, 0) | |
| } | |
| info = SessionDisplay.format_session_info(session_data) | |
| assert "Test User" in info | |
| assert "Manual Input" in info # Should format mode type | |
| assert "Test Dataset" in info | |
| assert "5/10" in info | |
| assert "β³ In Progress" in info | |
| assert "80.0%" in info | |
| assert "2025-01-01 12:00:00" in info | |
| def test_format_session_statistics(self): | |
| """Test session statistics formatting.""" | |
| stats = { | |
| 'verified_count': 10, | |
| 'correct_count': 8, | |
| 'incorrect_count': 2, | |
| 'accuracy': 80.0 | |
| } | |
| formatted_stats = SessionDisplay.format_session_statistics(stats) | |
| assert "Messages Processed:** 10" in formatted_stats | |
| assert "Correct Classifications:** 8" in formatted_stats | |
| assert "Incorrect Classifications:** 2" in formatted_stats | |
| assert "Accuracy:** 80.0%" in formatted_stats | |
| def test_create_session_summary_card(self): | |
| """Test session summary card creation.""" | |
| session_data = { | |
| 'mode_type': 'file_upload', | |
| 'dataset_name': 'Test File.csv', | |
| 'verifier_name': 'Test User', | |
| 'is_complete': True | |
| } | |
| stats = { | |
| 'verified_count': 20, | |
| 'correct_count': 18, | |
| 'incorrect_count': 2, | |
| 'accuracy': 90.0, | |
| 'breakdown_by_type': { | |
| 'green': 10, | |
| 'yellow': 5, | |
| 'red': 3 | |
| } | |
| } | |
| summary = SessionDisplay.create_session_summary_card(session_data, stats) | |
| assert "File Upload" in summary | |
| assert "Test File.csv" in summary | |
| assert "Test User" in summary | |
| assert "20" in summary | |
| assert "90.0%" in summary | |
| assert "π’" in summary and "10 correct" in summary | |
| assert "π‘" in summary and "5 correct" in summary | |
| assert "π΄" in summary and "3 correct" in summary | |
| assert "β Complete" in summary | |
| class TestHelpDisplay: | |
| """Test help display formatting consistency.""" | |
| def test_create_mode_description_card(self): | |
| """Test mode description card creation.""" | |
| features = ["Feature 1", "Feature 2", "Feature 3"] | |
| card = HelpDisplay.create_mode_description_card( | |
| "manual_input", | |
| "Test description", | |
| features | |
| ) | |
| assert "βοΈ" in card # Manual input icon | |
| assert "Manual Input" in card | |
| assert "Test description" in card | |
| assert "Feature 1" in card | |
| assert "Feature 2" in card | |
| assert "Feature 3" in card | |
| def test_create_format_help_display(self): | |
| """Test format help display creation.""" | |
| help_text = HelpDisplay.create_format_help_display() | |
| assert "Required columns:" in help_text | |
| assert "message" in help_text | |
| assert "expected_classification" in help_text | |
| assert "green" in help_text | |
| assert "yellow" in help_text | |
| assert "red" in help_text | |
| assert "CSV" in help_text | |
| assert "XLSX" in help_text | |
| def test_create_workflow_help_display(self): | |
| """Test workflow help display creation.""" | |
| manual_help = HelpDisplay.create_workflow_help_display("manual_input") | |
| dataset_help = HelpDisplay.create_workflow_help_display("enhanced_dataset") | |
| upload_help = HelpDisplay.create_workflow_help_display("file_upload") | |
| unknown_help = HelpDisplay.create_workflow_help_display("unknown_mode") | |
| assert "Manual Input Workflow" in manual_help | |
| assert "Enhanced Dataset Workflow" in dataset_help | |
| assert "File Upload Workflow" in upload_help | |
| assert "Unknown Mode" in unknown_help | |
| class TestUtilityFunctions: | |
| """Test utility formatting functions.""" | |
| def test_format_timestamp(self): | |
| """Test timestamp formatting consistency.""" | |
| dt = datetime(2025, 1, 1, 12, 30, 45) | |
| formatted = format_timestamp(dt) | |
| assert formatted == "2025-01-01 12:30:45" | |
| # Test with string input | |
| string_formatted = format_timestamp("2025-01-01 12:30:45") | |
| assert string_formatted == "2025-01-01 12:30:45" | |
| def test_format_file_size(self): | |
| """Test file size formatting.""" | |
| assert format_file_size(500) == "500 B" | |
| assert format_file_size(1536) == "1.5 KB" | |
| assert format_file_size(2097152) == "2.0 MB" | |
| def test_truncate_text(self): | |
| """Test text truncation consistency.""" | |
| short_text = "Short text" | |
| long_text = "This is a very long text that should be truncated" | |
| assert truncate_text(short_text, 50) == short_text | |
| assert truncate_text(long_text, 20) == "This is a very lo..." | |
| assert len(truncate_text(long_text, 20)) == 20 | |
| def test_format_duration(self): | |
| """Test duration formatting consistency.""" | |
| start = datetime(2025, 1, 1, 12, 0, 0) | |
| # Test seconds | |
| end_seconds = datetime(2025, 1, 1, 12, 0, 30) | |
| assert format_duration(start, end_seconds) == "30s" | |
| # Test minutes | |
| end_minutes = datetime(2025, 1, 1, 12, 5, 30) | |
| assert format_duration(start, end_minutes) == "5m 30s" | |
| # Test hours | |
| end_hours = datetime(2025, 1, 1, 14, 30, 0) | |
| assert format_duration(start, end_hours) == "2h 30m" | |
| # Test days | |
| end_days = datetime(2025, 1, 3, 14, 0, 0) | |
| assert format_duration(start, end_days) == "2d 2h" | |
| class TestUITheme: | |
| """Test UI theme consistency.""" | |
| def test_color_scheme_consistency(self): | |
| """Test that color scheme is consistently defined.""" | |
| # Test that all required colors are defined | |
| assert hasattr(UITheme, 'PRIMARY_COLOR') | |
| assert hasattr(UITheme, 'SUCCESS_COLOR') | |
| assert hasattr(UITheme, 'WARNING_COLOR') | |
| assert hasattr(UITheme, 'ERROR_COLOR') | |
| assert hasattr(UITheme, 'SECONDARY_COLOR') | |
| # Test classification colors | |
| assert hasattr(UITheme, 'GREEN_BG') | |
| assert hasattr(UITheme, 'GREEN_TEXT') | |
| assert hasattr(UITheme, 'YELLOW_BG') | |
| assert hasattr(UITheme, 'YELLOW_TEXT') | |
| assert hasattr(UITheme, 'RED_BG') | |
| assert hasattr(UITheme, 'RED_TEXT') | |
| # Test that colors are valid hex codes | |
| colors = [ | |
| UITheme.PRIMARY_COLOR, | |
| UITheme.SUCCESS_COLOR, | |
| UITheme.WARNING_COLOR, | |
| UITheme.ERROR_COLOR, | |
| UITheme.SECONDARY_COLOR | |
| ] | |
| for color in colors: | |
| assert color.startswith('#') | |
| assert len(color) == 7 # #RRGGBB format | |
| def test_layout_consistency(self): | |
| """Test that layout values are consistently defined.""" | |
| assert hasattr(UITheme, 'BORDER_RADIUS') | |
| assert hasattr(UITheme, 'PADDING_SM') | |
| assert hasattr(UITheme, 'PADDING_MD') | |
| assert hasattr(UITheme, 'PADDING_LG') | |
| # Test that padding values include units | |
| assert 'em' in UITheme.PADDING_SM | |
| assert 'em' in UITheme.PADDING_MD | |
| assert 'em' in UITheme.PADDING_LG | |
| def test_typography_consistency(self): | |
| """Test that typography is consistently defined.""" | |
| assert hasattr(UITheme, 'FONT_FAMILY') | |
| assert hasattr(UITheme, 'FONT_SIZE_SM') | |
| assert hasattr(UITheme, 'FONT_SIZE_MD') | |
| assert hasattr(UITheme, 'FONT_SIZE_LG') | |
| # Test that font sizes include units | |
| assert 'em' in UITheme.FONT_SIZE_SM | |
| assert 'em' in UITheme.FONT_SIZE_MD | |
| assert 'em' in UITheme.FONT_SIZE_LG | |
| if __name__ == "__main__": | |
| pytest.main([__file__]) |