use crate::common::harness::EditorTestHarness;
use crate::common::tracing::init_tracing_from_env;
use crossterm::event::{KeyCode, KeyModifiers};
use std::time::Duration;
#[test]
fn test_load_plugin_from_buffer_registers_command() {
init_tracing_from_env();
let mut harness = EditorTestHarness::with_temp_project(100, 30).unwrap();
let plugin_source = r#"
const editor = getEditor();
editor.registerCommand(
"Buffer Plugin Hello",
"Say hello from a buffer plugin",
"buffer_plugin_hello",
null
);
editor.setStatus("buffer-plugin loaded ok");
"#;
let project_dir = harness.project_dir().unwrap();
let plugin_file = project_dir.join("my_plugin.ts");
std::fs::write(&plugin_file, plugin_source).unwrap();
harness.open_file(&plugin_file).unwrap();
harness.render().unwrap();
harness.assert_screen_contains("registerCommand");
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("Load Plugin from Buffer").unwrap();
for _ in 0..3 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
for _ in 0..10 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
let screen = harness.screen_to_string();
assert!(
screen.contains("buffer-plugin loaded ok")
|| screen.contains("Plugin 'my_plugin.ts' loaded from buffer"),
"Expected plugin load success message. Screen:\n{}",
screen
);
harness.assert_no_plugin_errors();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("Buffer Plugin Hello").unwrap();
for _ in 0..3 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
let screen = harness.screen_to_string();
assert!(
screen.contains("Buffer Plugin Hello"),
"Plugin command should appear in palette after loading from buffer. Screen:\n{}",
screen
);
}
#[test]
fn test_load_plugin_from_buffer_hot_reload_cleanup() {
init_tracing_from_env();
let mut harness = EditorTestHarness::with_temp_project(100, 30).unwrap();
let plugin_v1 = r#"
const editor = getEditor();
editor.registerCommand(
"Alpha Zebra Xylophone",
"This command should disappear after reload",
"hot_reload_old",
null
);
editor.setStatus("v1 loaded");
"#;
let project_dir = harness.project_dir().unwrap();
let plugin_file = project_dir.join("reload_test.ts");
std::fs::write(&plugin_file, plugin_v1).unwrap();
harness.open_file(&plugin_file).unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("Load Plugin from Buffer").unwrap();
for _ in 0..3 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
for _ in 0..10 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
harness.assert_no_plugin_errors();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("Alpha Zebra Xylophone").unwrap();
for _ in 0..3 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
let screen = harness.screen_to_string();
assert!(
screen.contains("Alpha Zebra Xylophone"),
"Old command should be registered. Screen:\n{}",
screen
);
harness.send_key(KeyCode::Esc, KeyModifiers::NONE).unwrap();
harness.render().unwrap();
let plugin_v2 = r#"
const editor = getEditor();
editor.registerCommand(
"Beta Mango Pineapple",
"This is the replacement command",
"hot_reload_new",
null
);
editor.setStatus("v2 loaded");
"#;
std::fs::write(&plugin_file, plugin_v2).unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("Revert").unwrap();
for _ in 0..3 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
for _ in 0..5 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("Load Plugin from Buffer").unwrap();
for _ in 0..3 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
harness
.send_key(KeyCode::Enter, KeyModifiers::NONE)
.unwrap();
for _ in 0..10 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
harness.assert_no_plugin_errors();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("Beta Mango Pineapple").unwrap();
for _ in 0..3 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
let screen = harness.screen_to_string();
assert!(
screen.contains("Beta Mango Pineapple"),
"New command should be registered after hot-reload. Screen:\n{}",
screen
);
harness.send_key(KeyCode::Esc, KeyModifiers::NONE).unwrap();
harness.render().unwrap();
harness
.send_key(KeyCode::Char('p'), KeyModifiers::CONTROL)
.unwrap();
harness.render().unwrap();
harness.type_text("Alpha Zebra Xylophone").unwrap();
for _ in 0..3 {
harness.process_async_and_render().unwrap();
harness.sleep(Duration::from_millis(50));
}
let screen = harness.screen_to_string();
let count = screen.matches("Alpha Zebra Xylophone").count();
assert!(
count <= 1,
"Old command should be cleaned up after hot-reload (found {} occurrences, expected at most 1 from search input). Screen:\n{}",
count,
screen
);
}