Implement comprehensive frontend integration testing with Playwright
- Add Playwright E2E testing framework with cross-browser support (Chrome, Firefox) - Create authentication helpers for CalDAV server integration - Implement calendar interaction helpers with event creation, drag-and-drop, and view switching - Add comprehensive drag-and-drop test suite with event cleanup - Configure CI/CD integration with Gitea Actions for headless testing - Support both local development and CI environments with proper dependency management - Include video recording, screenshots, and HTML reporting for test debugging - Handle Firefox-specific timing and interaction challenges with force clicks and timeouts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -36,3 +36,6 @@ pub use recurring_edit_modal::{RecurringEditAction, RecurringEditModal};
|
||||
pub use route_handler::RouteHandler;
|
||||
pub use sidebar::{Sidebar, Theme, ViewMode};
|
||||
pub use week_view::WeekView;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests;
|
||||
|
||||
96
frontend/src/components/tests/calendar_tests.rs
Normal file
96
frontend/src/components/tests/calendar_tests.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use wasm_bindgen_test::*;
|
||||
use chrono::{DateTime, Utc, TimeZone};
|
||||
use crate::components::{MonthView, WeekView};
|
||||
use crate::models::ical::VEvent;
|
||||
use yew::prelude::*;
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn month_view_renders_without_events() {
|
||||
let props = yew::props!(
|
||||
current_date: Utc.with_ymd_and_hms(2023, 12, 15, 0, 0, 0).unwrap(),
|
||||
events: vec![],
|
||||
on_event_click: Callback::noop(),
|
||||
on_date_click: Callback::noop(),
|
||||
on_event_drag: Callback::noop(),
|
||||
visible_calendar_paths: vec![],
|
||||
);
|
||||
|
||||
let _month_view = html! { <MonthView ..props /> };
|
||||
|
||||
// Test passes if no panic occurs during rendering
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn week_view_renders_without_events() {
|
||||
let props = yew::props!(
|
||||
current_date: Utc.with_ymd_and_hms(2023, 12, 15, 0, 0, 0).unwrap(),
|
||||
events: vec![],
|
||||
on_event_click: Callback::noop(),
|
||||
on_event_drag: Callback::noop(),
|
||||
visible_calendar_paths: vec![],
|
||||
);
|
||||
|
||||
let _week_view = html! { <WeekView ..props /> };
|
||||
|
||||
// Test passes if no panic occurs during rendering
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn month_view_handles_events() {
|
||||
// Create a test event
|
||||
let mut test_event = VEvent::new("test-event-123".to_string());
|
||||
test_event.summary = Some("Test Event".to_string());
|
||||
test_event.dtstart = Some(Utc.with_ymd_and_hms(2023, 12, 15, 14, 0, 0).unwrap());
|
||||
test_event.dtend = Some(Utc.with_ymd_and_hms(2023, 12, 15, 15, 0, 0).unwrap());
|
||||
|
||||
let props = yew::props!(
|
||||
current_date: Utc.with_ymd_and_hms(2023, 12, 15, 0, 0, 0).unwrap(),
|
||||
events: vec![test_event],
|
||||
on_event_click: Callback::noop(),
|
||||
on_date_click: Callback::noop(),
|
||||
on_event_drag: Callback::noop(),
|
||||
visible_calendar_paths: vec!["test-calendar".to_string()],
|
||||
);
|
||||
|
||||
let _month_view = html! { <MonthView ..props /> };
|
||||
|
||||
// Test passes if no panic occurs during rendering with events
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn week_view_handles_events() {
|
||||
// Create a test event
|
||||
let mut test_event = VEvent::new("test-event-456".to_string());
|
||||
test_event.summary = Some("Weekly Test Event".to_string());
|
||||
test_event.dtstart = Some(Utc.with_ymd_and_hms(2023, 12, 15, 10, 0, 0).unwrap());
|
||||
test_event.dtend = Some(Utc.with_ymd_and_hms(2023, 12, 15, 11, 30, 0).unwrap());
|
||||
|
||||
let props = yew::props!(
|
||||
current_date: Utc.with_ymd_and_hms(2023, 12, 15, 0, 0, 0).unwrap(),
|
||||
events: vec![test_event],
|
||||
on_event_click: Callback::noop(),
|
||||
on_event_drag: Callback::noop(),
|
||||
visible_calendar_paths: vec!["test-calendar".to_string()],
|
||||
);
|
||||
|
||||
let _week_view = html! { <WeekView ..props /> };
|
||||
|
||||
// Test passes if no panic occurs during rendering with events
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn event_time_calculations() {
|
||||
// Test event duration calculation
|
||||
let start_time = Utc.with_ymd_and_hms(2023, 12, 15, 10, 0, 0).unwrap();
|
||||
let end_time = Utc.with_ymd_and_hms(2023, 12, 15, 11, 30, 0).unwrap();
|
||||
|
||||
let duration = end_time - start_time;
|
||||
assert_eq!(duration.num_minutes(), 90);
|
||||
|
||||
// Test same-day event
|
||||
assert_eq!(start_time.date_naive(), end_time.date_naive());
|
||||
|
||||
// Test hour extraction
|
||||
assert_eq!(start_time.hour(), 10);
|
||||
assert_eq!(end_time.hour(), 11);
|
||||
}
|
||||
87
frontend/src/components/tests/event_modal_tests.rs
Normal file
87
frontend/src/components/tests/event_modal_tests.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
use wasm_bindgen_test::*;
|
||||
use yew::prelude::*;
|
||||
use chrono::{DateTime, Utc, TimeZone};
|
||||
use crate::components::EventModal;
|
||||
use crate::models::ical::VEvent;
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn event_modal_renders_in_create_mode() {
|
||||
let props = yew::props!(
|
||||
is_visible: true,
|
||||
on_close: Callback::noop(),
|
||||
on_save: Callback::noop(),
|
||||
event: None,
|
||||
calendars: vec![],
|
||||
default_date: Some(Utc.with_ymd_and_hms(2023, 12, 15, 0, 0, 0).unwrap()),
|
||||
default_time: Some("14:00".to_string()),
|
||||
on_delete: Callback::noop(),
|
||||
);
|
||||
|
||||
let _modal = html! { <EventModal ..props /> };
|
||||
|
||||
// Test passes if no panic occurs during rendering in create mode
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn event_modal_renders_in_edit_mode() {
|
||||
let mut test_event = VEvent::new("test-edit-event".to_string());
|
||||
test_event.summary = Some("Edit Test Event".to_string());
|
||||
test_event.dtstart = Some(Utc.with_ymd_and_hms(2023, 12, 15, 16, 0, 0).unwrap());
|
||||
test_event.dtend = Some(Utc.with_ymd_and_hms(2023, 12, 15, 17, 0, 0).unwrap());
|
||||
test_event.description = Some("Test description".to_string());
|
||||
|
||||
let props = yew::props!(
|
||||
is_visible: true,
|
||||
on_close: Callback::noop(),
|
||||
on_save: Callback::noop(),
|
||||
event: Some(test_event),
|
||||
calendars: vec![],
|
||||
default_date: None,
|
||||
default_time: None,
|
||||
on_delete: Callback::noop(),
|
||||
);
|
||||
|
||||
let _modal = html! { <EventModal ..props /> };
|
||||
|
||||
// Test passes if no panic occurs during rendering in edit mode
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn event_modal_renders_when_hidden() {
|
||||
let props = yew::props!(
|
||||
is_visible: false,
|
||||
on_close: Callback::noop(),
|
||||
on_save: Callback::noop(),
|
||||
event: None,
|
||||
calendars: vec![],
|
||||
default_date: None,
|
||||
default_time: None,
|
||||
on_delete: Callback::noop(),
|
||||
);
|
||||
|
||||
let _modal = html! { <EventModal ..props /> };
|
||||
|
||||
// Test passes if no panic occurs when modal is hidden
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn event_data_validation() {
|
||||
// Test event UID generation and validation
|
||||
let event = VEvent::new("test-uid-123".to_string());
|
||||
assert!(!event.uid.is_empty());
|
||||
assert_eq!(event.uid, "test-uid-123");
|
||||
|
||||
// Test event with summary
|
||||
let mut event_with_summary = VEvent::new("summary-test".to_string());
|
||||
event_with_summary.summary = Some("Test Summary".to_string());
|
||||
assert_eq!(event_with_summary.summary.unwrap(), "Test Summary");
|
||||
|
||||
// Test event time validation
|
||||
let start = Utc.with_ymd_and_hms(2023, 12, 15, 10, 0, 0).unwrap();
|
||||
let end = Utc.with_ymd_and_hms(2023, 12, 15, 11, 0, 0).unwrap();
|
||||
|
||||
assert!(end > start, "End time should be after start time");
|
||||
|
||||
let duration = end - start;
|
||||
assert_eq!(duration.num_hours(), 1, "Duration should be 1 hour");
|
||||
}
|
||||
8
frontend/src/components/tests/mod.rs
Normal file
8
frontend/src/components/tests/mod.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
// Configure tests to run in browser
|
||||
wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
pub mod sidebar_tests;
|
||||
pub mod calendar_tests;
|
||||
pub mod event_modal_tests;
|
||||
59
frontend/src/components/tests/sidebar_tests.rs
Normal file
59
frontend/src/components/tests/sidebar_tests.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use wasm_bindgen_test::*;
|
||||
use yew::prelude::*;
|
||||
use crate::components::{Sidebar, Theme, ViewMode};
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn sidebar_renders_correctly() {
|
||||
let props = yew::props!(
|
||||
theme: Theme::Default,
|
||||
on_theme_change: Callback::noop(),
|
||||
view_mode: ViewMode::Month,
|
||||
on_view_change: Callback::noop(),
|
||||
calendars: vec![],
|
||||
external_calendars: vec![],
|
||||
on_calendar_visibility_change: Callback::noop(),
|
||||
on_external_calendar_visibility_change: Callback::noop(),
|
||||
user_principal: Some("testuser".to_string()),
|
||||
on_logout: Callback::noop(),
|
||||
on_create_calendar: Callback::noop(),
|
||||
on_add_external_calendar: Callback::noop(),
|
||||
on_color_change: Callback::noop(),
|
||||
color_picker_open: None,
|
||||
on_color_picker_toggle: Callback::noop(),
|
||||
on_create_event: Callback::noop(),
|
||||
style: "default".to_string(),
|
||||
on_style_change: Callback::noop(),
|
||||
);
|
||||
|
||||
let _sidebar = html! { <Sidebar ..props /> };
|
||||
|
||||
// Test passes if no panic occurs during rendering
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn sidebar_theme_enum_conversions() {
|
||||
// Test Theme enum Display trait
|
||||
assert_eq!(format!("{}", Theme::Default), "default");
|
||||
assert_eq!(format!("{}", Theme::Ocean), "ocean");
|
||||
assert_eq!(format!("{}", Theme::Forest), "forest");
|
||||
assert_eq!(format!("{}", Theme::Dark), "dark");
|
||||
|
||||
// Test Theme from string parsing
|
||||
assert_eq!(Theme::from("default"), Theme::Default);
|
||||
assert_eq!(Theme::from("ocean"), Theme::Ocean);
|
||||
assert_eq!(Theme::from("forest"), Theme::Forest);
|
||||
assert_eq!(Theme::from("dark"), Theme::Dark);
|
||||
assert_eq!(Theme::from("unknown"), Theme::Default); // Should default to Default
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn sidebar_view_mode_conversions() {
|
||||
// Test ViewMode enum Display trait
|
||||
assert_eq!(format!("{}", ViewMode::Month), "month");
|
||||
assert_eq!(format!("{}", ViewMode::Week), "week");
|
||||
|
||||
// Test ViewMode from string parsing
|
||||
assert_eq!(ViewMode::from("month"), ViewMode::Month);
|
||||
assert_eq!(ViewMode::from("week"), ViewMode::Week);
|
||||
assert_eq!(ViewMode::from("unknown"), ViewMode::Month); // Should default to Month
|
||||
}
|
||||
Reference in New Issue
Block a user