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

201 lines
7.6 KiB
Python

# -*- coding: utf-8 -*-
from odoo.tests.common import TransactionCase
from hypothesis import given, strategies as st, settings
class TestHelpdeskTicket(TransactionCase):
"""Test cases for the extended helpdesk ticket model"""
def setUp(self):
super(TestHelpdeskTicket, self).setUp()
self.HelpdeskTicket = self.env['helpdesk.ticket']
self.Rating = self.env['rating.rating']
self.Partner = self.env['res.partner']
self.User = self.env['res.users']
self.HelpdeskTeam = self.env['helpdesk.team']
# Create test partner
self.test_partner = self.Partner.create({
'name': 'Test Customer',
'email': 'test@example.com',
})
# Create test user
self.test_user = self.User.create({
'name': 'Test User',
'login': 'testuser',
'email': 'testuser@example.com',
})
# Create helpdesk team
self.helpdesk_team = self.HelpdeskTeam.create({
'name': 'Test Support Team',
})
def _create_ticket_with_rating(self, rating_value):
"""Helper method to create a ticket with a rating"""
# Create ticket
ticket = self.HelpdeskTicket.create({
'name': 'Test Ticket',
'partner_id': self.test_partner.id,
'team_id': self.helpdesk_team.id,
})
# Create rating for the ticket
if rating_value is not None:
rating = self.Rating.create({
'rating': rating_value,
'partner_id': self.test_partner.id,
'rated_partner_id': self.test_user.partner_id.id,
'res_model': 'helpdesk.ticket',
'res_id': ticket.id,
})
# No need to invalidate - computed fields will compute on access
return ticket
# Feature: helpdesk-rating-five-stars, Property 10: Backend displays correct star count
@given(rating_value=st.floats(min_value=1.0, max_value=5.0, allow_nan=False, allow_infinity=False))
@settings(max_examples=100, deadline=None)
def test_property_backend_displays_correct_star_count(self, rating_value):
"""
Property 10: Backend displays correct star count
For any rating value, the backend view should display the number
of filled stars equal to the rating value (rounded).
Validates: Requirements 4.3
"""
# Create ticket with rating
ticket = self._create_ticket_with_rating(rating_value)
# Get the HTML representation
html = ticket.rating_stars_html
# Verify HTML is generated
self.assertTrue(html, "HTML should be generated for rated ticket")
# Count filled and empty stars in HTML
filled_count = html.count('')
empty_count = html.count('')
# Expected filled stars (rounded rating value)
expected_filled = round(rating_value)
expected_empty = 5 - expected_filled
# Verify star counts match
self.assertEqual(filled_count, expected_filled,
f"For rating {rating_value}, should display {expected_filled} filled stars, got {filled_count}")
self.assertEqual(empty_count, expected_empty,
f"For rating {rating_value}, should display {expected_empty} empty stars, got {empty_count}")
# Verify total is always 5 stars
self.assertEqual(filled_count + empty_count, 5,
"Total stars should always be 5")
# Feature: helpdesk-rating-five-stars, Property 13: Ticket view displays rating stars
@given(rating_value=st.one_of(
st.just(0.0), # No rating
st.floats(min_value=1.0, max_value=5.0, allow_nan=False, allow_infinity=False) # Valid ratings
))
@settings(max_examples=100, deadline=None)
def test_property_ticket_view_displays_rating_stars(self, rating_value):
"""
Property 13: Ticket view displays rating stars
For any ticket with a rating, the backend view should display
the rating as filled star icons.
Validates: Requirements 5.1
"""
# Create ticket with rating
ticket = self._create_ticket_with_rating(rating_value)
# Get the HTML representation
html = ticket.rating_stars_html
# Verify HTML is generated
self.assertTrue(html, "HTML should be generated for ticket")
# Verify HTML contains star structure
self.assertIn('o_rating_stars', html,
"HTML should contain rating stars class")
# Verify stars are present
has_filled_stars = '' in html
has_empty_stars = '' in html
self.assertTrue(has_filled_stars or has_empty_stars,
"HTML should contain star characters")
# For non-zero ratings, verify filled stars match rating
if rating_value > 0:
filled_count = html.count('')
expected_filled = round(rating_value)
self.assertEqual(filled_count, expected_filled,
f"For rating {rating_value}, should display {expected_filled} filled stars")
else:
# For zero rating, should display 5 empty stars
empty_count = html.count('')
self.assertEqual(empty_count, 5,
"For zero rating, should display 5 empty stars")
def test_ticket_without_rating_displays_empty_stars(self):
"""Test that tickets without ratings display empty stars or 'Not Rated'"""
# Create ticket without rating
ticket = self._create_ticket_with_rating(None)
# Get the HTML representation
html = ticket.rating_stars_html
# Verify HTML is generated
self.assertTrue(html, "HTML should be generated even without rating")
# Should display 5 empty stars
empty_count = html.count('')
self.assertEqual(empty_count, 5,
"Ticket without rating should display 5 empty stars")
# Should not have filled stars
filled_count = html.count('')
self.assertEqual(filled_count, 0,
"Ticket without rating should have no filled stars")
def test_ticket_with_multiple_ratings_uses_most_recent(self):
"""Test that when a ticket has multiple ratings, the most recent is displayed"""
# Create ticket
ticket = self.HelpdeskTicket.create({
'name': 'Test Ticket',
'partner_id': self.test_partner.id,
'team_id': self.helpdesk_team.id,
})
# Create first rating
rating1 = self.Rating.create({
'rating': 2.0,
'partner_id': self.test_partner.id,
'rated_partner_id': self.test_user.partner_id.id,
'res_model': 'helpdesk.ticket',
'res_id': ticket.id,
})
# Create second rating (more recent)
rating2 = self.Rating.create({
'rating': 5.0,
'partner_id': self.test_partner.id,
'rated_partner_id': self.test_user.partner_id.id,
'res_model': 'helpdesk.ticket',
'res_id': ticket.id,
})
# Don't invalidate - just access the computed field directly
# The ORM will handle the relationship correctly
# Get the HTML representation
html = ticket.rating_stars_html
# Should display 5 filled stars (from most recent rating)
filled_count = html.count('')
self.assertEqual(filled_count, 5,
"Should display stars from most recent rating (5 stars)")