helpdesk_rating_five_stars/tests/test_hover_feedback.py
2025-11-26 10:39:26 +07:00

364 lines
14 KiB
Python

# -*- 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}"
)