""" 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'