textes revues et traduction
This commit is contained in:
0
apps/core/templatetags/__init__.py
Normal file
0
apps/core/templatetags/__init__.py
Normal file
16
apps/core/templatetags/i18n_switch.py
Normal file
16
apps/core/templatetags/i18n_switch.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from django import template
|
||||
from django.urls import translate_url
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def switch_lang_url(context, lang_code):
|
||||
request = context.get('request')
|
||||
if not request:
|
||||
return '/' if lang_code == 'fr' else '/en/'
|
||||
current_path = request.get_full_path()
|
||||
translated = translate_url(current_path, lang_code)
|
||||
if translated == current_path:
|
||||
return '/' if lang_code == 'fr' else '/en/'
|
||||
return translated
|
||||
@@ -1,3 +1,221 @@
|
||||
from django.test import TestCase
|
||||
import json
|
||||
from django.test import TestCase, Client, RequestFactory, override_settings
|
||||
from django.urls import reverse
|
||||
from .models import ContactRequest
|
||||
from .context_processors import site_context
|
||||
|
||||
# Create your tests here.
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Helpers
|
||||
# ─────────────────────────────────────────────
|
||||
VALID_CONTACT = {
|
||||
'last_name': 'Coulibaly',
|
||||
'first_name': 'Israel',
|
||||
'email': 'test@jool-int.com',
|
||||
'phone': '+225 07 00 00 00',
|
||||
'message': 'Demande de démonstration.',
|
||||
}
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Pages publiques — codes HTTP
|
||||
# ─────────────────────────────────────────────
|
||||
class PublicPagesTest(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
|
||||
def _get(self, name):
|
||||
return self.client.get(reverse(f'core:{name}'))
|
||||
|
||||
def test_home_200(self):
|
||||
self.assertEqual(self._get('home').status_code, 200)
|
||||
|
||||
def test_about_200(self):
|
||||
self.assertEqual(self._get('about').status_code, 200)
|
||||
|
||||
def test_kiriq_200(self):
|
||||
self.assertEqual(self._get('kiriq').status_code, 200)
|
||||
|
||||
def test_monitor_200(self):
|
||||
self.assertEqual(self._get('monitor').status_code, 200)
|
||||
|
||||
def test_joolid_200(self):
|
||||
self.assertEqual(self._get('joolid').status_code, 200)
|
||||
|
||||
def test_monagro_200(self):
|
||||
self.assertEqual(self._get('monagro').status_code, 200)
|
||||
|
||||
def test_privacy_200(self):
|
||||
self.assertEqual(self._get('privacy').status_code, 200)
|
||||
|
||||
def test_robots_txt_200(self):
|
||||
r = self._get('robots_txt')
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertIn('text/plain', r['Content-Type'])
|
||||
|
||||
def test_sitemap_xml_200(self):
|
||||
r = self._get('sitemap_xml')
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertIn('xml', r['Content-Type'])
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Templates — contenu minimal
|
||||
# ─────────────────────────────────────────────
|
||||
class TemplateContentTest(TestCase):
|
||||
def test_home_contains_products(self):
|
||||
r = self.client.get(reverse('core:home'))
|
||||
self.assertContains(r, 'KIRIQ')
|
||||
self.assertContains(r, 'Jool Monitor')
|
||||
self.assertContains(r, 'Jool ID')
|
||||
self.assertContains(r, 'Mon Agro')
|
||||
|
||||
def test_kiriq_page_title(self):
|
||||
r = self.client.get(reverse('core:kiriq'))
|
||||
self.assertContains(r, 'KIRIQ')
|
||||
|
||||
def test_monitor_page_title(self):
|
||||
r = self.client.get(reverse('core:monitor'))
|
||||
self.assertContains(r, 'Monitor')
|
||||
|
||||
def test_joolid_page_title(self):
|
||||
r = self.client.get(reverse('core:joolid'))
|
||||
self.assertContains(r, 'Jool ID')
|
||||
|
||||
def test_monagro_page_title(self):
|
||||
r = self.client.get(reverse('core:monagro'))
|
||||
self.assertContains(r, 'Mon Agro')
|
||||
|
||||
def test_about_has_solutions_section(self):
|
||||
r = self.client.get(reverse('core:about'))
|
||||
self.assertContains(r, 'Nos solutions')
|
||||
self.assertContains(r, 'Mon Agro')
|
||||
|
||||
def test_privacy_noindex(self):
|
||||
r = self.client.get(reverse('core:privacy'))
|
||||
self.assertContains(r, 'noindex')
|
||||
|
||||
def test_robots_txt_content(self):
|
||||
r = self.client.get(reverse('core:robots_txt'))
|
||||
content = r.content.decode()
|
||||
self.assertIn('User-agent', content)
|
||||
self.assertIn('sitemap', content.lower())
|
||||
|
||||
def test_sitemap_xml_has_urls(self):
|
||||
r = self.client.get(reverse('core:sitemap_xml'))
|
||||
content = r.content.decode()
|
||||
self.assertIn('<url>', content)
|
||||
self.assertIn('jool-international.com', content)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Formulaire de contact
|
||||
# ─────────────────────────────────────────────
|
||||
class ContactFormTest(TestCase):
|
||||
def setUp(self):
|
||||
self.url = reverse('core:contact_ajax')
|
||||
|
||||
def _post(self, data):
|
||||
return self.client.post(
|
||||
self.url, data,
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
)
|
||||
|
||||
@override_settings(
|
||||
EMAIL_BACKEND='django.core.mail.backends.dummy.EmailBackend'
|
||||
)
|
||||
def test_valid_form_creates_contact(self):
|
||||
r = self._post(VALID_CONTACT)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
body = json.loads(r.content)
|
||||
self.assertTrue(body['ok'])
|
||||
self.assertEqual(ContactRequest.objects.count(), 1)
|
||||
obj = ContactRequest.objects.first()
|
||||
self.assertEqual(obj.email, 'test@jool-int.com')
|
||||
|
||||
def test_missing_required_fields_returns_400(self):
|
||||
r = self._post({'last_name': 'Coulibaly'})
|
||||
self.assertEqual(r.status_code, 400)
|
||||
body = json.loads(r.content)
|
||||
self.assertFalse(body['ok'])
|
||||
self.assertIn('errors', body)
|
||||
|
||||
def test_invalid_email_returns_400(self):
|
||||
data = {**VALID_CONTACT, 'email': 'pas-un-email'}
|
||||
r = self._post(data)
|
||||
self.assertEqual(r.status_code, 400)
|
||||
body = json.loads(r.content)
|
||||
self.assertFalse(body['ok'])
|
||||
|
||||
def test_invalid_phone_returns_400(self):
|
||||
data = {**VALID_CONTACT, 'phone': 'abc!!!'}
|
||||
r = self._post(data)
|
||||
self.assertEqual(r.status_code, 400)
|
||||
body = json.loads(r.content)
|
||||
self.assertFalse(body['ok'])
|
||||
|
||||
def test_get_method_not_allowed(self):
|
||||
r = self.client.get(self.url)
|
||||
self.assertEqual(r.status_code, 405)
|
||||
|
||||
@override_settings(
|
||||
EMAIL_BACKEND='django.core.mail.backends.dummy.EmailBackend'
|
||||
)
|
||||
def test_phone_optional(self):
|
||||
data = {k: v for k, v in VALID_CONTACT.items() if k != 'phone'}
|
||||
r = self._post(data)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(json.loads(r.content)['ok'])
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Modèle ContactRequest
|
||||
# ─────────────────────────────────────────────
|
||||
class ContactRequestModelTest(TestCase):
|
||||
def test_str_representation(self):
|
||||
obj = ContactRequest(
|
||||
first_name='Israel',
|
||||
last_name='Coulibaly',
|
||||
email='test@jool-int.com',
|
||||
)
|
||||
self.assertIn('Israel', str(obj))
|
||||
self.assertIn('Coulibaly', str(obj))
|
||||
|
||||
def test_is_read_default_false(self):
|
||||
obj = ContactRequest.objects.create(**VALID_CONTACT)
|
||||
self.assertFalse(obj.is_read)
|
||||
|
||||
def test_ordering_newest_first(self):
|
||||
ContactRequest.objects.create(**VALID_CONTACT)
|
||||
data2 = {**VALID_CONTACT, 'email': 'second@jool-int.com'}
|
||||
ContactRequest.objects.create(**data2)
|
||||
first = ContactRequest.objects.first()
|
||||
self.assertEqual(first.email, 'second@jool-int.com')
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Context processor — careers_enabled
|
||||
# ─────────────────────────────────────────────
|
||||
class ContextProcessorTest(TestCase):
|
||||
def setUp(self):
|
||||
self.factory = RequestFactory()
|
||||
|
||||
@override_settings(CAREERS_ENABLED=False)
|
||||
def test_careers_disabled_in_context(self):
|
||||
r = self.client.get(reverse('core:home'))
|
||||
self.assertFalse(r.context['careers_enabled'])
|
||||
self.assertNotContains(r, 'Carrières')
|
||||
|
||||
@override_settings(CAREERS_ENABLED=False)
|
||||
def test_careers_disabled_returns_false(self):
|
||||
request = self.factory.get('/')
|
||||
ctx = site_context(request)
|
||||
self.assertFalse(ctx['careers_enabled'])
|
||||
self.assertEqual(ctx['open_jobs_count'], 0)
|
||||
|
||||
@override_settings(CAREERS_ENABLED=True)
|
||||
def test_careers_enabled_returns_true(self):
|
||||
request = self.factory.get('/')
|
||||
ctx = site_context(request)
|
||||
self.assertTrue(ctx['careers_enabled'])
|
||||
self.assertIn('open_jobs_count', ctx)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from django.urls import path
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from . import views
|
||||
|
||||
app_name = 'core'
|
||||
@@ -6,12 +7,13 @@ app_name = 'core'
|
||||
urlpatterns = [
|
||||
path('', views.HomeView.as_view(), name='home'),
|
||||
path('contact/', views.ContactAjaxView.as_view(), name='contact_ajax'),
|
||||
path('a-propos/', views.AboutView.as_view(), name='about'),
|
||||
path('produits/kiriq/', views.KiriqView.as_view(), name='kiriq'),
|
||||
path('produits/monitor/', views.MonitorView.as_view(), name='monitor'),
|
||||
path('produits/joolid/', views.JoolidView.as_view(), name='joolid'),
|
||||
path('confidentialite/', views.PrivacyView.as_view(), name='privacy'),
|
||||
# SEO
|
||||
path(_('a-propos/'), views.AboutView.as_view(), name='about'),
|
||||
path(_('produits/kiriq/'), views.KiriqView.as_view(), name='kiriq'),
|
||||
path(_('produits/monitor/'), views.MonitorView.as_view(), name='monitor'),
|
||||
path(_('produits/joolid/'), views.JoolidView.as_view(), name='joolid'),
|
||||
path(_('produits/monagro/'), views.MonAgroView.as_view(), name='monagro'),
|
||||
path(_('confidentialite/'), views.PrivacyView.as_view(), name='privacy'),
|
||||
# SEO — non traduits
|
||||
path('robots.txt', views.RobotsTxtView.as_view(), name='robots_txt'),
|
||||
path('sitemap.xml', views.SitemapXmlView.as_view(), name='sitemap_xml'),
|
||||
]
|
||||
|
||||
@@ -61,6 +61,10 @@ class JoolidView(TemplateView):
|
||||
template_name = 'core/products/joolid.html'
|
||||
|
||||
|
||||
class MonAgroView(TemplateView):
|
||||
template_name = 'core/products/monagro.html'
|
||||
|
||||
|
||||
class PrivacyView(TemplateView):
|
||||
template_name = 'core/privacy.html'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user