loko/streetup/home/tests.py

295 lines
12 KiB
Python

from django.contrib.auth import get_user_model
from django.test import TestCase
from datetime import date
from common.models import Role, Thematic, UserConfig, UserThematics
from contracts.models import Company, CompanyTeam, Contract
from home.models import HomeWidget, HomeWidgetConditionGroup, HomeWidgetCondition, TeambuildingVote
class HomeWidgetConditionTests(TestCase):
def setUp(self):
User = get_user_model()
self.user = User.objects.create_user('testuser', password='pass')
self.user_config = UserConfig.objects.create(user=self.user, is_intern=True)
self.widget = HomeWidget.objects.create(widget_code='intervention_stats')
self.group = HomeWidgetConditionGroup.objects.create(
widget=self.widget,
label='Test Group',
order=1,
priority=10
)
# Role
self.role_admin, _ = Role.objects.get_or_create(name='admin')
self.role_tech, _ = Role.objects.get_or_create(name='technician')
# Team
self.company = Company.objects.create(name='Test Company')
self.team_a = CompanyTeam.objects.create(name='Team A', company=self.company)
self.team_b = CompanyTeam.objects.create(name='Team B', company=self.company)
# Contract
self.contract_a = Contract.objects.create(
company=self.company,
contract_number='C-001',
start_date=date(2026, 1, 1),
end_date=date(2026, 12, 31)
)
self.contract_b = Contract.objects.create(
company=self.company,
contract_number='C-002',
start_date=date(2026, 1, 1),
end_date=date(2026, 12, 31)
)
# Thematic
self.thematic_a = Thematic.objects.create(code='THEME-A', name_fr='Thema A', name_nl='Thema A')
self.thematic_b = Thematic.objects.create(code='THEME-B', name_fr='Thema B', name_nl='Thema B')
def test_role_condition_evaluation(self):
# 1. Non-negated: User has role -> True
self.user_config.roles.add(self.role_admin)
cond = HomeWidgetCondition.objects.create(
group=self.group,
condition_type='role',
role=self.role_admin,
is_negated=False
)
self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none()))
# User does not have role -> False
cond.role = self.role_tech
cond.save()
self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none()))
# 2. Negated: User has role -> False
cond.role = self.role_admin
cond.is_negated = True
cond.save()
self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none()))
# User does not have role -> True
cond.role = self.role_tech
self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none()))
def test_team_condition_evaluation(self):
# 1. Non-negated: User team matches -> True
cond = HomeWidgetCondition.objects.create(
group=self.group,
condition_type='team',
team=self.team_a,
is_negated=False
)
self.assertTrue(cond.evaluate(self.user_config, self.team_a, Contract.objects.none()))
# User team does not match -> False
self.assertFalse(cond.evaluate(self.user_config, self.team_b, Contract.objects.none()))
self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none()))
# 2. Negated: User team matches -> False
cond.is_negated = True
cond.save()
self.assertFalse(cond.evaluate(self.user_config, self.team_a, Contract.objects.none()))
# User team does not match -> True
self.assertTrue(cond.evaluate(self.user_config, self.team_b, Contract.objects.none()))
self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none()))
def test_contract_condition_evaluation(self):
# 1. Non-negated: User has contract -> True
cond = HomeWidgetCondition.objects.create(
group=self.group,
condition_type='contract',
contract=self.contract_a,
is_negated=False
)
user_contracts = Contract.objects.filter(id=self.contract_a.id)
self.assertTrue(cond.evaluate(self.user_config, None, user_contracts))
# User does not have contract -> False
other_contracts = Contract.objects.filter(id=self.contract_b.id)
self.assertFalse(cond.evaluate(self.user_config, None, other_contracts))
# 2. Negated: User has contract -> False
cond.is_negated = True
cond.save()
self.assertFalse(cond.evaluate(self.user_config, None, user_contracts))
# User does not have contract -> True
self.assertTrue(cond.evaluate(self.user_config, None, other_contracts))
def test_thematic_condition_evaluation(self):
# 1. Non-negated: User has thematic -> True
UserThematics.objects.create(user_config=self.user_config, thematic=self.thematic_a)
cond = HomeWidgetCondition.objects.create(
group=self.group,
condition_type='thematic',
thematic=self.thematic_a,
is_negated=False
)
self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none()))
# User does not have thematic -> False
cond.thematic = self.thematic_b
cond.save()
self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none()))
# 2. Negated: User has thematic -> False
cond.thematic = self.thematic_a
cond.is_negated = True
cond.save()
self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none()))
# User does not have thematic -> True
cond.thematic = self.thematic_b
self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none()))
def test_is_intern_condition_evaluation(self):
# 1. Non-negated: matches -> True
cond = HomeWidgetCondition.objects.create(
group=self.group,
condition_type='is_intern',
is_intern=True,
is_negated=False
)
self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none()))
# Does not match -> False
cond.is_intern = False
cond.save()
self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none()))
# 2. Negated: matches -> False
cond.is_intern = True
cond.is_negated = True
cond.save()
self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none()))
# Does not match -> True
cond.is_intern = False
self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none()))
def test_condition_summary_and_string_representation(self):
cond = HomeWidgetCondition.objects.create(
group=self.group,
condition_type='role',
role=self.role_admin,
is_negated=False
)
self.assertEqual(str(cond), "Role: admin")
self.assertEqual(self.group.get_summary(), "role=admin")
cond.is_negated = True
cond.save()
self.assertEqual(str(cond), "NOT Role: admin")
self.assertEqual(self.group.get_summary(), "not(role=admin)")
class TeambuildingVoteViewsTests(TestCase):
def test_flexi_teambuilding_get(self):
# Page should be publicly accessible without logging in
response = self.client.get("/flexi-teambuilding/")
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "home/flexi_teambuilding.html")
def test_flexi_teambuilding_post(self):
# Submit a vote (publicly accessible)
response = self.client.post("/flexi-teambuilding/", {
"voter_name": "Jean-Luc",
"vote_gael": "3",
"vote_charly": "2",
"vote_tequila": "1",
"vote_vivien": "0"
})
# Should redirect to results page with success query param
self.assertRedirects(response, "/flexi-teambuilding/results/?success=1")
# Verify the database entry
self.assertEqual(TeambuildingVote.objects.count(), 1)
vote = TeambuildingVote.objects.first()
self.assertEqual(vote.voter_name, "Jean-Luc")
self.assertEqual(vote.vote_gael, 3)
self.assertEqual(vote.vote_charly, 2)
self.assertEqual(vote.vote_tequila, 1)
self.assertEqual(vote.vote_vivien, 0)
def test_flexi_teambuilding_results_calculation(self):
# Create dummy votes
TeambuildingVote.objects.create(
voter_name="Alice",
vote_gael=3,
vote_charly=2,
vote_tequila=1,
vote_vivien=0
)
TeambuildingVote.objects.create(
voter_name="Bob",
vote_gael=1,
vote_charly=2,
vote_tequila=3,
vote_vivien=3
)
# Access results page (publicly accessible)
response = self.client.get("/flexi-teambuilding/results/")
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "home/flexi_teambuilding_results.html")
# Check context averages
self.assertEqual(response.context["total_votes"], 2)
self.assertEqual(response.context["avg_gael"], 2.0)
self.assertEqual(response.context["avg_charly"], 2.0)
self.assertEqual(response.context["avg_tequila"], 2.0)
self.assertEqual(response.context["avg_vivien"], 1.5)
self.assertEqual(response.context["pct_gael"], 66.7)
self.assertEqual(response.context["pct_charly"], 66.7)
self.assertEqual(response.context["pct_tequila"], 66.7)
self.assertEqual(response.context["pct_vivien"], 50.0)
class HomeIndexViewTests(TestCase):
def test_home_index_inspector_link(self):
from django.urls import reverse
from django.contrib.auth import get_user_model
from common.models import Role, UserConfig
User = get_user_model()
user = User.objects.create_user('inspector_user', password='pass')
user_config = UserConfig.objects.create(user=user)
inspector_role, _ = Role.objects.get_or_create(name='inspector')
user_config.roles.add(inspector_role)
self.client.force_login(user)
response = self.client.get(reverse('home:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, reverse('inspections:quick_inspection_map'))
self.assertNotContains(response, 'data-bs-target="#newInspectionModal"')
def test_home_index_unread_notifications_banner(self):
from django.urls import reverse
from django.contrib.auth import get_user_model
from common.models import UserConfig
from notifications.models import Notification, NotificationRecipient
User = get_user_model()
user = User.objects.create_user('notif_user', password='pass')
UserConfig.objects.create(user=user)
self.client.force_login(user)
# 1. No unread notifications -> banner not shown
response = self.client.get(reverse('home:index'))
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, 'id="home-unread-notifications-alert"')
# 2. Add unread notification -> banner shown with count
notif = Notification.objects.create(title="Test notification")
NotificationRecipient.objects.create(notification=notif, user=user)
response = self.client.get(reverse('home:index'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'id="home-unread-notifications-alert"')
self.assertContains(response, 'Vous avez <strong class="home-unread-notifications-count">1</strong> notification non lue.')