# -*- coding: utf-8 -*- from odoo.tests.common import TransactionCase from hypothesis import given, strategies as st, settings class TestHoverFeedback(TransactionCase): """ Test cases for hover feedback behavior Property 3: Hover provides visual feedback For any star hovered, the system should display visual feedback indicating the potential rating. Validates: Requirements 1.4 """ def setUp(self): super(TestHoverFeedback, self).setUp() # We'll test the hover feedback logic that would be used in the frontend # The logic is: when hovering, hoverValue is set, and displayValue uses hoverValue self.max_stars = 5 def _simulate_hover(self, hover_star, selected_star=0): """ Simulate the hover logic from the JavaScript component. This mirrors the logic in rating_stars.js: - onStarHover sets state.hoverValue = starNumber - displayValue returns hoverValue || selectedValue - isStarFilled checks if starNumber <= displayValue Args: hover_star: The star number being hovered (1-5) selected_star: The currently selected star (0-5) Returns: dict with: - hover_value: The hover value set - display_value: The value used for display - filled_stars: List of star numbers that should be filled """ hover_value = hover_star display_value = hover_value if hover_value > 0 else selected_star # Stars that should be filled during hover filled_stars = list(range(1, int(display_value) + 1)) if display_value > 0 else [] return { 'hover_value': hover_value, 'display_value': display_value, 'filled_stars': filled_stars, } def _simulate_no_hover(self, selected_star=0): """ Simulate when not hovering (mouse leave). This mirrors the logic in rating_stars.js: - onStarLeave sets state.hoverValue = 0 - displayValue returns hoverValue || selectedValue (so just selectedValue) Args: selected_star: The currently selected star (0-5) Returns: dict with: - hover_value: The hover value (0) - display_value: The value used for display - filled_stars: List of star numbers that should be filled """ hover_value = 0 display_value = selected_star # Stars that should be filled when not hovering filled_stars = list(range(1, int(display_value) + 1)) if display_value > 0 else [] return { 'hover_value': hover_value, 'display_value': display_value, 'filled_stars': filled_stars, } def _verify_hover_feedback_property(self, hover_star, selected_star=0): """ Verify that hovering over a star provides visual feedback. The property states: For any star hovered, the system should display visual feedback indicating the potential rating. Visual feedback means: 1. The hovered star and all stars before it should be filled 2. The display should show the hover value, not the selected value 3. Stars after the hovered star should not be filled Args: hover_star: The star number being hovered (1-5) selected_star: The currently selected star (0-5) """ result = self._simulate_hover(hover_star, selected_star) # Property 1: Hover value should be set to the hovered star self.assertEqual( result['hover_value'], hover_star, f"Hovering star {hover_star} should set hover_value to {hover_star}" ) # Property 2: Display value should use hover value (visual feedback) self.assertEqual( result['display_value'], hover_star, f"When hovering star {hover_star}, display should show {hover_star}, " f"not selected value {selected_star}" ) # Property 3: All stars from 1 to hover_star should be filled (visual feedback) expected_filled = list(range(1, hover_star + 1)) self.assertEqual( result['filled_stars'], expected_filled, f"Hovering star {hover_star} should fill stars {expected_filled}, " f"but got {result['filled_stars']}" ) # Property 4: The number of filled stars should equal the hovered star self.assertEqual( len(result['filled_stars']), hover_star, f"Hovering star {hover_star} should fill exactly {hover_star} stars, " f"but {len(result['filled_stars'])} were filled" ) # Property 5: All filled stars should be <= hovered star for star in result['filled_stars']: self.assertLessEqual( star, hover_star, f"Filled star {star} should be <= hovered star {hover_star}" ) # Property 6: All stars > hovered star should NOT be filled for star in range(hover_star + 1, self.max_stars + 1): self.assertNotIn( star, result['filled_stars'], f"Star {star} should NOT be filled when hovering star {hover_star}" ) # Feature: helpdesk-rating-five-stars, Property 3: Hover provides visual feedback @given( hover_star=st.integers(min_value=1, max_value=5), selected_star=st.integers(min_value=0, max_value=5) ) @settings(max_examples=100, deadline=None) def test_property_hover_provides_visual_feedback(self, hover_star, selected_star): """ Property 3: Hover provides visual feedback For any star hovered (1-5) and any selected star (0-5), the system should display visual feedback indicating the potential rating. This tests that: 1. Hovering sets the hover value 2. The display uses the hover value (not selected value) 3. The correct stars are filled to show the potential rating 4. Visual feedback is independent of current selection Validates: Requirements 1.4 """ self._verify_hover_feedback_property(hover_star, selected_star) def test_hover_feedback_overrides_selection(self): """ Test that hover feedback overrides the current selection """ # Test case 1: Selected 2 stars, hover over 4 stars result = self._simulate_hover(hover_star=4, selected_star=2) self.assertEqual(result['display_value'], 4, "Hover should override selection") self.assertEqual(len(result['filled_stars']), 4, "Should show 4 filled stars when hovering, not 2") # Test case 2: Selected 5 stars, hover over 1 star result = self._simulate_hover(hover_star=1, selected_star=5) self.assertEqual(result['display_value'], 1, "Hover should override selection") self.assertEqual(len(result['filled_stars']), 1, "Should show 1 filled star when hovering, not 5") # Test case 3: Selected 3 stars, hover over 3 stars (same) result = self._simulate_hover(hover_star=3, selected_star=3) self.assertEqual(result['display_value'], 3, "Hover should show same value") self.assertEqual(len(result['filled_stars']), 3, "Should show 3 filled stars") def test_hover_feedback_no_selection(self): """ Test hover feedback when no star is selected """ for hover_star in range(1, self.max_stars + 1): result = self._simulate_hover(hover_star=hover_star, selected_star=0) self.assertEqual( result['display_value'], hover_star, f"Hovering star {hover_star} with no selection should show {hover_star}" ) self.assertEqual( len(result['filled_stars']), hover_star, f"Should show {hover_star} filled stars" ) def test_hover_feedback_removal(self): """ Test that visual feedback is removed when hover ends """ # Test with various selected values for selected_star in range(0, self.max_stars + 1): result = self._simulate_no_hover(selected_star=selected_star) # When not hovering, display should show selected value self.assertEqual( result['display_value'], selected_star, f"When not hovering, should display selected value {selected_star}" ) # Hover value should be 0 self.assertEqual( result['hover_value'], 0, "Hover value should be 0 when not hovering" ) # Filled stars should match selected value expected_filled = list(range(1, selected_star + 1)) if selected_star > 0 else [] self.assertEqual( result['filled_stars'], expected_filled, f"When not hovering with selection {selected_star}, " f"should show {expected_filled} filled stars" ) def test_hover_feedback_all_stars(self): """ Test hover feedback for each individual star """ for hover_star in range(1, self.max_stars + 1): result = self._simulate_hover(hover_star=hover_star, selected_star=0) # Verify correct number of stars filled self.assertEqual( len(result['filled_stars']), hover_star, f"Hovering star {hover_star} should fill {hover_star} stars" ) # Verify the filled stars are exactly [1, 2, ..., hover_star] expected = list(range(1, hover_star + 1)) self.assertEqual( result['filled_stars'], expected, f"Hovering star {hover_star} should fill stars {expected}" ) def test_hover_feedback_boundary_cases(self): """ Test boundary cases for hover feedback """ # Minimum hover (star 1) result = self._simulate_hover(hover_star=1, selected_star=0) self.assertEqual(len(result['filled_stars']), 1, "Hovering star 1 should fill 1 star") self.assertEqual(result['filled_stars'], [1], "Only star 1 should be filled") # Maximum hover (star 5) result = self._simulate_hover(hover_star=5, selected_star=0) self.assertEqual(len(result['filled_stars']), 5, "Hovering star 5 should fill 5 stars") self.assertEqual(result['filled_stars'], [1, 2, 3, 4, 5], "All stars should be filled") # Hover with maximum selection result = self._simulate_hover(hover_star=1, selected_star=5) self.assertEqual(result['display_value'], 1, "Hover should override even maximum selection") self.assertEqual(len(result['filled_stars']), 1, "Should show hover feedback, not selection") def test_hover_feedback_consistency(self): """ Test that hover feedback is consistent across multiple calls """ for hover_star in range(1, self.max_stars + 1): for selected_star in range(0, self.max_stars + 1): # Call multiple times with same values result1 = self._simulate_hover(hover_star, selected_star) result2 = self._simulate_hover(hover_star, selected_star) result3 = self._simulate_hover(hover_star, selected_star) # All results should be identical self.assertEqual(result1, result2, "Hover feedback should be consistent") self.assertEqual(result2, result3, "Hover feedback should be consistent") self.assertEqual(result1, result3, "Hover feedback should be consistent") def test_hover_feedback_sequential(self): """ Test hover feedback when hovering over stars sequentially """ selected_star = 2 # Simulate hovering over each star in sequence for hover_star in range(1, self.max_stars + 1): result = self._simulate_hover(hover_star, selected_star) # Each hover should show the correct feedback self.assertEqual( result['display_value'], hover_star, f"Hovering star {hover_star} should display {hover_star}" ) # Verify filled stars match hover position expected_filled = list(range(1, hover_star + 1)) self.assertEqual( result['filled_stars'], expected_filled, f"Hovering star {hover_star} should fill {expected_filled}" ) def test_hover_feedback_independence(self): """ Test that hover feedback is independent of selection """ # For each possible selection for selected_star in range(0, self.max_stars + 1): # For each possible hover for hover_star in range(1, self.max_stars + 1): result = self._simulate_hover(hover_star, selected_star) # Hover feedback should always show hover_star, regardless of selection self.assertEqual( result['display_value'], hover_star, f"Hover feedback should show {hover_star}, " f"not selection {selected_star}" ) # Number of filled stars should match hover, not selection self.assertEqual( len(result['filled_stars']), hover_star, f"Should fill {hover_star} stars when hovering, " f"regardless of selection {selected_star}" )