first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -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}");
|
||||
|
||||
@@ -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())
|
||||
})
|
||||
}
|
||||
@@ -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(),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,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}"
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(" ")
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user