//! What the tests share: the imports, the seeded ids, opening a workspace //! and driving it frame by frame. // Every test module starts with `use crate::support::*;`, which brings in // these along with the fixtures and fakes. pub use gpui_kit::component::{ActiveTheme as _, Root, WindowExt as _, notification::Notification}; pub use gpui_kit::test::{TestAppContextExt, TestWindowExt}; pub use gpui_kit::{ App, AppContext as _, ClipboardItem, ElementId, Entity, InputEvent as _, MouseButton, MouseMoveEvent, TestAppContext, WindowHandle, point, px, size, }; pub use semver::Version; pub use shellrs::app::{ CenterTab, CheckForUpdates, ClearTerminal, CloseScope, CloseTabs, CollapseAllGroups, ConnectGroup, ConnectHost, CopyCredentialPublicKey, CopyHostAddress, CopyHostId, DeleteCredential, DeleteForward, DeleteGroup, DeleteHost, DisconnectHost, DisconnectTerminal, EditCredential, EditForward, EditHost, ExpandAllGroups, FindInTerminal, FindNextInTerminal, FindPreviousInTerminal, FocusSearch, InstallCliCommand, NewHostInGroup, NewLocalTerminal, OpenExplorer, ReconnectTerminal, RemoveAgentSkill, RenameGroup, RenameTerminal, StartForward, StopForward, ToggleHostPanel, }; pub use shellrs::cli::{AgentKind, IntegrationPaths}; pub use shellrs::connection::{ ConnectionPrompt, ConnectionPromptField, ConnectionPromptKind, ConnectionPromptReply, ConnectionTester, Latency, LoginTest, TrustCallback, }; pub use shellrs::explorer::ExplorerId; pub use shellrs::forward::{ ForwardCommand, ForwardEvent, ForwardStatus, ForwardTransport, ForwardTransportProvider, }; pub use shellrs::host::{ AuthKind, ConnectionState, CredentialDraft, CredentialId, CredentialKind, ForwardDraft, ForwardEndpoint, ForwardId, ForwardKind, ForwardRule, GeneratedKey, GroupDraft, GroupId, HostDatabase, HostDraft, HostId, HostLogin, HostOs, HostStore, JumpLogin, KeyAlgorithm, LoginMethod, LoginRoute, PastedKey, ProxyKind, ProxySettings, Route, read_public_key, }; pub use shellrs::secrets::{InMemorySecretStore, SecretRef, SecretStore as _}; pub use shellrs::settings::{Appearance, InterfaceLanguage, SettingsStore}; pub use shellrs::sftp::{ DirectoryEntry, DirectoryListing, EntryKind, FileMetadata, LocalDirectoryProvider, RemotePath, SftpCommand, SftpEvent, SftpTransport, SftpTransportProvider, UploadRequest, }; pub use shellrs::terminal::{ FixedRemoteTerminalTransportProvider, LocalTerminalId, RemoteTerminalId, RemoteTerminalTransportProvider, SharedTerminalTransportFactory, TerminalFont, TerminalLifecycle, TerminalSize, TerminalTransport, TerminalTransportCommand, TerminalTransportEvent, TerminalTransportFactory, }; pub use shellrs::update::{ Channel, InstallKind, Installer, Relaunch, Release, Staged, TrustedKeys, Unsupported, UpdateError, UpdateFeed, UpdateServices, }; pub use shellrs::workspace::Workspace; pub use std::sync::atomic::{AtomicUsize, Ordering}; pub use std::sync::{Arc, Mutex, mpsc}; pub use std::time::Duration; mod connection; mod credential; mod forward; mod sftp; mod terminal; pub use connection::*; pub use credential::*; pub use forward::*; pub use sftp::*; pub use terminal::*; /// Seeded host ids, in insertion order (see `HostStore::seed`). pub const WEB_01: u64 = 1; pub const WEB_02: u64 = 2; pub const DB_01: u64 = 3; /// The first SFTP tab a test opens; tab ids count up from 1. pub const SFTP_TAB: u64 = 1; pub const STAGING_API: u64 = 4; pub const DEV_BOX: u64 = 6; pub const INITIAL_WEB_TERMINAL: u64 = 1; pub const INITIAL_STAGING_TERMINAL: u64 = 2; pub const FIRST_NEW_TERMINAL: u64 = 3; /// Seeded group ids, in insertion order: 生产, 测试, 开发. pub const PRODUCTION: u64 = 1; pub const DEVELOPMENT: u64 = 3; pub fn open_workspace(cx: &mut TestAppContext) -> (WindowHandle, Entity) { open_workspace_with_store(cx, HostStore::seed()) } /// Production loads the store from the database; the tests hand one in /// directly so they get the fixed shape `HostStore::seed` describes. pub fn open_workspace_with_store( cx: &mut TestAppContext, store: HostStore, ) -> (WindowHandle, Entity) { open_workspace_with_tester(cx, store, Arc::new(FakeConnectionTester::default())) } pub fn one_host_store(auth: AuthKind) -> (HostStore, HostId) { let mut store = HostStore::empty(); let id = store.insert_unnotified(HostDraft::new( "prompt-host", "example.test", 22, "tester", auth, None, )); (store, id) } pub fn appearance_dropdown(window: &mut gpui_kit::Window, item: usize) -> Option { window .within("settings") .within("group-0") .within(format!("item-{item}")) .find("btn") .label() .map(str::to_string) } /// `TestWindowExt::click` sends no modifiers, and file lists need ⌘ and /// Shift clicks. pub fn modified_click( window: &mut gpui_kit::Window, pane: (&'static str, u64), row: &str, modifiers: gpui_kit::Modifiers, cx: &mut App, ) { let row = ElementId::Name(row.to_string().into()); let position = window.within(pane).find(row).bounds().center(); click_at(window, position, modifiers, cx); } /// A left click at a point, for places without an element of their own. pub fn click_at( window: &mut gpui_kit::Window, position: gpui_kit::Point, modifiers: gpui_kit::Modifiers, cx: &mut App, ) { use gpui_kit::{MouseDownEvent, MouseUpEvent}; window.dispatch_event( MouseMoveEvent { position, pressed_button: None, modifiers, } .to_platform_input(), cx, ); window.render_frame(cx); window.dispatch_event( MouseDownEvent { button: MouseButton::Left, position, modifiers, click_count: 1, first_mouse: false, } .to_platform_input(), cx, ); window.dispatch_event( MouseUpEvent { button: MouseButton::Left, position, modifiers, click_count: 1, } .to_platform_input(), cx, ); } /// Whether a button accepts input. gpui-base does not report `disabled` for /// buttons, but a disabled one also leaves the focus order. pub fn enabled(button: &gpui_kit::test::ElementSnapshot) -> bool { button.focused().is_some() } /// Draw a frame, run `body` against it, and let what it started settle. pub fn in_frame( cx: &mut TestAppContext, handle: WindowHandle, body: impl FnOnce(&mut gpui_kit::Window, &mut App) -> R, ) -> R { let result = cx .update_window(handle.into(), |_, window, cx| { window.render_frame(cx); body(window, cx) }) .unwrap(); cx.run_until_parked(); result }