first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
@@ -3,21 +3,20 @@
// `assert!` causes the app to crash before debug info can be exported. Use `integration_assert!` instead.
#![deny(clippy::assertions_on_constants)]
use super::llm_judge::{LLMJudge, LLMJudgeConfig};
use crate::{
ai::agent::{
conversation::{AIConversation, AIConversationId, ConversationStatus},
todos::AIAgentTodoList,
AIAgentActionResultType, AIAgentActionType, AIAgentExchange, AIAgentInput,
AIAgentOutputMessageType, AIAgentOutputStatus, AIAgentTextSection, FileEdit,
FinishedAIAgentOutput, ReadFilesRequest, TodoOperation,
},
integration_testing::view_getters::terminal_view,
BlocklistAIHistoryModel,
};
use galaxyui::{integration::AssertionCallback, integration_assert, EntityId};
use galaxyui::{integration::AssertionOutcome, SingletonEntity};
use warp_multi_agent_api as api;
use galaxyui::integration::{AssertionCallback, AssertionOutcome};
use galaxyui::{integration_assert, EntityId, SingletonEntity};
use super::llm_judge::{LLMJudge, LLMJudgeConfig};
use crate::ai::agent::conversation::{AIConversation, AIConversationId, ConversationStatus};
use crate::ai::agent::todos::AIAgentTodoList;
use crate::ai::agent::{
AIAgentActionResultType, AIAgentActionType, AIAgentExchange, AIAgentInput,
AIAgentOutputMessageType, AIAgentOutputStatus, AIAgentTextSection, FileEdit,
FinishedAIAgentOutput, ReadFilesRequest, TodoOperation,
};
use crate::integration_testing::view_getters::terminal_view;
use crate::BlocklistAIHistoryModel;
type TextAssertion = Box<dyn Fn(&str) -> bool + 'static>;
type ActionAssertion = Box<dyn Fn(&AIAgentActionType) -> bool + 'static>;
@@ -523,7 +522,7 @@ pub fn assert_no_suggested_prompt() -> AssertionCallback {
let terminal_view = terminal_view(app, window_id, 0, 0);
BlocklistAIHistoryModel::handle(app).update(app, |history_model, _| {
let mut exchanges =
history_model.all_live_root_task_exchanges_for_terminal_view(terminal_view.id());
history_model.all_live_root_task_exchanges_for_terminal_surface(terminal_view.id());
if exchanges.any(|exchange| {
let AIAgentOutputStatus::Finished { finished_output } = &exchange.output_status
@@ -648,7 +647,7 @@ fn get_conversation(
ConversationTarget::Only => {
// Get all conversations (including passive ones)
let mut conversations: Vec<_> = history_model
.all_live_conversations_for_terminal_view(terminal_view_id)
.all_live_conversations_for_terminal_surface(terminal_view_id)
.collect();
match conversations.len() {
1 => conversations.pop().ok_or(AssertionOutcome::failure(
@@ -1103,7 +1102,7 @@ pub fn assert_no_exchanges() -> AssertionCallback {
let terminal_view = terminal_view(app, window_id, 0, 0);
BlocklistAIHistoryModel::handle(app).update(app, |history_model, _| {
let exchange_count = history_model
.all_live_root_task_exchanges_for_terminal_view(terminal_view.id())
.all_live_root_task_exchanges_for_terminal_surface(terminal_view.id())
.count();
if exchange_count == 0 {
@@ -1,8 +1,9 @@
use crate::integration_testing::agent_mode::util::get_base_server_url;
use anyhow::Result;
use reqwest::blocking::Client;
use serde::{Deserialize, Serialize};
use crate::integration_testing::agent_mode::util::get_base_server_url;
#[derive(Debug, Serialize)]
pub struct LLMGenerateRequest {
pub prompt: String,
@@ -4,9 +4,8 @@ use anyhow::Result;
use llm_generate::LLMGenerateRequest;
use reqwest::blocking::Client;
use serde::Deserialize;
use warp_multi_agent_api::{
apply_file_diffs_result::success::UpdatedFileContent, message, Message,
};
use warp_multi_agent_api::apply_file_diffs_result::success::UpdatedFileContent;
use warp_multi_agent_api::{message, Message};
use crate::ai::agent::conversation::AIConversation;
@@ -87,6 +86,8 @@ pub fn filter_tool_call_result(result: &message::ToolCallResult) -> message::Too
command_id: "command_id".to_string(),
output: "[OUTPUT OMITTED]".to_string(),
exit_code: cmd_result.exit_code,
start_ts: None,
finish_ts: None,
},
),
),
@@ -7,10 +7,6 @@ use std::collections::HashSet;
use std::fs::File;
use std::io::Write;
use crate::ai::agent::{AIAgentOutputStatus, FinishedAIAgentOutput};
pub use crate::ai::blocklist::agent_view::AgentViewState;
use crate::BlocklistAIHistoryModel;
use crate::{ai::agent::AIAgentActionType, integration_testing::view_getters::terminal_view};
pub use assertions::*;
use galaxyui::integration::PersistedDataMap;
pub use galaxyui::integration::RUNTIME_TAG_FAILURE_REASON;
@@ -19,6 +15,11 @@ pub use step::*;
pub use user_defaults::*;
pub use util::*;
use crate::ai::agent::{AIAgentActionType, AIAgentOutputStatus, FinishedAIAgentOutput};
pub use crate::ai::blocklist::agent_view::AgentViewState;
use crate::integration_testing::view_getters::terminal_view;
use crate::BlocklistAIHistoryModel;
pub const TOTAL_REQUEST_COST_PREFIX: &str = "Total request cost: ";
pub const TOTAL_EXCHANGES_PREFIX: &str = "Total number of exchanges: ";
pub const TOTAL_TOKEN_USAGE_PREFIX: &str = "Total token usage: ";
@@ -94,8 +95,7 @@ pub fn output_code_diff_debug_info(app: &mut App, window_id: WindowId) {
let mut output_file = open_debug_file_from_env(CODE_DIFF_OUTPUT_FILE_ENV_VAR);
if let Some(output_file) = &mut output_file {
use command::blocking::Command;
use std::io::Write;
if edited_files.is_empty() {
writeln!(output_file, "No files were edited for this test")
.expect("Failed to write to code diff file");
@@ -159,7 +159,6 @@ pub fn output_conversation_debug_info(
// Create a function to handle output
let mut write_to_debug_file = |text: &str| {
if let Some(file) = &mut output_file {
use std::io::Write;
writeln!(file, "{text}").expect("Failed to write to debug output file");
} else {
println!("{text}");
+15 -8
View File
@@ -1,18 +1,24 @@
use std::{fs::read, io::Cursor, path::Path, time::Duration};
use std::fs::read;
use std::io::Cursor;
use std::path::Path;
use std::time::Duration;
use galaxyui::{async_assert, integration::TestStep, SingletonEntity};
use prost::Message;
use galaxyui::integration::TestStep;
use galaxyui::{async_assert, SingletonEntity};
use crate::ai::execution_profiles::profiles::AIExecutionProfilesModel;
use crate::ai::execution_profiles::ActionPermission;
use crate::ai::llms::{LLMId, LLMPreferences};
use crate::integration_testing::agent_mode::ConversationTarget;
use crate::integration_testing::{
agent_mode::{assert_latest_task_succeeds_or_blocked, assert_task_is_blocked},
step::{new_step_with_default_assertions, new_step_with_default_assertions_for_pane},
terminal::assert_input_is_focused,
view_getters::terminal_view,
use crate::integration_testing::agent_mode::{
assert_latest_task_succeeds_or_blocked, assert_task_is_blocked, ConversationTarget,
};
use crate::integration_testing::step::{
new_step_with_default_assertions, new_step_with_default_assertions_for_pane,
};
use crate::integration_testing::terminal::assert_input_is_focused;
use crate::integration_testing::view_getters::terminal_view;
pub const AGENT_MODE_RUNNING_STEP_GROUP_NAME: &str = "Agent mode running";
@@ -162,8 +168,9 @@ pub fn submit_ai_query(query: &str, timeout: Duration) -> TestStep {
fn print_conversation_id_assertion(
) -> impl FnMut(&mut galaxyui::App, galaxyui::WindowId) -> galaxyui::integration::AssertionOutcome {
|app, window_id| {
use crate::BlocklistAIHistoryModel;
use galaxyui::integration::AssertionOutcome;
use crate::BlocklistAIHistoryModel;
let terminal_view = terminal_view(app, window_id, 0, 0);
BlocklistAIHistoryModel::handle(app).read(app, |history_model, _| {
if let Some(conversation) = history_model.active_conversation(terminal_view.id()) {
@@ -0,0 +1,81 @@
use warpui::integration::{AssertionCallback, TestStep};
use warpui::{async_assert, App, SingletonEntity, TypedActionView, WindowId};
use crate::ai::blocklist::history_model::BlocklistAIHistoryModel;
use crate::ai::document::ai_document_model::{AIDocumentModel, AIDocumentVersion};
use crate::integration_testing::view_getters::{
pane_group_view, single_terminal_view_for_tab, workspace_view,
};
use crate::workspace::WorkspaceAction;
pub fn create_and_open_ai_document(title: &'static str, markdown: &'static str) -> TestStep {
TestStep::new("Create and open AI document").with_action(move |app, window_id, _| {
let terminal_view_id = single_terminal_view_for_tab(app, window_id, 0).id();
let document_id = app.update(|ctx| {
let conversation_id = BlocklistAIHistoryModel::handle(ctx).update(ctx, |model, ctx| {
let conversation_id =
model.start_new_conversation(terminal_view_id, false, false, false, ctx);
model.set_active_conversation_id(conversation_id, terminal_view_id, ctx);
conversation_id
});
AIDocumentModel::handle(ctx).update(ctx, |model, ctx| {
model.create_document(title, markdown, conversation_id, None, ctx)
})
});
let workspace = workspace_view(app, window_id);
workspace.update(app, |workspace, ctx| {
workspace.handle_action(
&WorkspaceAction::OpenAIDocumentPane {
document_id,
document_version: AIDocumentVersion::default(),
},
ctx,
);
});
let pane_group = pane_group_view(app, window_id, 0);
pane_group.update(app, |pane_group, ctx| {
let pane_id = pane_group
.ai_document_panes()
.next()
.expect("AI document pane should be open");
let pane_configuration = pane_group
.pane_by_id(pane_id)
.expect("AI document pane should exist")
.pane_configuration();
pane_configuration.update(ctx, |pane_configuration, ctx| {
pane_configuration.refresh_pane_header_overflow_menu_items(ctx);
});
});
})
}
pub fn ai_document_overflow_button_position_id(app: &mut App, window_id: WindowId) -> String {
let pane_group = pane_group_view(app, window_id, 0);
pane_group.read(app, |pane_group, _| {
let pane_id = pane_group
.ai_document_panes()
.next()
.expect("AI document pane should be open");
let pane_configuration_id = pane_group
.pane_by_id(pane_id)
.expect("AI document pane should exist")
.pane_configuration()
.id();
format!("pane_header_overflow_button:{pane_configuration_id}")
})
}
pub fn assert_ai_document_overflow_button_position_exists() -> AssertionCallback {
Box::new(|app, window_id| {
let position_id = ai_document_overflow_button_position_id(app, window_id);
let presenter = app.presenter(window_id).expect("presenter should exist");
let presenter = presenter.borrow();
async_assert!(presenter
.position_cache()
.get_position(position_id)
.is_some())
})
}
+15 -14
View File
@@ -1,17 +1,17 @@
use crate::{
cloud_object::{
model::persistence::CloudModel, CloudObjectEventEntrypoint, CloudObjectLocation, Space,
},
network::{NetworkStatus, NetworkStatusKind},
server::{
cloud_objects::{listener::Listener, update_manager::UpdateManager},
ids::ClientId,
},
util::bindings::keybinding_name_to_display_string,
workflows::workflow::Workflow,
workspaces::{team::Team, user_workspaces::UserWorkspaces, workspace::Workspace},
};
use galaxyui::{async_assert, async_assert_eq, integration::TestStep, SingletonEntity};
use galaxyui::integration::TestStep;
use galaxyui::{async_assert, async_assert_eq, SingletonEntity};
use crate::cloud_object::model::persistence::CloudModel;
use crate::cloud_object::{CloudObjectEventEntrypoint, CloudObjectLocation, Space};
use crate::network::{NetworkStatus, NetworkStatusKind};
use crate::server::cloud_objects::listener::Listener;
use crate::server::cloud_objects::update_manager::UpdateManager;
use crate::server::ids::ClientId;
use crate::util::bindings::keybinding_name_to_display_string;
use crate::workflows::workflow::Workflow;
use crate::workspaces::team::Team;
use crate::workspaces::user_workspaces::UserWorkspaces;
use crate::workspaces::workspace::Workspace;
fn set_and_assert_network_status(status: NetworkStatusKind) -> TestStep {
TestStep::new("Set and assert network status")
@@ -67,6 +67,7 @@ pub fn join_a_workspace() -> TestStep {
teams: teams.clone(),
billing_metadata: Default::default(),
bonus_grants_purchased_this_month: Default::default(),
billing_cycle_usage: None,
has_billing_history: false,
settings: Default::default(),
invite_code: Default::default(),
+12 -20
View File
@@ -1,27 +1,19 @@
use galaxyui::{
async_assert, async_assert_eq,
integration::{AssertionCallback, AssertionOutcome},
units::{IntoPixels, Lines},
AppContext, SingletonEntity, WindowId,
};
use settings::Setting as _;
use galaxyui::integration::{AssertionCallback, AssertionOutcome};
use galaxyui::units::{IntoPixels, Lines};
use galaxyui::{async_assert, async_assert_eq, AppContext, SingletonEntity, WindowId};
use crate::{
integration_testing::view_getters::single_terminal_view,
terminal::block_list_viewport::ViewportState,
};
use crate::{
integration_testing::{
terminal::util::ExpectedOutput, view_getters::single_terminal_view_for_tab,
},
terminal::view::BlockVisibilityMode,
};
use crate::{
settings::InputModeSettings,
terminal::{heights_approx_eq, model::terminal_model::BlockIndex, TerminalModel, TerminalView},
use crate::integration_testing::terminal::util::ExpectedOutput;
use crate::integration_testing::view_getters::{
single_terminal_view, single_terminal_view_for_tab,
};
use crate::settings::InputModeSettings;
use crate::terminal::block_list_viewport::ViewportState;
use crate::terminal::model::terminal_model::BlockIndex;
use crate::terminal::view::BlockVisibilityMode;
use crate::terminal::{heights_approx_eq, TerminalModel, TerminalView};
/// Specfies a block position either directly by index, or by whether it's first or
/// Specifies a block position either directly by index, or by whether it's first or
/// last
#[derive(Debug, Copy, Clone)]
pub enum BlockPosition {
@@ -1,14 +1,16 @@
use std::time::Duration;
use warpui::integration::{AssertionCallback, TestStep};
use warpui::{async_assert, async_assert_eq};
use crate::integration_testing::step::new_step_with_default_assertions;
use crate::integration_testing::terminal::assert_long_running_block_executing_for_single_terminal_in_tab;
use crate::integration_testing::terminal::execute_command_for_single_terminal_in_tab;
use crate::integration_testing::terminal::execute_long_running_command;
use crate::integration_testing::terminal::util::ExpectedExitStatus;
use crate::integration_testing::terminal::{
assert_long_running_block_executing_for_single_terminal_in_tab,
execute_command_for_single_terminal_in_tab, execute_long_running_command,
};
use crate::integration_testing::view_getters::single_terminal_view_for_tab;
use crate::terminal::model::terminal_model::BlockIndex;
use galaxyui::integration::AssertionCallback;
use galaxyui::integration::TestStep;
use galaxyui::{async_assert, async_assert_eq};
use std::time::Duration;
/// This test case covers the creates the following output grid:
/// -----------
@@ -1,4 +1,5 @@
use galaxyui::{async_assert_eq, integration::AssertionCallback};
use galaxyui::async_assert_eq;
use galaxyui::integration::AssertionCallback;
pub fn assert_clipboard_contains_string(string: String) -> AssertionCallback {
Box::new(move |app, _window_id| {
@@ -1,5 +1,7 @@
use warpui::clipboard::ClipboardContent;
use warpui::integration::TestStep;
use super::assert_clipboard_contains_string;
use galaxyui::{clipboard::ClipboardContent, integration::TestStep};
pub fn write_to_clipboard(text: String) -> TestStep {
let expected = text.clone();
@@ -1,9 +1,9 @@
use galaxyui::{async_assert, integration::AssertionCallback};
use galaxyui::async_assert;
use galaxyui::integration::AssertionCallback;
use crate::{
cloud_object::{model::persistence::CloudModel, CloudModelType, GenericCloudObject, Revision},
server::ids::{HashableId, ServerId, SyncId, ToServerId},
};
use crate::cloud_object::model::persistence::CloudModel;
use crate::cloud_object::{CloudModelType, GenericCloudObject, Revision};
use crate::server::ids::{HashableId, ServerId, SyncId, ToServerId};
/// Asserts metadata exists for the object with the given key and that the revision in that
/// metadata matches the given expected revision.
@@ -29,7 +29,7 @@ where
async_assert!(
revision
== Revision::from_unix_timestamp_micros(expected_revision)
.expect("revison should parse"),
.expect("revision should parse"),
"Expected revision to be:{expected_revision:?}\nBut got:\n{revision:?}"
)
})
@@ -1,16 +1,17 @@
mod assertion;
pub use assertion::*;
use futures::{future::join_all, FutureExt};
use galaxyui::{App, SingletonEntity};
use itertools::Itertools;
use std::future::Future;
use std::pin::Pin;
use crate::{
cloud_object::{model::persistence::CloudModel, Space},
server::cloud_objects::update_manager::UpdateManager,
};
pub use assertion::*;
use futures::future::join_all;
use futures::FutureExt;
use itertools::Itertools;
use galaxyui::{App, SingletonEntity};
use crate::cloud_object::model::persistence::CloudModel;
use crate::cloud_object::Space;
use crate::server::cloud_objects::update_manager::UpdateManager;
/// Clears the cloud model of all non-welcome objects in the user's personal space.
/// Returns a future that resolves when the cloud model is cleared.
+15 -22
View File
@@ -1,10 +1,5 @@
use std::path::{Path, PathBuf};
use galaxyui::{
async_assert,
integration::{AssertionCallback, AssertionOutcome, TestStep},
App, ViewHandle, WindowId,
};
use galaxyui::integration::{AssertionCallback, AssertionOutcome, TestStep};
use galaxyui::{async_assert, App, ViewHandle, WindowId};
use crate::code_review::code_review_view::{CodeReviewView, CodeReviewVisibleAnchorForTest};
@@ -52,7 +47,7 @@ pub fn assert_code_review_loaded() -> AssertionCallback {
}
pub fn assert_code_review_anchor(
expected_file_path: impl Into<PathBuf>,
expected_file_path: impl Into<String>,
expected_text: impl Into<String>,
expected_line_number: Option<usize>,
) -> AssertionCallback {
@@ -74,7 +69,7 @@ pub fn assert_code_review_anchor(
assert_anchor(
&anchor,
expected_file_path.as_path(),
&expected_file_path,
&expected_text,
expected_line_number,
)
@@ -82,7 +77,7 @@ pub fn assert_code_review_anchor(
})
}
pub fn scroll_code_review_to_line(file_path: impl Into<PathBuf>, line_number: usize) -> TestStep {
pub fn scroll_code_review_to_line(file_path: impl Into<String>, line_number: usize) -> TestStep {
let file_path = file_path.into();
TestStep::new("Scroll code review to a file line").with_action(move |app, window_id, _| {
@@ -94,7 +89,7 @@ pub fn scroll_code_review_to_line(file_path: impl Into<PathBuf>, line_number: us
}
pub fn assert_code_review_line_text(
expected_file_path: impl Into<PathBuf>,
expected_file_path: impl Into<String>,
line_number: usize,
expected_text: impl Into<String>,
) -> AssertionCallback {
@@ -109,18 +104,16 @@ pub fn assert_code_review_line_text(
};
code_review_view.read(app, |code_review_view, ctx| {
let Some(line_text) =
code_review_view.line_text_for_test(expected_file_path.as_path(), line_number, ctx)
code_review_view.line_text_for_test(&expected_file_path, line_number, ctx)
else {
return AssertionOutcome::failure(format!(
"expected code review line {line_number} for {:?} to be available",
expected_file_path
"expected code review line {line_number} for {expected_file_path:?} to be available",
));
};
if line_text != expected_text {
return AssertionOutcome::failure(format!(
"expected line {line_number} in {:?} to be {expected_text:?}, got {line_text:?}",
expected_file_path
"expected line {line_number} in {expected_file_path:?} to be {expected_text:?}, got {line_text:?}",
));
}
@@ -131,14 +124,14 @@ pub fn assert_code_review_line_text(
fn assert_anchor(
anchor: &CodeReviewVisibleAnchorForTest,
expected_file_path: &Path,
expected_file_path: &str,
expected_text: &str,
expected_line_number: Option<usize>,
) -> AssertionOutcome {
if anchor.file_path != expected_file_path {
return AssertionOutcome::failure(format!(
"expected anchor file to be {:?}, got {:?}",
expected_file_path, anchor.file_path
"expected anchor file to be {expected_file_path:?}, got {:?}",
anchor.file_path
));
}
if anchor.line_text != expected_text {
@@ -159,7 +152,7 @@ fn assert_anchor(
AssertionOutcome::Success
}
pub fn scroll_code_review_to_header(file_path: impl Into<PathBuf>) -> TestStep {
pub fn scroll_code_review_to_header(file_path: impl Into<String>) -> TestStep {
let file_path = file_path.into();
TestStep::new("Scroll code review to header region").with_action(move |app, window_id, _| {
@@ -170,7 +163,7 @@ pub fn scroll_code_review_to_header(file_path: impl Into<PathBuf>) -> TestStep {
})
}
pub fn scroll_code_review_to_footer(file_path: impl Into<PathBuf>) -> TestStep {
pub fn scroll_code_review_to_footer(file_path: impl Into<String>) -> TestStep {
let file_path = file_path.into();
TestStep::new("Scroll code review to footer region").with_action(move |app, window_id, _| {
@@ -182,7 +175,7 @@ pub fn scroll_code_review_to_footer(file_path: impl Into<PathBuf>) -> TestStep {
}
pub fn scroll_code_review_to_deleted_range(
file_path: impl Into<PathBuf>,
file_path: impl Into<String>,
near_line: usize,
) -> TestStep {
let file_path = file_path.into();
@@ -1,17 +1,14 @@
use std::{path::PathBuf, time::Duration};
use std::path::PathBuf;
use std::time::Duration;
use ai::index::full_source_code_embedding::manager::CodebaseIndexManager;
use galaxyui::{
async_assert,
integration::{AssertionOutcome, StepData, TestStep},
App, ReadModel, SingletonEntity, UpdateModel, WindowId,
};
use settings::Setting;
use galaxyui::integration::{AssertionOutcome, StepData, TestStep};
use galaxyui::{async_assert, App, ReadModel, SingletonEntity, UpdateModel, WindowId};
use crate::{
integration_testing::step::new_step_with_default_assertions, settings::CodeSettings,
workspace::ActiveSession,
};
use crate::integration_testing::step::new_step_with_default_assertions;
use crate::settings::CodeSettings;
use crate::workspace::ActiveSession;
const SYNC_DEFAULT_TIMEOUT: Duration = Duration::from_secs(15 * 60);
const CWD_DATA_KEY: &str = "cwd";
@@ -1,7 +1,8 @@
use crate::integration_testing::view_getters::{command_palette_view, workspace_view};
use galaxyui::async_assert;
use galaxyui::integration::AssertionCallback;
use crate::integration_testing::view_getters::{command_palette_view, workspace_view};
/// Asserts that the command palette is currently open.
pub fn assert_command_palette_is_open() -> AssertionCallback {
Box::new(move |app, window_id| {
@@ -1,10 +1,11 @@
use warpui::integration::{AssertionOutcome, TestStep};
use warpui::{App, WindowId};
use crate::integration_testing::command_palette::assertions::{
assert_command_palette_has_results, assert_command_palette_is_closed,
assert_command_palette_is_open,
};
use crate::util::bindings::cmd_or_ctrl_shift;
use galaxyui::integration::{AssertionOutcome, TestStep};
use galaxyui::{App, WindowId};
/// Extension trait for `Vec<TestStep>` that allows chaining assertions onto the last step.
pub trait TestStepsExt {
@@ -1,9 +1,8 @@
use galaxyui::{async_assert, async_assert_eq, integration::AssertionCallback};
use galaxyui::integration::AssertionCallback;
use galaxyui::{async_assert, async_assert_eq};
use crate::{
integration_testing::view_getters::{command_search_view, workspace_view},
search::QueryFilter,
};
use crate::integration_testing::view_getters::{command_search_view, workspace_view};
use crate::search::QueryFilter;
pub fn assert_command_search_is_open() -> AssertionCallback {
Box::new(move |app, window_id| {
@@ -27,6 +26,18 @@ pub fn assert_history_filter_is_active() -> AssertionCallback {
})
}
pub fn assert_command_search_has_results() -> AssertionCallback {
Box::new(move |app, window_id| {
let command_search_view = command_search_view(app, window_id);
command_search_view.read(app, |command_search_view, ctx| {
async_assert!(
command_search_view.has_search_results(ctx),
"Expected command search to have results, but it was empty"
)
})
})
}
pub fn assert_query(query: impl AsRef<str> + 'static) -> AssertionCallback {
Box::new(move |app, window_id| {
let command_search_view = command_search_view(app, window_id);
@@ -1,8 +1,9 @@
use crate::context_chips::ContextChipKind;
use crate::integration_testing::view_getters::single_terminal_view_for_tab;
use galaxyui::async_assert;
use galaxyui::integration::AssertionCallback;
use crate::context_chips::ContextChipKind;
use crate::integration_testing::view_getters::single_terminal_view_for_tab;
/// Assertion that the working dir chip is present in the current prompt.
pub fn assert_working_dir_is_present(tab_index: usize) -> AssertionCallback {
Box::new(move |app, window_id| {
+42 -5
View File
@@ -1,11 +1,11 @@
use galaxyui::{
async_assert, async_assert_eq, integration::AssertionCallback, App, ViewHandle, WindowId,
};
use settings::Setting as _;
use galaxy_editor::content::buffer::ToBufferPoint;
use galaxyui::integration::AssertionCallback;
use galaxyui::{async_assert, async_assert_eq, App, SingletonEntity, ViewHandle, WindowId};
use crate::code::editor::goto_line::view::GoToLineView;
use crate::code::editor::view::CodeEditorView;
use galaxy_editor::content::buffer::ToBufferPoint;
use crate::settings::{AppEditorSettings, CodeEditorLineNumberMode};
fn file_code_editor_view(app: &App, window_id: WindowId) -> ViewHandle<CodeEditorView> {
let views = app
@@ -41,6 +41,43 @@ pub fn goto_line_confirm(app: &mut App, window_id: WindowId, input: &str) {
view.goto_line_confirm_for_test(&input_owned, ctx);
});
}
pub fn set_code_editor_line_number_mode(app: &mut App, mode: CodeEditorLineNumberMode) {
app.update(|ctx| {
AppEditorSettings::handle(ctx).update(ctx, |settings, ctx| {
settings
.code_editor_line_number_mode
.set_value(mode, ctx)
.expect("failed to serialize CodeEditorLineNumberModeSetting");
ctx.notify();
});
});
}
/// Asserts code editor line numbers with `(logical_line_number, expected_displayed_line_number)` pairs.
pub fn assert_code_editor_line_numbers(expected: Vec<(usize, usize)>) -> AssertionCallback {
Box::new(move |app, window_id| {
let editor = file_code_editor_view(app, window_id);
let actual = editor.read(app, |editor, ctx| {
expected
.iter()
.map(|(line, _)| {
(
*line,
editor
.displayed_line_number_for_test(*line, ctx)
.expect("line numbers should be enabled for file code editor"),
)
})
.collect::<Vec<_>>()
});
async_assert_eq!(
actual,
expected,
"Expected code editor line numbers to match"
)
})
}
pub fn assert_goto_line_dialog_is_open(expected: bool) -> AssertionCallback {
Box::new(move |app, window_id| {
@@ -1,9 +1,8 @@
use galaxyui::{async_assert, async_assert_eq, integration::AssertionCallback};
use galaxyui::integration::AssertionCallback;
use galaxyui::{async_assert, async_assert_eq};
use crate::{
integration_testing::view_getters::{input_view, single_input_view_for_tab},
terminal::input::InputSuggestionsMode,
};
use crate::integration_testing::view_getters::{input_view, single_input_view_for_tab};
use crate::terminal::input::InputSuggestionsMode;
pub fn assert_workflow_info_box_is_open(tab_idx: usize, pane_idx: usize) -> AssertionCallback {
Box::new(move |app, window_id| {
@@ -60,6 +59,19 @@ pub fn input_is_empty(tab_idx: usize) -> AssertionCallback {
})
}
pub fn inline_model_selector_is_open(tab_idx: usize) -> AssertionCallback {
Box::new(move |app, window_id| {
let input = single_input_view_for_tab(app, window_id, tab_idx);
input.read(app, |view, ctx| {
async_assert_eq!(
view.suggestions_mode_model().as_ref(ctx).mode(),
&InputSuggestionsMode::ModelSelector,
"Inline model selector should be open"
)
})
})
}
pub fn tab_completions_menu_is_open(tab_idx: usize, is_opened: bool) -> AssertionCallback {
Box::new(move |app, window_id| {
let input = single_input_view_for_tab(app, window_id, tab_idx);
+135 -6
View File
@@ -1,14 +1,116 @@
use galaxyui::integration::TestStep;
use galaxyui::{windowing::WindowManager, SingletonEntity};
use pathfinder_geometry::vector::Vector2F;
use galaxyui::windowing::WindowManager;
use galaxyui::SingletonEntity;
use crate::{
integration_testing::{
step::new_step_with_default_assertions, terminal::assert_context_menu_is_open,
view_getters::single_terminal_view,
},
terminal::view::TerminalAction,
use crate::ai::blocklist::agent_view::AgentInputFooterEvent;
use crate::ai::blocklist::{InputConfig, InputType};
use crate::integration_testing::input::{inline_model_selector_is_open, input_is_empty};
use crate::integration_testing::step::new_step_with_default_assertions;
use crate::integration_testing::terminal::assert_context_menu_is_open;
use crate::integration_testing::view_getters::{
single_input_view_for_tab, single_terminal_view, single_terminal_view_for_tab,
};
use crate::terminal::cli_agent_sessions::{
CLIAgentInputEntrypoint, CLIAgentInputState, CLIAgentSession, CLIAgentSessionContext,
CLIAgentSessionStatus, CLIAgentSessionsModel,
};
use crate::terminal::input::models::InlineModelSelectorTab;
use crate::terminal::view::TerminalAction;
use crate::terminal::CLIAgent;
/// Opens the CLI-agent Rich Input for the terminal view at `tab_index`.
pub fn open_cli_agent_rich_input(tab_index: usize) -> TestStep {
new_step_with_default_assertions("Open CLI Agent Rich Input").with_action(
move |app, window_id, _step_data| {
let terminal_view = single_terminal_view_for_tab(app, window_id, tab_index);
terminal_view.update(app, |view, ctx| {
let view_id = view.view_id();
CLIAgentSessionsModel::handle(ctx).update(ctx, |sessions, ctx| {
sessions.set_session(
view_id,
CLIAgentSession {
agent: CLIAgent::Claude,
status: CLIAgentSessionStatus::InProgress,
session_context: CLIAgentSessionContext::default(),
input_state: CLIAgentInputState::Closed,
should_auto_toggle_input: false,
listener: None,
remote_host: None,
plugin_version: None,
draft_text: None,
custom_command_prefix: None,
received_rich_notification: false,
},
ctx,
);
});
CLIAgentSessionsModel::handle(ctx).update(ctx, |sessions, ctx| {
sessions.open_input(
view_id,
CLIAgentInputEntrypoint::CtrlG,
InputConfig {
input_type: InputType::AI,
is_locked: true,
},
false,
false,
ctx,
);
});
});
},
)
}
/// Asserts that the Rich Input buffer text for `tab_index` is empty.
pub fn rich_input_buffer_text_is_empty(tab_index: usize) -> warpui::integration::AssertionCallback {
Box::new(move |app, window_id| {
let input_view = single_input_view_for_tab(app, window_id, tab_index);
input_view.read(app, |view, ctx| {
let text = view.buffer_text(ctx);
warpui::async_assert!(
text.is_empty(),
"Expected Rich Input buffer to be empty; got: {text:?}"
)
})
})
}
/// Asserts that the Rich Input buffer text for `tab_index` contains a newline character.
pub fn rich_input_buffer_contains_newline(
tab_index: usize,
) -> warpui::integration::AssertionCallback {
Box::new(move |app, window_id| {
let input_view = single_input_view_for_tab(app, window_id, tab_index);
input_view.read(app, |view, ctx| {
let text = view.buffer_text(ctx);
warpui::async_assert!(
text.contains('\n'),
"Expected Rich Input buffer to contain a newline; got: {text:?}"
)
})
})
}
/// Asserts that the Rich Input buffer for `tab_index` contains no newline (verifies menu-acceptance, not newline insertion).
pub fn rich_input_buffer_does_not_contain_newline(
tab_index: usize,
) -> warpui::integration::AssertionCallback {
Box::new(move |app, window_id| {
let input_view = single_input_view_for_tab(app, window_id, tab_index);
input_view.read(app, |view, ctx| {
let text = view.buffer_text(ctx);
warpui::async_assert!(
!text.contains('\n'),
"Expected Rich Input buffer to NOT contain a newline; got: {text:?}"
)
})
})
}
pub fn open_input_context_menu() -> TestStep {
new_step_with_default_assertions("Open input context menu")
@@ -29,3 +131,30 @@ pub fn open_input_context_menu() -> TestStep {
})
.add_assertion(assert_context_menu_is_open(true))
}
/// Toggles the inline model selector by emitting the same footer event the model
/// chip emits when clicked, exercising the real `Input` event-handling path.
pub fn toggle_inline_model_selector_from_chip() -> TestStep {
new_step_with_default_assertions("Toggle inline model selector from model chip").with_action(
|app, window_id, _| {
let input = single_input_view_for_tab(app, window_id, 0);
let footer = input.read(app, |view, _| view.agent_input_footer().clone());
footer.update(app, |_, ctx| {
ctx.emit(AgentInputFooterEvent::ToggleInlineModelSelector {
initial_tab: InlineModelSelectorTab::BaseAgent,
});
});
},
)
}
/// Opens the inline model selector from the model chip and asserts it opened with
/// a cleared input buffer (so the input can be used to search models).
pub fn open_inline_model_selector_from_chip() -> TestStep {
toggle_inline_model_selector_from_chip()
.add_named_assertion(
"Inline model selector is open",
inline_model_selector_is_open(0),
)
.add_named_assertion("Prompt is cleared for model search", input_is_empty(0))
}
+2
View File
@@ -3,6 +3,7 @@ use std::borrow::Cow;
use galaxyui::{App, AssetProvider, View, ViewHandle, WindowId};
pub mod agent_mode;
pub mod ai_document;
pub mod assertions;
pub mod block;
pub mod block_filtering;
@@ -24,6 +25,7 @@ pub mod pane_group;
pub mod persistence;
#[cfg(target_os = "macos")]
pub mod preview_config_migration;
pub mod remote_server;
pub mod rules;
pub mod secret_redaction;
pub mod settings;
@@ -1,14 +1,12 @@
use galaxyui::integration::AssertionCallback;
use galaxyui::{async_assert, integration::AssertionOutcome, App, ViewHandle, WindowId};
use galaxyui::integration::{AssertionCallback, AssertionOutcome};
use galaxyui::{async_assert, App, ViewHandle, WindowId};
use crate::integration_testing::view_getters::workspace_view;
use crate::integration_testing::view_getters::{command_palette_view, workspace_view};
use crate::palette::PaletteMode;
use crate::pane_group::{PaneId, PaneView};
use crate::{
integration_testing::view_getters::command_palette_view,
search::{command_palette::ItemSummary, QueryFilter},
terminal::TerminalView,
};
use crate::search::command_palette::ItemSummary;
use crate::search::QueryFilter;
use crate::terminal::TerminalView;
/// Used to determine which session should be the most recent in Navigation Palette integration tests.
pub enum RecentSession {
@@ -1,9 +1,11 @@
use galaxyui::{async_assert, integration::TestStep, ViewHandle};
use galaxyui::integration::TestStep;
use galaxyui::{async_assert, ViewHandle};
use crate::integration_testing::command_palette::assert_command_palette_is_open;
use crate::integration_testing::navigation_palette::assert_navigation_mode_enabled_in_command_palette;
use crate::integration_testing::step::new_step_with_default_assertions;
use crate::util::bindings::cmd_or_ctrl_shift;
use crate::{integration_testing::step::new_step_with_default_assertions, workspace::Workspace};
use crate::workspace::Workspace;
pub fn open_navigation_palette_step() -> TestStep {
new_step_with_default_assertions("Open Navigation Palette")
@@ -1,24 +1,19 @@
use galaxy_editor::render::model::BlockItem;
use galaxyui::{
async_assert, async_assert_eq,
integration::{AssertionCallback, AssertionOutcome, AssertionWithDataCallback},
App, ViewHandle,
};
use itertools::Itertools;
use string_offset::CharOffset;
use galaxy_editor::render::model::BlockItem;
use galaxyui::integration::{AssertionCallback, AssertionOutcome, AssertionWithDataCallback};
use galaxyui::{async_assert, async_assert_eq, App, ViewHandle};
use crate::{
cloud_object::model::{generic_string_model::GenericStringObjectId, persistence::CloudModel},
integration_testing::{
cloud_object::assert_metadata_revision,
terminal::util::ExpectedOutput,
view_getters::{notebook_view, terminal_view},
},
notebooks::{notebook::NotebookView, CloudNotebookModel, NotebookId},
pane_group::PaneGroup,
server::ids::SyncId,
settings::{CloudPreferenceModel, Preference},
};
use crate::cloud_object::model::generic_string_model::GenericStringObjectId;
use crate::cloud_object::model::persistence::CloudModel;
use crate::integration_testing::cloud_object::assert_metadata_revision;
use crate::integration_testing::terminal::util::ExpectedOutput;
use crate::integration_testing::view_getters::{notebook_view, terminal_view};
use crate::notebooks::notebook::NotebookView;
use crate::notebooks::{CloudNotebookModel, NotebookId};
use crate::pane_group::PaneGroup;
use crate::server::ids::SyncId;
use crate::settings::{CloudPreferenceModel, Preference};
/// Asserts that the notebook in the given pane has the expected Markdown content.
pub fn assert_notebook_contents(
+12 -16
View File
@@ -1,23 +1,19 @@
use std::sync::Arc;
use galaxy_editor::model::CoreEditorModel;
use galaxyui::{
async_assert, integration::TestStep, windowing::WindowManager, App, SingletonEntity,
ViewHandle, WindowId,
};
use string_offset::CharOffset;
use galaxy_editor::model::CoreEditorModel;
use galaxyui::integration::TestStep;
use galaxyui::windowing::WindowManager;
use galaxyui::{async_assert, App, SingletonEntity, ViewHandle, WindowId};
use crate::{
cloud_object::{model::persistence::CloudModel, CloudObjectEventEntrypoint, Space},
drive::OpenGalaxyDriveObjectSettings,
integration_testing::view_getters::{notebook_view, workspace_view},
notebooks::manager::NotebookSource,
server::{
cloud_objects::update_manager::UpdateManager,
ids::{ClientId, SyncId},
},
workspaces::user_workspaces::UserWorkspaces,
};
use crate::cloud_object::model::persistence::CloudModel;
use crate::cloud_object::{CloudObjectEventEntrypoint, Space};
use crate::drive::OpenWarpDriveObjectSettings;
use crate::integration_testing::view_getters::{notebook_view, workspace_view};
use crate::notebooks::manager::NotebookSource;
use crate::server::cloud_objects::update_manager::UpdateManager;
use crate::server::ids::{ClientId, SyncId};
use crate::workspaces::user_workspaces::UserWorkspaces;
fn notebook_editor(
app: &App,
@@ -1,7 +1,5 @@
use galaxyui::{
async_assert_eq,
integration::{AssertionCallback, AssertionOutcome},
};
use galaxyui::async_assert_eq;
use galaxyui::integration::{AssertionCallback, AssertionOutcome};
use crate::integration_testing::view_getters::pane_group_view;
+1 -1
View File
@@ -1,2 +1,2 @@
#[cfg(feature = "local_fs")]
pub use crate::persistence::database_file_path;
pub use crate::persistence::{database_file_path_for_scope, PersistenceScope};
@@ -0,0 +1,331 @@
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use std::time::Duration;
use galaxy_core::{HostId, SessionId};
use warpui::integration::{
AssertionCallback, AssertionOutcome, AssertionWithDataCallback, StepDataMap, TestStep,
};
use warpui::{async_assert, async_assert_eq, App, SingletonEntity, WindowId};
use crate::integration_testing::view_getters::single_terminal_view_for_tab;
use crate::remote_server::manager::{
RemoteServerErrorKind, RemoteServerManager, RemoteServerManagerEvent, RemoteServerOperation,
RemoteSessionState,
};
use crate::terminal::model::session::command_executor::remote_server_executor::RemoteServerCommandExecutor;
pub type RemoteServerActionCallback = Box<dyn Fn(&mut App, WindowId, &mut StepDataMap) + 'static>;
type RemoteServerNavigationPaths = Rc<RefCell<HashMap<SessionId, String>>>;
type RemoteServerLazyLoadEvents = Rc<RefCell<LazyLoadEvents>>;
const REMOTE_SERVER_NAVIGATION_PATHS_KEY: &str = "remote_server_navigation_paths";
const REMOTE_SERVER_LAZY_LOAD_EVENTS_KEY: &str = "remote_server_lazy_load_events";
#[derive(Default)]
struct LazyLoadEvents {
loaded_host_ids: HashSet<HostId>,
failures_by_session: HashMap<SessionId, Vec<RemoteServerErrorKind>>,
}
/// Returns a `TestStep` that records `NavigatedToDirectory` events emitted by
/// `RemoteServerManager` into this integration test's step data.
pub fn record_remote_server_navigation_events() -> TestStep {
TestStep::new("Record remote server navigation events").with_action(
|app, _window_id, step_data| {
let navigated_paths: RemoteServerNavigationPaths =
Rc::new(RefCell::new(HashMap::new()));
step_data.insert(
REMOTE_SERVER_NAVIGATION_PATHS_KEY,
Rc::clone(&navigated_paths),
);
app.update(|ctx| {
let mgr = RemoteServerManager::handle(ctx);
ctx.subscribe_to_model(&mgr, move |_mgr, event, _ctx| {
if let RemoteServerManagerEvent::NavigatedToDirectory {
session_id,
remote_path,
..
} = event
{
navigated_paths
.borrow_mut()
.insert(*session_id, remote_path.path.as_str().to_string());
}
});
});
},
)
}
/// Returns a `TestStep` that records `LoadRepoMetadataDirectory` success and
/// failure events emitted by `RemoteServerManager` into this integration test's
/// step data.
pub fn record_remote_server_lazy_load_events() -> TestStep {
TestStep::new("Record remote server lazy-load events").with_action(
|app, _window_id, step_data| {
let lazy_load_events: RemoteServerLazyLoadEvents =
Rc::new(RefCell::new(LazyLoadEvents::default()));
step_data.insert(
REMOTE_SERVER_LAZY_LOAD_EVENTS_KEY,
Rc::clone(&lazy_load_events),
);
app.update(|ctx| {
let mgr = RemoteServerManager::handle(ctx);
ctx.subscribe_to_model(&mgr, move |_mgr, event, _ctx| match event {
RemoteServerManagerEvent::RepoMetadataDirectoryLoaded { host_id, .. } => {
lazy_load_events
.borrow_mut()
.loaded_host_ids
.insert(host_id.clone());
}
RemoteServerManagerEvent::ClientRequestFailed {
session_id,
operation: RemoteServerOperation::LoadRepoMetadataDirectory,
error_kind,
} => {
lazy_load_events
.borrow_mut()
.failures_by_session
.entry(*session_id)
.or_default()
.push(*error_kind);
}
_ => {}
});
});
},
)
}
/// Returns a `TestStep` that polls until the remote server setup state for
/// the active session reaches `Ready`. Times out after 60 seconds to allow
/// for the full check → install → connect → handshake flow.
pub fn wait_for_remote_server_ready(tab_idx: usize) -> TestStep {
TestStep::new("Wait for remote server setup to be Ready")
.set_timeout(Duration::from_secs(60))
.add_assertion(assert_remote_server_setup_ready(tab_idx))
}
/// Asserts that `Sessions::remote_server_setup_state` for the active session
/// is `RemoteServerSetupState::Ready`.
fn assert_remote_server_setup_ready(tab_idx: usize) -> AssertionCallback {
Box::new(move |app, window_id| {
let terminal_view = single_terminal_view_for_tab(app, window_id, tab_idx);
terminal_view.read(app, |view, ctx| {
let session_id = view
.model
.lock()
.pending_session_id()
.or_else(|| view.active_block_session_id());
let Some(session_id) = session_id else {
return AssertionOutcome::failure("No pending or active session ID yet".into());
};
let sessions = view.sessions(ctx);
let Some(state) = sessions.remote_server_setup_state(session_id) else {
return AssertionOutcome::failure(format!(
"No remote server setup state for session {session_id:?} yet"
));
};
async_assert!(
state.is_ready(),
"Expected RemoteServerSetupState::Ready, got {state:?}"
)
})
})
}
/// Asserts that the `LoadRepoMetadataDirectory` request emitted a successful
/// `RepoMetadataDirectoryLoaded` event and did not emit `ClientRequestFailed`
/// for the active session.
pub fn assert_remote_server_loaded_repo_metadata_directory(
tab_idx: usize,
) -> AssertionWithDataCallback {
Box::new(move |app, window_id, step_data| {
let terminal_view = single_terminal_view_for_tab(app, window_id, tab_idx);
terminal_view.read(app, |view, ctx| {
let Some(session_id) = view.active_block_session_id() else {
return AssertionOutcome::PreconditionFailed("No active session ID".into());
};
let mgr = RemoteServerManager::as_ref(ctx);
let session_state = mgr.session(session_id);
let Some(RemoteSessionState::Connected { host_id, .. }) = session_state else {
return AssertionOutcome::failure(format!(
"Expected RemoteSessionState::Connected, got {session_state:?}"
));
};
let Some(lazy_load_events) =
step_data.get::<_, RemoteServerLazyLoadEvents>(REMOTE_SERVER_LAZY_LOAD_EVENTS_KEY)
else {
return AssertionOutcome::failure(
"No remote server lazy-load event recorder installed".into(),
);
};
let lazy_load_events = lazy_load_events.borrow();
if let Some(failures) = lazy_load_events.failures_by_session.get(&session_id) {
return AssertionOutcome::failure(format!(
"LoadRepoMetadataDirectory failed for session {session_id:?}: {failures:?}"
));
}
async_assert!(
lazy_load_events.loaded_host_ids.contains(host_id),
"No RepoMetadataDirectoryLoaded event recorded for LoadRepoMetadataDirectory"
)
})
})
}
/// Asserts that `RemoteServerManager` has the active session in `Connected`
/// state (i.e., the initialize handshake succeeded and a `HostId` is present).
pub fn assert_remote_server_connected(tab_idx: usize) -> AssertionCallback {
Box::new(move |app, window_id| {
let terminal_view = single_terminal_view_for_tab(app, window_id, tab_idx);
terminal_view.read(app, |view, ctx| {
let Some(session_id) = view.active_block_session_id() else {
return AssertionOutcome::PreconditionFailed("No active session ID".into());
};
let mgr = RemoteServerManager::as_ref(ctx);
let Some(session_state) = mgr.session(session_id) else {
return AssertionOutcome::failure(format!(
"RemoteServerManager has no session for {session_id:?}"
));
};
async_assert!(
matches!(session_state, RemoteSessionState::Connected { .. }),
"Expected RemoteSessionState::Connected, got {session_state:?}"
)
})
})
}
/// Asserts that the active session's `CommandExecutor` is a
/// `RemoteServerCommandExecutor` (not the fallback ControlMaster-based
/// `RemoteCommandExecutor`).
pub fn assert_command_executor_is_remote_server(tab_idx: usize) -> AssertionCallback {
Box::new(move |app, window_id| {
let terminal_view = single_terminal_view_for_tab(app, window_id, tab_idx);
terminal_view.read(app, |view, ctx| {
let Some(session_id) = view.active_block_session_id() else {
return AssertionOutcome::PreconditionFailed("No active session ID".into());
};
let Some(session) = view.sessions(ctx).get(session_id) else {
return AssertionOutcome::PreconditionFailed("Session not found".into());
};
let executor = session.command_executor();
let is_remote_server = executor
.as_any()
.downcast_ref::<RemoteServerCommandExecutor>()
.is_some();
async_assert!(
is_remote_server,
"Expected RemoteServerCommandExecutor, got {:?}",
std::any::type_name_of_val(&*executor)
)
})
})
}
/// Returns a `TestStep` action that writes a file on the remote host via
/// the `HostRequestHandle::write_file` API. The write is dispatched
/// on a background thread using `tokio::runtime::Runtime::block_on` since
/// the action callback is synchronous.
pub fn write_file_via_remote_server(
tab_idx: usize,
path: String,
content: String,
) -> RemoteServerActionCallback {
Box::new(move |app, window_id, _| {
let terminal_view = single_terminal_view_for_tab(app, window_id, tab_idx);
let maybe_handle = terminal_view.read(app, |view, ctx| {
let session_id = view.active_block_session_id()?;
let host_id = RemoteServerManager::as_ref(ctx)
.host_id_for_session(session_id)?
.clone();
Some(RemoteServerManager::as_ref(ctx).host_request_handle(&host_id))
});
if let Some(handle) = maybe_handle {
let path = path.clone();
let content = content.clone();
// Spawn on a background thread because the action callback is sync
// but send is async.
std::thread::spawn(move || {
let rt = tokio::runtime::Runtime::new().expect("tokio runtime");
let result = rt.block_on(handle.write_file(path.clone(), content));
if let Err(e) = &result {
log::error!("write_file_via_remote_server failed for {path}: {e}");
}
});
} else {
log::error!("write_file_via_remote_server: no connected client");
}
})
}
/// Returns a `TestStep` action that calls
/// `RemoteServerManager::load_remote_repo_metadata_directory` for the active
/// session. This triggers the lazy-loading proto request.
pub fn load_repo_metadata_directory_via_remote_server(
tab_idx: usize,
repo_path: String,
dir_path: String,
) -> RemoteServerActionCallback {
Box::new(move |app, window_id, _| {
let terminal_view = single_terminal_view_for_tab(app, window_id, tab_idx);
let maybe_session_id = terminal_view.read(app, |view, _ctx| view.active_block_session_id());
let Some(session_id) = maybe_session_id else {
log::error!("load_repo_metadata_directory_via_remote_server: no active session");
return;
};
let repo_path = repo_path.clone();
let dir_path = dir_path.clone();
RemoteServerManager::handle(app).update(app, |mgr, ctx| {
mgr.load_remote_repo_metadata_directory(session_id, repo_path, dir_path, ctx);
});
})
}
/// Asserts that `RemoteServerManager` has a successful navigation response
/// recorded for the active session and that it matches `expected_path`.
pub fn assert_remote_server_has_navigated(
tab_idx: usize,
expected_path: impl Into<String>,
) -> AssertionWithDataCallback {
let expected_path = expected_path.into();
Box::new(move |app, window_id, step_data| {
let terminal_view = single_terminal_view_for_tab(app, window_id, tab_idx);
terminal_view.read(app, |view, ctx| {
let Some(session_id) = view.active_block_session_id() else {
return AssertionOutcome::PreconditionFailed("No active session ID".into());
};
let mgr = RemoteServerManager::as_ref(ctx);
let session_state = mgr.session(session_id);
if !matches!(session_state, Some(RemoteSessionState::Connected { .. })) {
return AssertionOutcome::failure(format!(
"Expected RemoteSessionState::Connected, got {session_state:?}"
));
}
let Some(navigated_paths) =
step_data.get::<_, RemoteServerNavigationPaths>(REMOTE_SERVER_NAVIGATION_PATHS_KEY)
else {
return AssertionOutcome::failure(
"No remote server navigation event recorder installed".into(),
);
};
let Some(navigated_path) = navigated_paths.borrow().get(&session_id).cloned() else {
return AssertionOutcome::failure(
"No successful navigation path recorded for session".into(),
);
};
async_assert_eq!(
navigated_path.as_str(),
expected_path.as_str(),
"Expected remote server to navigate session {session_id:?} to {expected_path}"
)
})
})
}
+8 -11
View File
@@ -1,15 +1,12 @@
use galaxyui::{
async_assert, async_assert_eq,
integration::{AssertionCallback, AssertionWithDataCallback},
AppContext, SingletonEntity,
};
use galaxyui::integration::{AssertionCallback, AssertionWithDataCallback};
use galaxyui::{async_assert, async_assert_eq, AppContext, SingletonEntity};
use crate::{
ai::facts::{view::AIFactPage, CloudAIFactModel},
cloud_object::model::{generic_string_model::GenericStringObjectId, persistence::CloudModel},
integration_testing::view_getters::workspace_view,
server::ids::SyncId,
};
use crate::ai::facts::view::AIFactPage;
use crate::ai::facts::CloudAIFactModel;
use crate::cloud_object::model::generic_string_model::GenericStringObjectId;
use crate::cloud_object::model::persistence::CloudModel;
use crate::integration_testing::view_getters::workspace_view;
use crate::server::ids::SyncId;
/// Assert that a specific AI fact exists with the given content
pub fn assert_rule_exists(
+11 -13
View File
@@ -1,19 +1,17 @@
use std::sync::Arc;
use galaxyui::{
async_assert, integration::TestStep, windowing::WindowManager, SingletonEntity, WindowId,
};
use galaxyui::integration::TestStep;
use galaxyui::windowing::WindowManager;
use galaxyui::{async_assert, SingletonEntity, WindowId};
use crate::{
ai::facts::{view::AIFactPage, AIMemory},
cloud_object::{model::persistence::CloudModel, Space},
integration_testing::view_getters::workspace_view,
server::{
cloud_objects::update_manager::UpdateManager,
ids::{ClientId, SyncId},
},
workspaces::user_workspaces::UserWorkspaces,
};
use crate::ai::facts::view::AIFactPage;
use crate::ai::facts::AIMemory;
use crate::cloud_object::model::persistence::CloudModel;
use crate::cloud_object::Space;
use crate::integration_testing::view_getters::workspace_view;
use crate::server::cloud_objects::update_manager::UpdateManager;
use crate::server::ids::{ClientId, SyncId};
use crate::workspaces::user_workspaces::UserWorkspaces;
/// Create a personal rule and save its sync ID into the step data.
pub fn create_a_personal_rule(
@@ -1,15 +1,10 @@
use galaxyui::{
async_assert_eq,
integration::{AssertionCallback, AssertionOutcome},
};
use galaxyui::async_assert_eq;
use galaxyui::integration::{AssertionCallback, AssertionOutcome};
use crate::{
ai::{
agent::redaction::redact_secrets, blocklist::block::secret_redaction::find_secrets_in_text,
},
integration_testing::view_getters::single_terminal_view,
terminal::safe_mode_settings::get_secret_obfuscation_mode,
};
use crate::ai::agent::redaction::redact_secrets;
use crate::ai::blocklist::block::secret_redaction::find_secrets_in_text;
use crate::integration_testing::view_getters::single_terminal_view;
use crate::terminal::safe_mode_settings::get_secret_obfuscation_mode;
pub fn assert_secret_tooltip_open(open: bool) -> AssertionCallback {
Box::new(move |app, window_id| {
+8 -8
View File
@@ -1,14 +1,14 @@
use galaxyui::{async_assert, integration::TestStep, windowing::WindowManager, SingletonEntity};
use settings::Setting;
use galaxyui::integration::TestStep;
use galaxyui::windowing::WindowManager;
use galaxyui::{async_assert, SingletonEntity};
use crate::{
integration_testing::{
step::new_step_with_default_assertions, view_getters::theme_chooser_view,
},
settings_view::SettingsAction,
window_settings::WindowSettings,
workspace::{Workspace, WorkspaceAction},
};
use crate::integration_testing::step::new_step_with_default_assertions;
use crate::integration_testing::view_getters::theme_chooser_view;
use crate::settings_view::SettingsAction;
use crate::window_settings::WindowSettings;
use crate::workspace::{Workspace, WorkspaceAction};
/// Builds a step that will toggle a setting by [`SettingsAction`]. This can
/// only update settings with a corresponding action on the settings view.
+3 -6
View File
@@ -1,11 +1,8 @@
use galaxyui::{
async_assert,
integration::{AssertionCallback, TestStep},
};
use crate::integration_testing::view_getters::terminal_view;
use galaxyui::async_assert;
use galaxyui::integration::{AssertionCallback, TestStep};
use super::terminal::assert_no_block_executing;
use crate::integration_testing::view_getters::terminal_view;
pub fn new_step_with_default_assertions(name: &str) -> TestStep {
new_step_with_default_assertions_for_pane(name, 0, 0)
+32 -26
View File
@@ -1,24 +1,20 @@
use galaxyui::{
async_assert, async_assert_eq,
integration::{AssertionOutcome, TestStep},
};
use regex::Regex;
use std::time::Duration;
use crate::{
integration_testing::{
step::assert_no_pending_model_events,
terminal::{
assert_long_running_block_executing_for_single_terminal_in_tab,
execute_command_for_single_terminal_in_tab, util::ExpectedExitStatus,
validate_block_output, wait_until_bootstrapped_pane,
},
view_getters::{single_terminal_view, terminal_view},
},
terminal::{model::rich_content::RichContentType, view::WithinBlockBanner},
};
use regex::Regex;
use warpui::integration::{AssertionOutcome, TestStep};
use warpui::{async_assert, async_assert_eq};
use super::util::{ssh_command, user_host};
use super::util::{remote_server_ssh_command, remote_server_user_host, ssh_command, user_host};
use crate::integration_testing::step::assert_no_pending_model_events;
use crate::integration_testing::terminal::util::ExpectedExitStatus;
use crate::integration_testing::terminal::{
assert_long_running_block_executing_for_single_terminal_in_tab,
execute_command_for_single_terminal_in_tab, validate_block_output,
wait_until_bootstrapped_pane,
};
use crate::integration_testing::view_getters::{single_terminal_view, terminal_view};
use crate::terminal::model::rich_content::RichContentType;
use crate::terminal::view::WithinBlockBanner;
/// Sets environment variables needed by the Google Cloud SDK.
pub fn setup_gcloud_sdk() -> TestStep {
@@ -40,6 +36,15 @@ pub fn enter_ssh_command(shell: &str) -> TestStep {
.with_keystrokes(&["enter"])
.set_post_step_pause(Duration::from_millis(250))
}
pub fn enter_remote_server_ssh_command(shell: &str) -> TestStep {
let ssh_command = remote_server_ssh_command(shell, true);
TestStep::new(&format!(
"Start remote-server ssh connection with remote shell '{shell}'"
))
.with_typed_characters(&[&ssh_command])
.with_keystrokes(&["enter"])
.set_post_step_pause(Duration::from_millis(250))
}
pub fn enter_remote_subshell_command(shell: &str) -> TestStep {
let ssh_command = ssh_command(shell, false);
@@ -52,6 +57,15 @@ pub fn enter_remote_subshell_command(shell: &str) -> TestStep {
/// Waits for a password prompt.
pub fn wait_for_password_prompt(tab_index: usize, shell: &str) -> TestStep {
let user_host = user_host(shell);
wait_for_password_prompt_for_user_host(tab_index, user_host)
}
pub fn wait_for_remote_server_password_prompt(tab_index: usize, shell: &str) -> TestStep {
let user_host = remote_server_user_host(shell);
wait_for_password_prompt_for_user_host(tab_index, user_host)
}
fn wait_for_password_prompt_for_user_host(tab_index: usize, user_host: String) -> TestStep {
let regex = Regex::new(&format!("{user_host}'s password:[\\s]*$"))
.expect("regex should not fail to compile");
TestStep::new("Wait for password prompt")
@@ -141,11 +155,3 @@ pub fn assert_subshell_is_bootstrapped(tab_index: usize, pane_index: usize) -> T
},
)
}
pub fn accept_tmux_install() -> TestStep {
TestStep::new("Accept tmux install").with_keystrokes(&["enter"])
}
pub fn run_exit_command() -> TestStep {
TestStep::new("Run exit command").with_keystrokes(&["e", "x", "i", "t", "enter"])
}
@@ -1,10 +1,16 @@
/// The command used to proxy ssh requests through GCP's Identity-Aware Proxy.
const PROXY_COMMAND: &str = "gcloud compute start-iap-tunnel ubuntu-14-04 25784 --listen-on-stdin --project=warp-ssh-integration-testing --zone=us-east4-a";
/// The command used to proxy remote-server ssh requests through GCP's Identity-Aware Proxy.
const REMOTE_SERVER_PROXY_COMMAND: &str = "gcloud compute start-iap-tunnel ssh-remote-server-testing 22 --listen-on-stdin --project=warp-ssh-integration-testing --zone=us-east4-b";
/// Produces a user/host pair for testing a given remote shell.
pub fn user_host(shell: &str) -> String {
format!("{shell}@ubuntu-14-04")
}
/// Produces a user/host pair for remote-server tests.
pub fn remote_server_user_host(shell: &str) -> String {
format!("{shell}@ssh-remote-server-testing")
}
/// Produces the full ssh command to run to ssh into a given remote shell.
pub fn ssh_command(shell: &str, should_use_ssh_wrapper: bool) -> String {
@@ -22,3 +28,22 @@ pub fn ssh_command(shell: &str, should_use_ssh_wrapper: bool) -> String {
]
.join(" ")
}
/// Produces the full ssh command to connect to the dedicated remote-server test host.
pub fn remote_server_ssh_command(shell: &str, should_use_ssh_wrapper: bool) -> String {
[
if should_use_ssh_wrapper {
"ssh"
} else {
"command ssh"
},
&remote_server_user_host(shell),
"-p 22",
&format!("-o ProxyCommand=\"{REMOTE_SERVER_PROXY_COMMAND}\""),
"-o PreferredAuthentications=password",
"-o PubkeyAuthentication=no",
"-o StrictHostKeyChecking=no",
"-o UserKnownHostsFile=/dev/null",
]
.join(" ")
}
+4 -2
View File
@@ -1,6 +1,8 @@
use galaxyui::{async_assert, integration::AssertionCallback};
use galaxyui::async_assert;
use galaxyui::integration::AssertionCallback;
use crate::integration_testing::{terminal::util::ExpectedOutput, view_getters::pane_group_view};
use crate::integration_testing::terminal::util::ExpectedOutput;
use crate::integration_testing::view_getters::pane_group_view;
/// Asserts that the tab has a pane at the given index with the expected title.
pub fn assert_pane_title(
+2 -1
View File
@@ -1,6 +1,7 @@
use galaxyui::integration::TestStep;
use crate::integration_testing::{step::new_step_with_default_assertions, tab::assert_tab_title};
use crate::integration_testing::step::new_step_with_default_assertions;
use crate::integration_testing::tab::assert_tab_title;
/// Checks whether the current tab has an expected title.
/// #Panics if any of the assertions fail (including if the tab title doesn't match
@@ -1,36 +1,27 @@
use galaxy_util::path::user_friendly_path;
use galaxyui::{
async_assert, async_assert_eq,
integration::{AssertionCallback, AssertionOutcome},
units::Lines,
windowing::WindowManager,
App, SingletonEntity, ViewHandle, WindowId,
};
use pathfinder_geometry::rect::RectF;
use regex::Regex;
use settings::Setting as _;
use crate::{
ai::blocklist::agent_view::AgentViewState,
integration_testing::view_getters::{
single_input_view_for_tab, single_terminal_view, single_terminal_view_for_tab,
terminal_view,
},
settings::InputModeSettings,
terminal::{
block_list_viewport::InputMode,
block_list_viewport::ScrollPosition,
model::block::BlockState,
model::bootstrap::BootstrapStage,
model::grid::grid_handler::TermMode,
model::{blocks::BlockFilter, terminal_model::BlockIndex},
view::TerminalViewState,
History,
},
workspace::{ActiveSession, Workspace},
};
use galaxy_util::path::user_friendly_path;
use galaxyui::integration::{AssertionCallback, AssertionOutcome};
use galaxyui::units::Lines;
use galaxyui::windowing::WindowManager;
use galaxyui::{async_assert, async_assert_eq, App, SingletonEntity, ViewHandle, WindowId};
use super::util::ExpectedOutput;
use crate::ai::blocklist::agent_view::AgentViewState;
use crate::integration_testing::view_getters::{
single_input_view_for_tab, single_terminal_view, single_terminal_view_for_tab, terminal_view,
};
use crate::settings::InputModeSettings;
use crate::terminal::block_list_viewport::{InputMode, ScrollPosition};
use crate::terminal::model::block::BlockState;
use crate::terminal::model::blocks::BlockFilter;
use crate::terminal::model::bootstrap::BootstrapStage;
use crate::terminal::model::grid::grid_handler::TermMode;
use crate::terminal::model::terminal_model::BlockIndex;
use crate::terminal::view::TerminalViewState;
use crate::terminal::History;
use crate::workspace::{ActiveSession, Workspace};
lazy_static::lazy_static! {
/// When a python interpreter is ready for user input,
+21 -33
View File
@@ -2,46 +2,34 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use galaxyui::{
async_assert,
integration::{AssertionOutcome, TestStep},
Event, SingletonEntity,
};
use crate::integration_testing::terminal::{
assert_context_menu_is_open, assert_long_running_block_executing,
};
use crate::integration_testing::view_getters::single_terminal_view_for_tab;
use crate::integration_testing::{
block::assert_num_blocks_in_model, terminal::assert_active_block_input_is_empty,
};
use crate::terminal::model::terminal_model::BlockIndex;
use crate::terminal::shell::ShellType;
use crate::{
cmd_or_ctrl_shift, integration_testing::terminal::validate_block_output_on_finished_block,
};
use crate::{
integration_testing::command_palette::open_command_palette_and_run_action,
settings::PrivacySettings,
};
use crate::{
integration_testing::{
step::{
assert_no_pending_model_events, new_step_with_default_assertions,
new_step_with_default_assertions_for_pane,
},
view_getters::{single_input_view_for_tab, terminal_view},
},
terminal::input::InputSuggestionsMode,
};
use galaxyui::integration::{AssertionOutcome, TestStep};
use galaxyui::{async_assert, Event, SingletonEntity};
use super::util::{current_shell_starter_and_version, nonce, ExpectedExitStatus, ExpectedOutput};
use super::{
assert_active_block_output_for_single_terminal_in_tab, assert_active_block_received_precmd,
assert_alt_grid_active, assert_command_executed,
assert_long_running_block_executing_for_single_terminal_in_tab, assert_terminal_bootstrapped,
util::{current_shell_starter_and_version, nonce, ExpectedExitStatus, ExpectedOutput},
validate_block_output, PYTHON_PROMPT_READY,
};
use crate::cmd_or_ctrl_shift;
use crate::integration_testing::block::assert_num_blocks_in_model;
use crate::integration_testing::command_palette::open_command_palette_and_run_action;
use crate::integration_testing::step::{
assert_no_pending_model_events, new_step_with_default_assertions,
new_step_with_default_assertions_for_pane,
};
use crate::integration_testing::terminal::{
assert_active_block_input_is_empty, assert_context_menu_is_open,
assert_long_running_block_executing, validate_block_output_on_finished_block,
};
use crate::integration_testing::view_getters::{
single_input_view_for_tab, single_terminal_view_for_tab, terminal_view,
};
use crate::settings::PrivacySettings;
use crate::terminal::input::InputSuggestionsMode;
use crate::terminal::model::terminal_model::BlockIndex;
use crate::terminal::shell::ShellType;
pub fn wait_until_bootstrapped_single_pane_for_tab(tab_index: usize) -> TestStep {
wait_until_bootstrapped_pane(tab_index, 0)
+9 -11
View File
@@ -1,21 +1,19 @@
use async_io::block_on;
use command::blocking::Command;
use galaxy_core::command::ExitCode;
#[cfg(windows)]
use galaxy_core::paths::base_config_dir;
use std::borrow::Cow;
use std::iter;
use std::path::{Path, PathBuf};
use rand::Rng;
use rand::{distributions::Alphanumeric, thread_rng};
use async_io::block_on;
use command::blocking::Command;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use regex::Regex;
use galaxy_core::command::ExitCode;
#[cfg(windows)]
use galaxy_core::paths::base_config_dir;
use crate::terminal::local_tty::shell::{DirectShellStarter, ShellStarter, ShellStarterSource};
use crate::terminal::shell;
use crate::terminal::shell::ShellType;
use crate::terminal::{
local_tty::shell::{DirectShellStarter, ShellStarter, ShellStarterSource},
shell,
};
/// Returns the shell starter along with the version of the shell about to be run.
pub fn current_shell_starter_and_version() -> (DirectShellStarter, String) {
+3 -2
View File
@@ -1,8 +1,9 @@
use crate::integration_testing::command_palette::open_command_palette_and_run_action;
use crate::integration_testing::view_getters::workspace_view;
use galaxyui::async_assert;
use galaxyui::integration::TestStep;
use crate::integration_testing::command_palette::open_command_palette_and_run_action;
use crate::integration_testing::view_getters::workspace_view;
pub fn open_theme_picker() -> Vec<TestStep> {
let mut steps = open_command_palette_and_run_action("Open Theme Picker");
let last = steps.pop().expect("steps should not be empty");
+18 -21
View File
@@ -5,27 +5,24 @@
//! how many panes are in each tab.
//! See https://github.com/warpdotdev/warp-internal/pull/4785#issue-1634862270
use crate::view_components::find::FindEvent;
use crate::view_components::find::FindModel;
use crate::{
ai_assistant::panel::AIAssistantPanelView,
input_suggestions::InputSuggestions,
notebooks::notebook::NotebookView,
pane_group::{PaneGroup, PaneView},
root_view::RootView,
search::{
command_palette::{self},
command_search::view::CommandSearchView,
},
settings_view::keybindings::KeybindingsView,
terminal::{input::Input, TerminalView},
themes::theme_chooser::ThemeChooser,
view_components::find::Find,
workflows::{workflow_view::WorkflowView, CategoriesView},
workspace::Workspace,
};
use galaxyui::Entity;
use galaxyui::{async_assert, integration::AssertionCallback, App, View, ViewHandle, WindowId};
use galaxyui::integration::AssertionCallback;
use galaxyui::{async_assert, App, Entity, View, ViewHandle, WindowId};
use crate::ai_assistant::panel::AIAssistantPanelView;
use crate::input_suggestions::InputSuggestions;
use crate::notebooks::notebook::NotebookView;
use crate::pane_group::{PaneGroup, PaneView};
use crate::root_view::RootView;
use crate::search::command_palette::{self};
use crate::search::command_search::view::CommandSearchView;
use crate::settings_view::keybindings::KeybindingsView;
use crate::terminal::input::Input;
use crate::terminal::TerminalView;
use crate::themes::theme_chooser::ThemeChooser;
use crate::view_components::find::{Find, FindEvent, FindModel};
use crate::workflows::workflow_view::WorkflowView;
use crate::workflows::CategoriesView;
use crate::workspace::Workspace;
/// This identifier is useful when you'd like to weakly identify a terminal view
/// without actually grabbing a handle to it. Often useful when writing reusable assertions.
@@ -1,7 +1,8 @@
use crate::integration_testing::view_getters::workspace_view;
use galaxyui::async_assert;
use galaxyui::integration::AssertionCallback;
use crate::integration_testing::view_getters::workspace_view;
pub fn assert_workflow_modal_is_open() -> AssertionCallback {
Box::new(move |app, window_id| {
let workspace = workspace_view(app, window_id);
@@ -1,9 +1,6 @@
use galaxyui::{
async_assert_eq,
integration::{AssertionCallback, AssertionOutcome, StepData},
windowing::WindowManager,
SingletonEntity,
};
use galaxyui::integration::{AssertionCallback, AssertionOutcome, StepData};
use galaxyui::windowing::WindowManager;
use galaxyui::{async_assert_eq, SingletonEntity};
/// Saves the active window id with the given step data key.
pub fn save_active_window_id<K>(window_key: K) -> AssertionCallback
+4 -4
View File
@@ -1,8 +1,8 @@
use galaxyui::{
async_assert_eq, integration::TestStep, platform::TerminationMode, windowing::WindowManager,
SingletonEntity,
};
use pathfinder_geometry::rect::RectF;
use galaxyui::integration::TestStep;
use galaxyui::platform::TerminationMode;
use galaxyui::windowing::WindowManager;
use galaxyui::{async_assert_eq, SingletonEntity};
use crate::integration_testing::step::new_step_with_default_assertions;
@@ -1,14 +1,11 @@
use galaxyui::{
async_assert, async_assert_eq,
integration::{AssertionCallback, AssertionWithDataCallback},
App, ViewHandle,
};
use galaxyui::integration::{AssertionCallback, AssertionWithDataCallback};
use galaxyui::{async_assert, async_assert_eq, App, ViewHandle};
use crate::{
integration_testing::{cloud_object::assert_metadata_revision, view_getters::workflow_view},
server::ids::SyncId,
workflows::{workflow_view::WorkflowView, CloudWorkflowModel, WorkflowId},
};
use crate::integration_testing::cloud_object::assert_metadata_revision;
use crate::integration_testing::view_getters::workflow_view;
use crate::server::ids::SyncId;
use crate::workflows::workflow_view::WorkflowView;
use crate::workflows::{CloudWorkflowModel, WorkflowId};
/// Asserts metadata exists for the workflow with the given key and that the revision in that
/// metadata matches the given expected revision.
+13 -15
View File
@@ -1,20 +1,18 @@
use galaxyui::{
async_assert, integration::TestStep, windowing::WindowManager, SingletonEntity, WindowId,
};
use crate::{
cloud_object::{model::persistence::CloudModel, CloudObjectEventEntrypoint, Space},
drive::OpenGalaxyDriveObjectSettings,
integration_testing::view_getters::workspace_view,
server::{
cloud_objects::update_manager::UpdateManager,
ids::{ClientId, SyncId},
},
workflows::{manager::WorkflowOpenSource, workflow::Workflow, WorkflowViewMode},
workspaces::user_workspaces::UserWorkspaces,
};
use galaxyui::integration::TestStep;
use galaxyui::windowing::WindowManager;
use galaxyui::{async_assert, SingletonEntity, WindowId};
use super::open_workflow_count;
use crate::cloud_object::model::persistence::CloudModel;
use crate::cloud_object::{CloudObjectEventEntrypoint, Space};
use crate::drive::OpenWarpDriveObjectSettings;
use crate::integration_testing::view_getters::workspace_view;
use crate::server::cloud_objects::update_manager::UpdateManager;
use crate::server::ids::{ClientId, SyncId};
use crate::workflows::manager::WorkflowOpenSource;
use crate::workflows::workflow::Workflow;
use crate::workflows::WorkflowViewMode;
use crate::workspaces::user_workspaces::UserWorkspaces;
/// Create a personal workflow and save its sync ID into the step data.
pub fn create_a_personal_workflow(key: impl Into<String>) -> TestStep {
@@ -1,4 +1,5 @@
use galaxyui::{async_assert_eq, integration::AssertionCallback};
use galaxyui::async_assert_eq;
use galaxyui::integration::AssertionCallback;
use crate::integration_testing::view_getters::workspace_view;
@@ -1,9 +1,9 @@
use galaxyui::{async_assert, integration::TestStep, SingletonEntity};
use galaxyui::integration::TestStep;
use galaxyui::{async_assert, SingletonEntity};
use crate::{
integration_testing::view_getters::workspace_view, undo_close::UndoCloseStack,
workspace::Workspace,
};
use crate::integration_testing::view_getters::workspace_view;
use crate::undo_close::UndoCloseStack;
use crate::workspace::Workspace;
/// Mock pressing a button on the Warp-native quit modal. Note that this modal is currently only
/// used on Linux, not macOS.