nigig-org/crates/apps/nigig-build/tests/ui.rs

884 lines
25 KiB
Rust

use makepad_widgets::makepad_test::{makepad_test, Selector, TestApp};
/// Skip tests that require a project to be loaded.
fn require_project_loaded() -> bool {
std::env::var("NIGIG_TEST_MODE").is_ok()
}
// ── App launch smoke tests ─────────────────────────────────────
#[makepad_test]
fn app_launches_successfully(app: TestApp) {
app.locator(Selector::widget_type("Window"))
.wait_visible();
}
#[makepad_test]
fn construction_screen_is_visible(app: TestApp) {
app.locator(Selector::id("main_adaptive_view"))
.wait_visible();
}
// ── Workspace overlay tests (requires NIGIG_TEST_MODE) ─────────
#[makepad_test]
fn workspace_overlay_exists_when_opened(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
}
#[makepad_test]
fn workspace_title_shows_correct_text(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_title"))
.wait_visible()
.assert_text("Spreadsheet");
}
#[makepad_test]
fn workspace_close_button_is_clickable(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_close_btn"))
.wait_visible()
.click();
app.locator(Selector::id("m_workspace_overlay"))
.wait_hidden();
}
// ── Spreadsheet workspace tests ────────────────────────────────
#[makepad_test]
fn spreadsheet_grid_is_visible(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("m_ss_grid"))
.wait_visible();
}
#[makepad_test]
fn spreadsheet_formula_bar_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("m_ss_formula_bar"))
.wait_visible();
}
#[makepad_test]
fn spreadsheet_cell_ref_label_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("m_ss_cell_ref"))
.wait_visible();
}
#[makepad_test]
fn spreadsheet_sum_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("m_ss_sum_btn"))
.wait_visible();
}
#[makepad_test]
fn spreadsheet_avg_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("m_ss_avg_btn"))
.wait_visible();
}
#[makepad_test]
fn spreadsheet_clear_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("m_ss_clear_btn"))
.wait_visible();
}
// ── Solar calculator workspace tests ───────────────────────────
#[makepad_test]
fn solar_calculator_page_is_visible(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("solar_calculator_page"))
.wait_visible();
}
#[makepad_test]
fn solar_tab_buttons_exist(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("solar_calculator_page"))
.wait_visible();
app.locator(Selector::id("solar_load_tab_btn"))
.wait_visible();
app.locator(Selector::id("solar_array_tab_btn"))
.wait_visible();
app.locator(Selector::id("solar_battery_tab_btn"))
.wait_visible();
app.locator(Selector::id("solar_results_tab_btn"))
.wait_visible();
}
#[makepad_test]
fn solar_load_tab_has_energy_input(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("solar_calculator_page"))
.wait_visible();
app.locator(Selector::id("sc_daily_energy"))
.wait_visible();
}
#[makepad_test]
fn solar_load_tab_has_peak_hours_input(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("solar_calculator_page"))
.wait_visible();
app.locator(Selector::id("sc_peak_sun"))
.wait_visible();
}
#[makepad_test]
fn solar_load_tab_has_peak_load_input(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("solar_calculator_page"))
.wait_visible();
app.locator(Selector::id("sc_peak_load"))
.wait_visible();
}
#[makepad_test]
fn solar_calculate_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("solar_calculator_page"))
.wait_visible();
app.locator(Selector::id("sc_calculate_btn"))
.wait_visible();
}
#[makepad_test]
fn solar_array_tab_panel_dropdown_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("solar_calculator_page"))
.wait_visible();
app.locator(Selector::id("solar_array_tab_btn"))
.click();
app.locator(Selector::id("sc_panel_dropdown"))
.wait_visible();
}
#[makepad_test]
fn solar_array_tab_arrays_count_input_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("solar_calculator_page"))
.wait_visible();
app.locator(Selector::id("solar_array_tab_btn"))
.click();
app.locator(Selector::id("sc_array_count"))
.wait_visible();
}
#[makepad_test]
fn solar_battery_tab_battery_type_dropdown_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("solar_calculator_page"))
.wait_visible();
app.locator(Selector::id("solar_battery_tab_btn"))
.click();
app.locator(Selector::id("sc_battery_type"))
.wait_visible();
}
#[makepad_test]
fn solar_tab_switching_works(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("solar_calculator_page"))
.wait_visible();
// Start on Load tab
app.locator(Selector::id("sc_daily_energy"))
.wait_visible();
// Switch to Array tab
app.locator(Selector::id("solar_array_tab_btn"))
.click();
app.locator(Selector::id("sc_panel_dropdown"))
.wait_visible();
// Switch to Battery tab
app.locator(Selector::id("solar_battery_tab_btn"))
.click();
app.locator(Selector::id("sc_battery_type"))
.wait_visible();
// Switch to Results tab
app.locator(Selector::id("solar_results_tab_btn"))
.click();
app.locator(Selector::id("sc_res_system_val"))
.wait_visible();
}
// ── PageFlip navigation between workspaces ─────────────────────
#[makepad_test]
fn page_flip_between_workspaces(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("m_workspace_flip"))
.wait_visible();
}
// ── Project Management workspace tests ─────────────────────────
#[makepad_test]
fn pm_page_is_visible(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("project_management_page"))
.wait_visible();
}
#[makepad_test]
fn pm_kpi_header_visible(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("m_workspace_overlay"))
.wait_visible();
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("kpi_header"))
.wait_visible();
}
#[makepad_test]
fn pm_kpi_task_count_visible(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("kpi_tasks"))
.wait_visible();
}
#[makepad_test]
fn pm_kpi_duration_visible(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("kpi_duration"))
.wait_visible();
}
#[makepad_test]
fn pm_kpi_progress_visible(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("kpi_progress"))
.wait_visible();
}
#[makepad_test]
fn pm_toolbar_visible(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("pm_toolbar"))
.wait_visible();
}
#[makepad_test]
fn pm_save_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("save_btn"))
.wait_visible();
}
#[makepad_test]
fn pm_undo_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("undo_button"))
.wait_visible();
}
#[makepad_test]
fn pm_redo_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("redo_button"))
.wait_visible();
}
#[makepad_test]
fn pm_add_task_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("add_task_btn"))
.wait_visible();
}
#[makepad_test]
fn pm_add_milestone_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("add_milestone_btn"))
.wait_visible();
}
#[makepad_test]
fn pm_add_group_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("add_group_btn"))
.wait_visible();
}
#[makepad_test]
fn pm_indent_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("indent_btn"))
.wait_visible();
}
#[makepad_test]
fn pm_outdent_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("outdent_btn"))
.wait_visible();
}
#[makepad_test]
fn pm_delete_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("delete_btn"))
.wait_visible();
}
#[makepad_test]
fn pm_zoom_buttons_exist(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("zoom_in_btn"))
.wait_visible();
app.locator(Selector::id("zoom_out_btn"))
.wait_visible();
}
#[makepad_test]
fn pm_today_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("today_btn"))
.wait_visible();
}
#[makepad_test]
fn pm_gantt_chart_is_visible(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("gantt_view"))
.wait_visible();
}
#[makepad_test]
fn pm_set_baseline_button_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("project_management_page"))
.wait_visible();
app.locator(Selector::id("set_baseline_btn"))
.wait_visible();
}
// ── CAD workspace tests ────────────────────────────────────────
#[makepad_test]
fn cad_viewport_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
}
#[makepad_test]
fn cad_tool_overlay_exists(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Tool overlay is drawn by the viewport; check for status label
app.locator(Selector::id("cad_status_label"))
.wait_visible();
}
#[makepad_test]
fn cad_tool_key_switches_tool(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Press L to switch to Line tool
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyL);
// Status label should update
app.locator(Selector::id("cad_status_label"))
.wait_visible();
}
#[makepad_test]
fn cad_escape_cancels_drawing(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Press L then Escape — should return to Select
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyL);
app.press_key(makepad_widgets::makepad_test::KeyCode::Escape);
app.locator(Selector::id("cad_status_label"))
.wait_visible();
}
#[makepad_test]
fn cad_toggle_ortho_polar(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// F8 toggles ortho, F9 toggles polar
app.press_key(makepad_widgets::makepad_test::KeyCode::F8);
app.press_key(makepad_widgets::makepad_test::KeyCode::F9);
app.locator(Selector::id("cad_status_label"))
.wait_visible();
}
#[makepad_test]
fn cad_dde_digit_enters_buffer(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Switch to Line tool, click to start line, type digit
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyL);
app.locator(Selector::id("cad_viewport"))
.click();
// Type a digit — DDE buffer should contain "5"
app.press_key(makepad_widgets::makepad_test::KeyCode::Key5);
}
#[makepad_test]
fn cad_dde_backspace_removes_char(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Switch to Line, click, type digits, backspace
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyL);
app.locator(Selector::id("cad_viewport"))
.click();
app.press_key(makepad_widgets::makepad_test::KeyCode::Key5);
app.press_key(makepad_widgets::makepad_test::KeyCode::Key3);
app.press_key(makepad_widgets::makepad_test::KeyCode::Backspace);
}
#[makepad_test]
fn cad_select_tool_click(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// S should switch to Select tool
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyS);
app.locator(Selector::id("cad_status_label"))
.wait_visible();
}
#[makepad_test]
fn cad_multiple_tool_switches(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Cycle through several tools via keyboard
let keys = [
makepad_widgets::makepad_test::KeyCode::KeyL,
makepad_widgets::makepad_test::KeyCode::KeyR,
makepad_widgets::makepad_test::KeyCode::KeyC,
makepad_widgets::makepad_test::KeyCode::KeyW,
];
for key in keys {
app.press_key(key);
app.locator(Selector::id("cad_status_label"))
.wait_visible();
}
}
// ── Section shape tests ────────────────────────────────────────
#[makepad_test]
fn cad_beam_tool_shows_rect_section(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Press B to switch to Beam tool
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyB);
app.locator(Selector::id("cad_status_label"))
.wait_visible();
}
#[makepad_test]
fn cad_beam_tab_cycles_section(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Switch to Beam tool (B), then Tab to cycle section
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyB);
app.locator(Selector::id("cad_status_label"))
.wait_visible();
app.press_key(makepad_widgets::makepad_test::KeyCode::Tab);
app.locator(Selector::id("cad_status_label"))
.wait_visible();
app.press_key(makepad_widgets::makepad_test::KeyCode::Tab);
app.locator(Selector::id("cad_status_label"))
.wait_visible();
}
#[makepad_test]
fn cad_beam_section_indicator_drawn(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Switch to Beam, create a beam, then verify section indicator appears
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyB);
app.locator(Selector::id("cad_viewport"))
.click();
app.press_key(makepad_widgets::makepad_test::KeyCode::Escape);
// Verify viewport still renders
app.locator(Selector::id("cad_viewport"))
.wait_visible();
}
#[makepad_test]
fn cad_beam_ibeam_section_switch(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Switch to Beam tool, Tab once to I-Beam, Tab once to HSS, Tab back to Rect
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyB);
app.press_key(makepad_widgets::makepad_test::KeyCode::Tab);
app.press_key(makepad_widgets::makepad_test::KeyCode::Tab);
app.press_key(makepad_widgets::makepad_test::KeyCode::Tab);
app.locator(Selector::id("cad_status_label"))
.wait_visible();
}
#[makepad_test]
fn cad_beam_section_ignored_when_not_beam(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Switch to Line tool — Tab should NOT cycle beam section
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyL);
app.press_key(makepad_widgets::makepad_test::KeyCode::Tab);
app.locator(Selector::id("cad_status_label"))
.wait_visible();
}
// ===========================================================================
// Session 6 — Selection actions UI tests
// ===========================================================================
#[makepad_test]
fn cad_escape_deselects(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Press Escape — should deselect all
app.press_key(makepad_widgets::makepad_test::KeyCode::Escape);
app.locator(Selector::id("cad_viewport"))
.wait_visible();
}
#[makepad_test]
fn cad_isolate_toggle(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Click on viewport to select something, then press I to isolate
app.locator(Selector::id("cad_viewport"))
.click();
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyI);
// Press I again to restore
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyI);
app.locator(Selector::id("cad_viewport"))
.wait_visible();
}
#[makepad_test]
fn cad_dof_toggle_shift_d(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Select something and toggle DOF
app.locator(Selector::id("cad_viewport"))
.click();
app.press_key(makepad_widgets::makepad_test::KeyCode::Shift);
app.press_key(makepad_widgets::makepad_test::KeyCode::KeyD);
app.locator(Selector::id("cad_viewport"))
.wait_visible();
}
#[makepad_test]
fn cad_properties_panel_dof_row(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Select a part to show properties panel
app.locator(Selector::id("cad_viewport"))
.click();
// Properties panel should now be visible with DOF buttons
app.locator(Selector::id("properties_panel_view"))
.wait_visible();
}
// ===========================================================================
// Session 7 — Export + PdfPreview UI tests
// ===========================================================================
#[makepad_test]
fn cad_stl_export_button(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Click STL export button
app.locator(Selector::id("export_stl_btn"))
.click();
// Status label should update with STL status
app.locator(Selector::id("status_label"))
.wait_visible();
}
#[makepad_test]
fn cad_svg_export_button(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Click SVG export button
app.locator(Selector::id("export_svg_btn"))
.click();
// Should auto-switch to preview tab after export
app.locator(Selector::id("status_label"))
.wait_visible();
}
#[makepad_test]
fn cad_pdf_tab_switch(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Click PDF tab to switch to preview page
app.locator(Selector::id("desktop_pdf_tab_btn"))
.click();
// Preview page should be visible
app.locator(Selector::id("desktop_pdf_page"))
.wait_visible();
}
#[makepad_test]
fn cad_pdf_tab_then_script_tab(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Switch to PDF preview
app.locator(Selector::id("desktop_pdf_tab_btn"))
.click();
app.locator(Selector::id("desktop_pdf_page"))
.wait_visible();
// Switch back to Script
app.locator(Selector::id("desktop_editor_tab_btn"))
.click();
app.locator(Selector::id("desktop_script_page"))
.wait_visible();
}
#[makepad_test]
fn cad_svg_export_shows_preview(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Click SVG export — should show SVG preview and hide placeholder
app.locator(Selector::id("export_svg_btn"))
.click();
app.locator(Selector::id("desktop_svg_preview"))
.wait_visible();
}
#[makepad_test]
fn cad_preview_placeholder_initially_visible(app: TestApp) {
if !require_project_loaded() {
return;
}
app.locator(Selector::id("cad_viewport"))
.wait_visible();
// Switch to PDF preview page
app.locator(Selector::id("desktop_pdf_tab_btn"))
.click();
// Placeholder should be visible initially (no export yet)
app.locator(Selector::id("desktop_preview_placeholder"))
.wait_visible();
}