- Replaced feed-* inline styles in base.html with feed-cards.css component (~60 lines) - Replaced ios-search inline styles in 3 templates with ios-search.css component * employees/employees_list.html * search/results.html * employees/department_list.html - Eliminated ~150 lines of duplicate CSS across templates - All 17 tests passing
165 lines
6.8 KiB
Python
165 lines
6.8 KiB
Python
"""
|
||
Тесты для проверки синтаксиса компонентов шаблонов.
|
||
Проверяет, что компоненты не содержат тегов, принадлежащих родительским layout'ам.
|
||
"""
|
||
import os
|
||
from pathlib import Path
|
||
from django.test import TestCase
|
||
from django.template import loader, TemplateSyntaxError
|
||
|
||
|
||
class TemplateComponentsTestCase(TestCase):
|
||
"""Тесты синтаксиса компонентов шаблонов"""
|
||
|
||
# Список всех компонентов для проверки
|
||
COMPONENTS = [
|
||
# Компоненты employees/department
|
||
'employees/components/department_header.html',
|
||
'employees/components/department_info.html',
|
||
'employees/components/department_team_circle.html',
|
||
'employees/components/department_sidebar.html',
|
||
'employees/components/department_modals.html',
|
||
'employees/components/department_scripts.html',
|
||
'employees/components/department_styles.html',
|
||
|
||
# Компоненты employees/employee_form
|
||
'employees/components/employee_form_personal.html',
|
||
'employees/components/employee_form_contact.html',
|
||
'employees/components/employee_form_position.html',
|
||
'employees/components/employee_form_actions.html',
|
||
'employees/components/employee_form_scripts.html',
|
||
'employees/_employee_edit.html',
|
||
]
|
||
|
||
# Главные шаблоны, которые используют компоненты
|
||
MAIN_TEMPLATES = [
|
||
'employees/department_detail.html',
|
||
'includes/rightbar_calendar.html',
|
||
]
|
||
|
||
# Недопустимые теги в компонентах (они должны быть только в layout'ах)
|
||
FORBIDDEN_TAGS = [
|
||
'{% extends ',
|
||
'{% block content %}',
|
||
'{% block extra_css %}',
|
||
'{% block extra_js %}',
|
||
]
|
||
|
||
def test_components_syntax(self):
|
||
"""Проверка синтаксиса всех компонентов через Django template loader"""
|
||
errors = []
|
||
|
||
for template_path in self.COMPONENTS:
|
||
try:
|
||
loader.get_template(template_path)
|
||
except TemplateSyntaxError as e:
|
||
errors.append(f"{template_path}: {e}")
|
||
except Exception as e:
|
||
errors.append(f"{template_path}: Unexpected error - {e}")
|
||
|
||
if errors:
|
||
error_msg = "\n".join([f" - {err}" for err in errors])
|
||
self.fail(f"Found {len(errors)} template syntax errors:\n{error_msg}")
|
||
|
||
def test_main_templates_syntax(self):
|
||
"""Проверка синтаксиса главных шаблонов"""
|
||
errors = []
|
||
|
||
for template_path in self.MAIN_TEMPLATES:
|
||
try:
|
||
loader.get_template(template_path)
|
||
except TemplateSyntaxError as e:
|
||
errors.append(f"{template_path}: {e}")
|
||
except Exception as e:
|
||
errors.append(f"{template_path}: Unexpected error - {e}")
|
||
|
||
if errors:
|
||
error_msg = "\n".join([f" - {err}" for err in errors])
|
||
self.fail(f"Found {len(errors)} main template syntax errors:\n{error_msg}")
|
||
|
||
def test_components_no_forbidden_tags(self):
|
||
"""Проверка, что компоненты не содержат тегов layout'ов"""
|
||
from django.conf import settings
|
||
templates_dir = Path(settings.BASE_DIR) / 'templates'
|
||
|
||
errors = []
|
||
|
||
for template_path in self.COMPONENTS:
|
||
file_path = templates_dir / template_path
|
||
if not file_path.exists():
|
||
continue
|
||
|
||
content = file_path.read_text(encoding='utf-8')
|
||
|
||
# Проверка на недопустимые теги
|
||
for forbidden_tag in self.FORBIDDEN_TAGS:
|
||
if forbidden_tag in content:
|
||
errors.append(f"{template_path}: contains forbidden tag '{forbidden_tag}'")
|
||
|
||
if errors:
|
||
error_msg = "\n".join([f" - {err}" for err in errors])
|
||
self.fail(f"Found {len(errors)} components with forbidden layout tags:\n{error_msg}")
|
||
|
||
def test_components_no_orphan_endblock(self):
|
||
"""Проверка, что компоненты не содержат одиноких {% endblock %}"""
|
||
from django.conf import settings
|
||
templates_dir = Path(settings.BASE_DIR) / 'templates'
|
||
|
||
errors = []
|
||
|
||
for template_path in self.COMPONENTS:
|
||
file_path = templates_dir / template_path
|
||
if not file_path.exists():
|
||
continue
|
||
|
||
content = file_path.read_text(encoding='utf-8')
|
||
|
||
# Проверка на {% endblock %} (должен быть только в layout'ах)
|
||
if '{% endblock %}' in content or '{% endblock' in content:
|
||
# Получаем номера строк с endblock
|
||
lines_with_endblock = [
|
||
i + 1 for i, line in enumerate(content.splitlines())
|
||
if '{% endblock' in line
|
||
]
|
||
errors.append(
|
||
f"{template_path}: contains orphan {{% endblock %}} on line(s) {lines_with_endblock}"
|
||
)
|
||
|
||
if errors:
|
||
error_msg = "\n".join([f" - {err}" for err in errors])
|
||
self.fail(f"Found {len(errors)} components with orphan endblock tags:\n{error_msg}")
|
||
|
||
def test_balanced_tags(self):
|
||
"""Проверка баланса открывающих/закрывающих тегов"""
|
||
from django.conf import settings
|
||
templates_dir = Path(settings.BASE_DIR) / 'templates'
|
||
|
||
errors = []
|
||
|
||
tag_pairs = [
|
||
('{% if ', '{% endif %}'),
|
||
('{% for ', '{% endfor %}'),
|
||
('{% with ', '{% endwith %}'),
|
||
]
|
||
|
||
for template_path in self.COMPONENTS:
|
||
file_path = templates_dir / template_path
|
||
if not file_path.exists():
|
||
continue
|
||
|
||
content = file_path.read_text(encoding='utf-8')
|
||
|
||
for open_tag, close_tag in tag_pairs:
|
||
open_count = content.count(open_tag)
|
||
close_count = content.count(close_tag)
|
||
|
||
if open_count != close_count:
|
||
errors.append(
|
||
f"{template_path}: unbalanced tags - "
|
||
f"{open_count} × '{open_tag}' but {close_count} × '{close_tag}'"
|
||
)
|
||
|
||
if errors:
|
||
error_msg = "\n".join([f" - {err}" for err in errors])
|
||
self.fail(f"Found {len(errors)} components with unbalanced tags:\n{error_msg}")
|