Files
scenar-creator/tests/test_inline_builder.py
Martin Sukany b7b56fe15f
Some checks failed
Build & Push Docker / build (push) Has been cancelled
Refactor: Oddělení business logiky + inline editor
- Nový modul scenar/core.py (491 řádků čisté logiky)
- Refactored cgi-bin/scenar.py (450 řádků CGI wrapper)
- Inline editor s JavaScript row managementem
- Custom exceptions (ScenarsError, ValidationError, TemplateError)
- Kompletní test coverage (10 testů, všechny )
- Fixed Dockerfile (COPY scenar/, requirements.txt)
- Fixed requirements.txt (openpyxl==3.1.5)
- Fixed pytest.ini (pythonpath = .)
- Nové testy: test_http_inline.py, test_inline_builder.py
- HTTP testy označeny jako @pytest.mark.integration
- Build script: scripts/build_image.sh
- Dokumentace: COMPLETION.md
2025-11-13 16:06:32 +01:00

262 lines
7.5 KiB
Python

"""
End-to-end tests for inline builder (without Excel upload).
Tests the full form submission flow from HTML form to timetable generation.
"""
import pytest
from datetime import date, time
import pandas as pd
from scenar.core import parse_inline_schedule, parse_inline_types, create_timetable, ValidationError
def test_inline_builder_valid_form():
"""Test inline builder with valid schedule and types."""
# Simulate form data from HTML
form_data = {
# Metadata
'title': 'Test Conference',
'detail': 'Testing inline builder',
'step': 'builder',
# Schedule rows (2 rows)
'datum_0': '2025-11-13',
'zacatek_0': '09:00',
'konec_0': '10:00',
'program_0': 'Opening Keynote',
'typ_0': 'KEYNOTE',
'garant_0': 'Dr. Smith',
'poznamka_0': 'Welcome speech',
'datum_1': '2025-11-13',
'zacatek_1': '10:30',
'konec_1': '11:30',
'program_1': 'Workshop: Python',
'typ_1': 'WORKSHOP',
'garant_1': 'Jane Doe',
'poznamka_1': 'Hands-on coding',
# Type definitions
'type_name_0': 'KEYNOTE',
'type_desc_0': 'Main Address',
'type_color_0': '#FF0000',
'type_name_1': 'WORKSHOP',
'type_desc_1': 'Interactive Session',
'type_color_1': '#0070C0',
}
# Parse schedule
schedule = parse_inline_schedule(form_data)
assert len(schedule) == 2
assert schedule.iloc[0]['Program'] == 'Opening Keynote'
assert schedule.iloc[0]['Typ'] == 'KEYNOTE'
# Parse types
descriptions, colors = parse_inline_types(form_data)
assert len(descriptions) == 2
assert descriptions['KEYNOTE'] == 'Main Address'
assert colors['KEYNOTE'] == 'FFFF0000'
# Generate timetable
wb = create_timetable(
schedule,
title=form_data['title'],
detail=form_data['detail'],
program_descriptions=descriptions,
program_colors=colors
)
assert wb is not None
ws = wb.active
assert ws['A1'].value == 'Test Conference'
assert ws['A2'].value == 'Testing inline builder'
def test_inline_builder_missing_type_definition():
"""Test that undefined type in schedule raises error."""
form_data = {
'title': 'Bad Conference',
'detail': 'Missing type definition',
# Schedule with UNKNOWN type
'datum_0': '2025-11-13',
'zacatek_0': '09:00',
'konec_0': '10:00',
'program_0': 'Unknown Program',
'typ_0': 'UNKNOWN_TYPE', # This type is not defined below!
'garant_0': 'Someone',
'poznamka_0': '',
# Only define LECTURE, not UNKNOWN_TYPE
'type_name_0': 'LECTURE',
'type_desc_0': 'Standard Lecture',
'type_color_0': '#3498db',
}
schedule = parse_inline_schedule(form_data)
descriptions, colors = parse_inline_types(form_data)
# Should fail because UNKNOWN_TYPE is not in colors dict
with pytest.raises(Exception): # ScenarsError
create_timetable(schedule, 'Bad', 'Bad', descriptions, colors)
def test_inline_builder_empty_type_definition():
"""Test that empty type definitions are skipped."""
form_data = {
'title': 'Conference',
'detail': 'With empty types',
'datum_0': '2025-11-13',
'zacatek_0': '09:00',
'konec_0': '10:00',
'program_0': 'Program 1',
'typ_0': 'WORKSHOP',
'garant_0': 'John',
'poznamka_0': '',
# One empty type definition (should be skipped)
'type_name_0': '',
'type_desc_0': 'Empty type',
'type_color_0': '#FF0000',
# One valid type
'type_name_1': 'WORKSHOP',
'type_desc_1': 'Workshop Type',
'type_color_1': '#0070C0',
}
descriptions, colors = parse_inline_types(form_data)
# Empty type should be skipped
assert 'WORKSHOP' in descriptions
assert '' not in descriptions
def test_inline_builder_overlapping_times():
"""Test schedule with overlapping time slots."""
form_data = {
'title': 'Conference',
'detail': 'Overlapping schedule',
# Two programs at same time
'datum_0': '2025-11-13',
'zacatek_0': '09:00',
'konec_0': '10:00',
'program_0': 'Program A',
'typ_0': 'WORKSHOP',
'garant_0': 'John',
'poznamka_0': '',
'datum_1': '2025-11-13',
'zacatek_1': '09:30', # Overlaps with Program A
'konec_1': '10:30',
'program_1': 'Program B',
'typ_1': 'WORKSHOP',
'garant_1': 'Jane',
'poznamka_1': '',
'type_name_0': 'WORKSHOP',
'type_desc_0': 'Workshop',
'type_color_0': '#0070C0',
}
schedule = parse_inline_schedule(form_data)
descriptions, colors = parse_inline_types(form_data)
# Should allow overlapping times — timetable will show them
assert len(schedule) == 2
# Generate timetable (may have rendering issues but should complete)
wb = create_timetable(schedule, 'Conf', 'Test', descriptions, colors)
assert wb is not None
def test_inline_builder_multiday():
"""Test schedule spanning multiple days."""
form_data = {
'title': 'Multi-day Conference',
'detail': 'Two-day event',
# Day 1
'datum_0': '2025-11-13',
'zacatek_0': '09:00',
'konec_0': '10:00',
'program_0': 'Day 1 Opening',
'typ_0': 'KEYNOTE',
'garant_0': 'Dr. A',
'poznamka_0': '',
# Day 2
'datum_1': '2025-11-14',
'zacatek_1': '09:00',
'konec_1': '10:00',
'program_1': 'Day 2 Opening',
'typ_1': 'KEYNOTE',
'garant_1': 'Dr. B',
'poznamka_1': '',
'type_name_0': 'KEYNOTE',
'type_desc_0': 'Keynote Speech',
'type_color_0': '#FF6600',
}
schedule = parse_inline_schedule(form_data)
descriptions, colors = parse_inline_types(form_data)
wb = create_timetable(schedule, 'Multi-day', 'Test', descriptions, colors)
assert wb is not None
ws = wb.active
# Should have multiple date rows
assert ws['A1'].value == 'Multi-day'
def test_inline_builder_validation_errors():
"""Test validation of inline form data."""
# Missing required field
form_data_missing = {
'datum_0': '2025-11-13',
# Missing zacatek_0, konec_0, program_0, typ_0
'garant_0': 'John',
}
with pytest.raises(ValidationError):
parse_inline_schedule(form_data_missing)
def test_inline_builder_with_empty_rows():
"""Test that empty schedule rows are skipped."""
form_data = {
'title': 'Test',
'detail': 'With empty rows',
# Valid row
'datum_0': '2025-11-13',
'zacatek_0': '09:00',
'konec_0': '10:00',
'program_0': 'Program 1',
'typ_0': 'WORKSHOP',
'garant_0': 'John',
'poznamka_0': '',
# Empty row (all fields missing)
'datum_1': '',
'zacatek_1': '',
'konec_1': '',
'program_1': '',
'typ_1': '',
'garant_1': '',
'poznamka_1': '',
'type_name_0': 'WORKSHOP',
'type_desc_0': 'Workshop',
'type_color_0': '#0070C0',
}
schedule = parse_inline_schedule(form_data)
# Should only have 1 row (empty row skipped)
assert len(schedule) == 1
assert schedule.iloc[0]['Program'] == 'Program 1'