Make the first prettier test pass

This commit is contained in:
Kirill Bulatov 2023-10-12 12:40:35 +03:00
parent a528c6c686
commit 7f4ebf50d3
4 changed files with 124 additions and 29 deletions

View file

@ -7830,11 +7830,12 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
Some(tree_sitter_rust::language()),
);
let test_plugin = "test_plugin";
let _ = language
.set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
enabled_formatters: vec![BundledFormatter::Prettier {
parser_name: Some("test_parser"),
plugin_names: vec!["test_plugin"],
plugin_names: vec![test_plugin],
}],
..Default::default()
}))
@ -7843,37 +7844,31 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
let fs = FakeFs::new(cx.background());
fs.insert_file("/file.rs", Default::default()).await;
// TODO kb have to specify some test node runtime
let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
project.update(cx, |project, _| project.languages().add(Arc::new(language)));
let prettier_format_suffix = project.update(cx, |project, _| {
let suffix = project.enable_test_prettier(&[test_plugin]);
project.languages().add(Arc::new(language));
suffix
});
let buffer = project
.update(cx, |project, cx| project.open_local_buffer("/file.rs", cx))
.await
.unwrap();
let buffer_text = "one\ntwo\nthree\n";
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
let editor = cx.add_window(|cx| build_editor(buffer, cx)).root(cx);
editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
editor.update(cx, |editor, cx| editor.set_text(buffer_text, cx));
let format = editor.update(cx, |editor, cx| {
editor.perform_format(project.clone(), FormatTrigger::Manual, cx)
});
format.await.unwrap();
assert_eq!(
editor.read_with(cx, |editor, cx| editor.text(cx)),
"one, two\nthree\n"
);
editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
let format = editor.update(cx, |editor, cx| {
editor.perform_format(project, FormatTrigger::Manual, cx)
});
cx.foreground().advance_clock(super::FORMAT_TIMEOUT);
cx.foreground().start_waiting();
format.await.unwrap();
assert_eq!(
editor.read_with(cx, |editor, cx| editor.text(cx)),
"one\ntwo\nthree\n"
buffer_text.to_string() + prettier_format_suffix,
"Test prettier formatting was not applied to the original buffer text",
);
}

View file

@ -220,18 +220,83 @@ impl NodeRuntime for RealNodeRuntime {
}
}
pub struct FakeNodeRuntime;
pub struct FakeNodeRuntime(Option<PrettierSupport>);
struct PrettierSupport {
plugins: Vec<&'static str>,
}
impl FakeNodeRuntime {
pub fn new() -> Arc<dyn NodeRuntime> {
Arc::new(FakeNodeRuntime)
Arc::new(FakeNodeRuntime(None))
}
pub fn with_prettier_support(plugins: &[&'static str]) -> Arc<dyn NodeRuntime> {
Arc::new(FakeNodeRuntime(Some(PrettierSupport::new(plugins))))
}
}
#[async_trait::async_trait]
impl NodeRuntime for FakeNodeRuntime {
async fn binary_path(&self) -> anyhow::Result<PathBuf> {
// TODO kb move away into a separate type + a Project's setter (for test code)
if let Some(prettier_support) = &self.0 {
prettier_support.binary_path().await
} else {
unreachable!()
}
}
async fn run_npm_subcommand(
&self,
directory: Option<&Path>,
subcommand: &str,
args: &[&str],
) -> anyhow::Result<Output> {
if let Some(prettier_support) = &self.0 {
prettier_support
.run_npm_subcommand(directory, subcommand, args)
.await
} else {
unreachable!()
}
}
async fn npm_package_latest_version(&self, name: &str) -> anyhow::Result<String> {
if let Some(prettier_support) = &self.0 {
prettier_support.npm_package_latest_version(name).await
} else {
unreachable!()
}
}
async fn npm_install_packages(
&self,
directory: &Path,
packages: &[(&str, &str)],
) -> anyhow::Result<()> {
if let Some(prettier_support) = &self.0 {
prettier_support
.npm_install_packages(directory, packages)
.await
} else {
unreachable!()
}
}
}
impl PrettierSupport {
const PACKAGE_VERSION: &str = "0.0.1";
fn new(plugins: &[&'static str]) -> Self {
Self {
plugins: plugins.to_vec(),
}
}
}
#[async_trait::async_trait]
impl NodeRuntime for PrettierSupport {
async fn binary_path(&self) -> anyhow::Result<PathBuf> {
Ok(PathBuf::from("prettier_fake_node"))
}
@ -240,10 +305,10 @@ impl NodeRuntime for FakeNodeRuntime {
}
async fn npm_package_latest_version(&self, name: &str) -> anyhow::Result<String> {
if name == "prettier" {
Ok("0.0.1".to_string())
if name == "prettier" || self.plugins.contains(&name) {
Ok(Self::PACKAGE_VERSION.to_string())
} else {
unreachable!("Unexpected package name: {name}")
panic!("Unexpected package name: {name}")
}
}
@ -252,10 +317,32 @@ impl NodeRuntime for FakeNodeRuntime {
_: &Path,
packages: &[(&str, &str)],
) -> anyhow::Result<()> {
if packages == [("prettier", "0.0.1")] {
Ok(())
} else {
unreachable!("Unexpected packages to install: {packages:?}")
assert_eq!(
packages.len(),
self.plugins.len() + 1,
"Unexpected packages length to install: {:?}, expected `prettier` + {:?}",
packages,
self.plugins
);
for (name, version) in packages {
assert!(
name == &"prettier" || self.plugins.contains(name),
"Unexpected package `{}` to install in packages {:?}, expected {} for `prettier` + {:?}",
name,
packages,
Self::PACKAGE_VERSION,
self.plugins
);
assert_eq!(
version,
&Self::PACKAGE_VERSION,
"Unexpected package version `{}` to install in packages {:?}, expected {} for `prettier` + {:?}",
version,
packages,
Self::PACKAGE_VERSION,
self.plugins
);
}
Ok(())
}
}

View file

@ -71,6 +71,9 @@ impl Prettier {
".editorconfig",
];
#[cfg(any(test, feature = "test-support"))]
pub const FORMAT_SUFFIX: &str = "\nformatted by test prettier";
pub fn remote(
project_id: u64,
worktree_id: Option<usize>,
@ -433,7 +436,7 @@ impl Prettier {
#[cfg(any(test, feature = "test-support"))]
Self::Test(_) => Ok(buffer
.read_with(cx, |buffer, cx| {
let formatted_text = buffer.text() + "\nformatted by test prettier";
let formatted_text = buffer.text() + Self::FORMAT_SUFFIX;
buffer.diff(formatted_text, cx)
})
.await),

View file

@ -837,6 +837,16 @@ impl Project {
project
}
/// Enables a prettier mock that avoids interacting with node runtime, prettier LSP wrapper, or any real file changes.
/// Instead, if appends the suffix to every input, this suffix is returned by this method.
#[cfg(any(test, feature = "test-support"))]
pub fn enable_test_prettier(&mut self, plugins: &[&'static str]) -> &'static str {
self.node = Some(node_runtime::FakeNodeRuntime::with_prettier_support(
plugins,
));
Prettier::FORMAT_SUFFIX
}
fn on_settings_changed(&mut self, cx: &mut ModelContext<Self>) {
let mut language_servers_to_start = Vec::new();
let mut language_formatters_to_check = Vec::new();
@ -8442,7 +8452,7 @@ impl Project {
return Some(existing_prettier);
}
log::info!("Found prettier at {prettier_dir:?}, starting.");
log::info!("Found prettier in {prettier_dir:?}, starting.");
let task_prettier_dir = prettier_dir.clone();
let weak_project = this.downgrade();
let new_server_id =
@ -8459,7 +8469,7 @@ impl Project {
.await
.context("prettier start")
.map_err(Arc::new)?;
log::info!("Had started prettier in {:?}", prettier.prettier_dir());
log::info!("Started prettier in {:?}", prettier.prettier_dir());
if let Some((project, prettier_server)) =
weak_project.upgrade(&mut cx).zip(prettier.server())