use crate::{
platforms::windows::{generate_element_id, WindowsUIElement},
AutomationError, Desktop, Selector, UIElement,
};
use std::process::Command;
use std::thread;
use std::time::Duration;
struct NotepadGuard(std::process::Child);
impl Drop for NotepadGuard {
fn drop(&mut self) {
let _ = self.0.kill();
let _ = self.0.wait();
let _ = Command::new("taskkill")
.args(["/F", "/IM", "notepad.exe"])
.output();
}
}
fn setup_notepad() -> (NotepadGuard, Desktop, UIElement) {
let _ = Command::new("taskkill")
.args(["/F", "/IM", "notepad.exe"])
.output();
thread::sleep(Duration::from_millis(500));
let child = Command::new("notepad.exe")
.spawn()
.expect("Failed to start Notepad");
thread::sleep(Duration::from_millis(1000));
let desktop = Desktop::new(false, false).unwrap();
let notepad_app = desktop
.engine
.get_application_by_name("notepad")
.expect("Failed to get Notepad application");
notepad_app
.type_text("hello", false)
.expect("Failed to type in Notepad");
(NotepadGuard(child), desktop, notepad_app)
}
#[tokio::test]
#[ignore] async fn test_element_id_stability_across_restarts() -> Result<(), AutomationError> {
let get_notepad_document_hash = || -> Result<usize, AutomationError> {
let (_guard, desktop, notepad_app) = setup_notepad();
let document_selector = Selector::Role {
role: "document".to_string(),
name: None,
};
let doc_element =
desktop
.engine
.find_element(&document_selector, Some(¬epad_app), None)?;
let doc_impl = doc_element
.as_any()
.downcast_ref::<WindowsUIElement>()
.ok_or_else(|| {
AutomationError::PlatformError("Failed to downcast UIElement".to_string())
})?;
generate_element_id(&doc_impl.element.0)
};
let hash1 = get_notepad_document_hash()?;
thread::sleep(Duration::from_millis(500));
let hash2 = get_notepad_document_hash()?;
assert_eq!(
hash1, hash2,
"The element ID should be stable when the application is restarted. If this fails, a regression has occurred."
);
Ok(())
}