debugger: Fix running JS tests when worktree root and package root do not coincide (#32644)
- construct the correct path to the test library based on the location of package.json - run scripts from the package root where they were defined - run tests in the directory of the defining file Release Notes: - Debugger Beta: fixed running JS tests when the worktree root is above the location of package.json. --------- Co-authored-by: Anthony <anthony@zed.dev> Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
parent
9166e66519
commit
bcd79331b9
3 changed files with 289 additions and 112 deletions
|
@ -8,8 +8,7 @@ use futures::future::join_all;
|
|||
use gpui::{App, AppContext, AsyncApp, Task};
|
||||
use http_client::github::{AssetKind, GitHubLspBinaryVersion, build_asset_url};
|
||||
use language::{
|
||||
ContextLocation, ContextProvider, File, LanguageToolchainStore, LocalFile, LspAdapter,
|
||||
LspAdapterDelegate,
|
||||
ContextLocation, ContextProvider, File, LanguageToolchainStore, LspAdapter, LspAdapterDelegate,
|
||||
};
|
||||
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName};
|
||||
use node_runtime::NodeRuntime;
|
||||
|
@ -29,6 +28,7 @@ use util::archive::extract_zip;
|
|||
use util::merge_json_value_into;
|
||||
use util::{ResultExt, fs::remove_matching, maybe};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TypeScriptContextProvider {
|
||||
last_package_json: PackageJsonContents,
|
||||
}
|
||||
|
@ -42,47 +42,81 @@ const TYPESCRIPT_JEST_TEST_NAME_VARIABLE: VariableName =
|
|||
const TYPESCRIPT_VITEST_TEST_NAME_VARIABLE: VariableName =
|
||||
VariableName::Custom(Cow::Borrowed("TYPESCRIPT_VITEST_TEST_NAME"));
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
const TYPESCRIPT_JEST_PACKAGE_PATH_VARIABLE: VariableName =
|
||||
VariableName::Custom(Cow::Borrowed("TYPESCRIPT_JEST_PACKAGE_PATH"));
|
||||
|
||||
const TYPESCRIPT_MOCHA_PACKAGE_PATH_VARIABLE: VariableName =
|
||||
VariableName::Custom(Cow::Borrowed("TYPESCRIPT_MOCHA_PACKAGE_PATH"));
|
||||
|
||||
const TYPESCRIPT_VITEST_PACKAGE_PATH_VARIABLE: VariableName =
|
||||
VariableName::Custom(Cow::Borrowed("TYPESCRIPT_VITEST_PACKAGE_PATH"));
|
||||
|
||||
const TYPESCRIPT_JASMINE_PACKAGE_PATH_VARIABLE: VariableName =
|
||||
VariableName::Custom(Cow::Borrowed("TYPESCRIPT_JASMINE_PACKAGE_PATH"));
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct PackageJsonContents(Arc<RwLock<HashMap<PathBuf, PackageJson>>>);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct PackageJson {
|
||||
mtime: DateTime<Local>,
|
||||
data: PackageJsonData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
struct PackageJsonData {
|
||||
jest: bool,
|
||||
mocha: bool,
|
||||
vitest: bool,
|
||||
jasmine: bool,
|
||||
scripts: BTreeSet<String>,
|
||||
jest_package_path: Option<Arc<Path>>,
|
||||
mocha_package_path: Option<Arc<Path>>,
|
||||
vitest_package_path: Option<Arc<Path>>,
|
||||
jasmine_package_path: Option<Arc<Path>>,
|
||||
scripts: BTreeSet<(Arc<Path>, String)>,
|
||||
package_manager: Option<&'static str>,
|
||||
}
|
||||
|
||||
impl PackageJsonData {
|
||||
fn new(package_json: HashMap<String, Value>) -> Self {
|
||||
fn new(path: Arc<Path>, package_json: HashMap<String, Value>) -> Self {
|
||||
let mut scripts = BTreeSet::new();
|
||||
if let Some(serde_json::Value::Object(package_json_scripts)) = package_json.get("scripts") {
|
||||
scripts.extend(package_json_scripts.keys().cloned());
|
||||
scripts.extend(
|
||||
package_json_scripts
|
||||
.keys()
|
||||
.cloned()
|
||||
.map(|name| (path.clone(), name)),
|
||||
);
|
||||
}
|
||||
|
||||
let mut jest = false;
|
||||
let mut mocha = false;
|
||||
let mut vitest = false;
|
||||
let mut jasmine = false;
|
||||
let mut jest_package_path = None;
|
||||
let mut mocha_package_path = None;
|
||||
let mut vitest_package_path = None;
|
||||
let mut jasmine_package_path = None;
|
||||
if let Some(serde_json::Value::Object(dependencies)) = package_json.get("devDependencies") {
|
||||
jest |= dependencies.contains_key("jest");
|
||||
mocha |= dependencies.contains_key("mocha");
|
||||
vitest |= dependencies.contains_key("vitest");
|
||||
jasmine |= dependencies.contains_key("jasmine");
|
||||
if dependencies.contains_key("jest") {
|
||||
jest_package_path.get_or_insert_with(|| path.clone());
|
||||
}
|
||||
if dependencies.contains_key("mocha") {
|
||||
mocha_package_path.get_or_insert_with(|| path.clone());
|
||||
}
|
||||
if dependencies.contains_key("vitest") {
|
||||
vitest_package_path.get_or_insert_with(|| path.clone());
|
||||
}
|
||||
if dependencies.contains_key("jasmine") {
|
||||
jasmine_package_path.get_or_insert_with(|| path.clone());
|
||||
}
|
||||
}
|
||||
if let Some(serde_json::Value::Object(dev_dependencies)) = package_json.get("dependencies")
|
||||
{
|
||||
jest |= dev_dependencies.contains_key("jest");
|
||||
mocha |= dev_dependencies.contains_key("mocha");
|
||||
vitest |= dev_dependencies.contains_key("vitest");
|
||||
jasmine |= dev_dependencies.contains_key("jasmine");
|
||||
if dev_dependencies.contains_key("jest") {
|
||||
jest_package_path.get_or_insert_with(|| path.clone());
|
||||
}
|
||||
if dev_dependencies.contains_key("mocha") {
|
||||
mocha_package_path.get_or_insert_with(|| path.clone());
|
||||
}
|
||||
if dev_dependencies.contains_key("vitest") {
|
||||
vitest_package_path.get_or_insert_with(|| path.clone());
|
||||
}
|
||||
if dev_dependencies.contains_key("jasmine") {
|
||||
jasmine_package_path.get_or_insert_with(|| path.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let package_manager = package_json
|
||||
|
@ -101,33 +135,37 @@ impl PackageJsonData {
|
|||
});
|
||||
|
||||
Self {
|
||||
jest,
|
||||
mocha,
|
||||
vitest,
|
||||
jasmine,
|
||||
jest_package_path,
|
||||
mocha_package_path,
|
||||
vitest_package_path,
|
||||
jasmine_package_path,
|
||||
scripts,
|
||||
package_manager,
|
||||
}
|
||||
}
|
||||
|
||||
fn merge(&mut self, other: Self) {
|
||||
self.jest |= other.jest;
|
||||
self.mocha |= other.mocha;
|
||||
self.vitest |= other.vitest;
|
||||
self.jasmine |= other.jasmine;
|
||||
self.jest_package_path = self.jest_package_path.take().or(other.jest_package_path);
|
||||
self.mocha_package_path = self.mocha_package_path.take().or(other.mocha_package_path);
|
||||
self.vitest_package_path = self
|
||||
.vitest_package_path
|
||||
.take()
|
||||
.or(other.vitest_package_path);
|
||||
self.jasmine_package_path = self
|
||||
.jasmine_package_path
|
||||
.take()
|
||||
.or(other.jasmine_package_path);
|
||||
self.scripts.extend(other.scripts);
|
||||
self.package_manager = self.package_manager.or(other.package_manager);
|
||||
}
|
||||
|
||||
fn fill_task_templates(&self, task_templates: &mut TaskTemplates) {
|
||||
if self.jest {
|
||||
if self.jest_package_path.is_some() {
|
||||
task_templates.0.push(TaskTemplate {
|
||||
label: "jest file test".to_owned(),
|
||||
command: TYPESCRIPT_RUNNER_VARIABLE.template_value(),
|
||||
args: vec![
|
||||
"jest".to_owned(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
args: vec!["jest".to_owned(), VariableName::Filename.template_value()],
|
||||
cwd: Some(VariableName::Dirname.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
task_templates.0.push(TaskTemplate {
|
||||
|
@ -140,28 +178,28 @@ impl PackageJsonData {
|
|||
"\"{}\"",
|
||||
TYPESCRIPT_JEST_TEST_NAME_VARIABLE.template_value()
|
||||
),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
VariableName::Filename.template_value(),
|
||||
],
|
||||
tags: vec![
|
||||
"ts-test".to_owned(),
|
||||
"js-test".to_owned(),
|
||||
"tsx-test".to_owned(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
cwd: Some(VariableName::Dirname.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
}
|
||||
|
||||
if self.vitest {
|
||||
if self.vitest_package_path.is_some() {
|
||||
task_templates.0.push(TaskTemplate {
|
||||
label: format!("{} file test", "vitest".to_owned()),
|
||||
command: TYPESCRIPT_RUNNER_VARIABLE.template_value(),
|
||||
args: vec![
|
||||
"vitest".to_owned(),
|
||||
"run".to_owned(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
VariableName::Filename.template_value(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
cwd: Some(VariableName::Dirname.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
task_templates.0.push(TaskTemplate {
|
||||
|
@ -179,27 +217,24 @@ impl PackageJsonData {
|
|||
"\"{}\"",
|
||||
TYPESCRIPT_VITEST_TEST_NAME_VARIABLE.template_value()
|
||||
),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
VariableName::Filename.template_value(),
|
||||
],
|
||||
tags: vec![
|
||||
"ts-test".to_owned(),
|
||||
"js-test".to_owned(),
|
||||
"tsx-test".to_owned(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
cwd: Some(VariableName::Dirname.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
}
|
||||
|
||||
if self.mocha {
|
||||
if self.mocha_package_path.is_some() {
|
||||
task_templates.0.push(TaskTemplate {
|
||||
label: format!("{} file test", "mocha".to_owned()),
|
||||
command: TYPESCRIPT_RUNNER_VARIABLE.template_value(),
|
||||
args: vec![
|
||||
"mocha".to_owned(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
args: vec!["mocha".to_owned(), VariableName::Filename.template_value()],
|
||||
cwd: Some(VariableName::Dirname.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
task_templates.0.push(TaskTemplate {
|
||||
|
@ -213,27 +248,27 @@ impl PackageJsonData {
|
|||
"mocha".to_owned(),
|
||||
"--grep".to_owned(),
|
||||
format!("\"{}\"", VariableName::Symbol.template_value()),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
VariableName::Filename.template_value(),
|
||||
],
|
||||
tags: vec![
|
||||
"ts-test".to_owned(),
|
||||
"js-test".to_owned(),
|
||||
"tsx-test".to_owned(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
cwd: Some(VariableName::Dirname.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
}
|
||||
|
||||
if self.jasmine {
|
||||
if self.jasmine_package_path.is_some() {
|
||||
task_templates.0.push(TaskTemplate {
|
||||
label: format!("{} file test", "jasmine".to_owned()),
|
||||
command: TYPESCRIPT_RUNNER_VARIABLE.template_value(),
|
||||
args: vec![
|
||||
"jasmine".to_owned(),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
VariableName::Filename.template_value(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
cwd: Some(VariableName::Dirname.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
task_templates.0.push(TaskTemplate {
|
||||
|
@ -246,30 +281,31 @@ impl PackageJsonData {
|
|||
args: vec![
|
||||
"jasmine".to_owned(),
|
||||
format!("--filter={}", VariableName::Symbol.template_value()),
|
||||
VariableName::RelativeFile.template_value(),
|
||||
VariableName::Filename.template_value(),
|
||||
],
|
||||
tags: vec![
|
||||
"ts-test".to_owned(),
|
||||
"js-test".to_owned(),
|
||||
"tsx-test".to_owned(),
|
||||
"jasmine-test".to_owned(),
|
||||
],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
cwd: Some(VariableName::Dirname.template_value()),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
}
|
||||
|
||||
for script in &self.scripts {
|
||||
for (path, script) in &self.scripts {
|
||||
task_templates.0.push(TaskTemplate {
|
||||
label: format!("package.json > {script}",),
|
||||
command: TYPESCRIPT_RUNNER_VARIABLE.template_value(),
|
||||
args: vec![
|
||||
"--prefix".to_owned(),
|
||||
VariableName::WorktreeRoot.template_value(),
|
||||
"run".to_owned(),
|
||||
script.to_owned(),
|
||||
],
|
||||
args: vec!["run".to_owned(), script.to_owned()],
|
||||
tags: vec!["package-script".into()],
|
||||
cwd: Some(VariableName::WorktreeRoot.template_value()),
|
||||
cwd: Some(
|
||||
path.parent()
|
||||
.unwrap_or(Path::new(""))
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
),
|
||||
..TaskTemplate::default()
|
||||
});
|
||||
}
|
||||
|
@ -287,13 +323,9 @@ impl TypeScriptContextProvider {
|
|||
&self,
|
||||
fs: Arc<dyn Fs>,
|
||||
worktree_root: &Path,
|
||||
file_abs_path: &Path,
|
||||
file_relative_path: &Path,
|
||||
cx: &App,
|
||||
) -> Task<anyhow::Result<PackageJsonData>> {
|
||||
let Some(file_relative_path) = file_abs_path.strip_prefix(&worktree_root).ok() else {
|
||||
log::debug!("No package json data for off-worktree files");
|
||||
return Task::ready(Ok(PackageJsonData::default()));
|
||||
};
|
||||
let new_json_data = file_relative_path
|
||||
.ancestors()
|
||||
.map(|path| worktree_root.join(path))
|
||||
|
@ -345,7 +377,8 @@ impl TypeScriptContextProvider {
|
|||
serde_json::from_str(&package_json_string).with_context(|| {
|
||||
format!("parsing package.json from {package_json_path:?}")
|
||||
})?;
|
||||
let new_data = PackageJsonData::new(package_json);
|
||||
let new_data =
|
||||
PackageJsonData::new(package_json_path.as_path().into(), package_json);
|
||||
{
|
||||
let mut contents = existing_package_json.0.write().await;
|
||||
contents.insert(
|
||||
|
@ -361,31 +394,25 @@ impl TypeScriptContextProvider {
|
|||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_package_manager(
|
||||
&self,
|
||||
worktree_root: PathBuf,
|
||||
fs: Arc<dyn Fs>,
|
||||
cx: &App,
|
||||
) -> Task<&'static str> {
|
||||
let last_package_json = self.last_package_json.clone();
|
||||
let package_json_data =
|
||||
self.package_json_data(&worktree_root, last_package_json, fs.clone(), cx);
|
||||
cx.background_spawn(async move {
|
||||
if let Ok(package_json_data) = package_json_data.await {
|
||||
if let Some(package_manager) = package_json_data.package_manager {
|
||||
return package_manager;
|
||||
}
|
||||
}
|
||||
if fs.is_file(&worktree_root.join("pnpm-lock.yaml")).await {
|
||||
return "pnpm";
|
||||
}
|
||||
if fs.is_file(&worktree_root.join("yarn.lock")).await {
|
||||
return "yarn";
|
||||
}
|
||||
"npm"
|
||||
})
|
||||
async fn detect_package_manager(
|
||||
worktree_root: PathBuf,
|
||||
fs: Arc<dyn Fs>,
|
||||
package_json_data: Option<PackageJsonData>,
|
||||
) -> &'static str {
|
||||
if let Some(package_json_data) = package_json_data {
|
||||
if let Some(package_manager) = package_json_data.package_manager {
|
||||
return package_manager;
|
||||
}
|
||||
}
|
||||
if fs.is_file(&worktree_root.join("pnpm-lock.yaml")).await {
|
||||
return "pnpm";
|
||||
}
|
||||
if fs.is_file(&worktree_root.join("yarn.lock")).await {
|
||||
return "yarn";
|
||||
}
|
||||
"npm"
|
||||
}
|
||||
|
||||
impl ContextProvider for TypeScriptContextProvider {
|
||||
|
@ -401,9 +428,9 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
let Some(worktree_root) = file.worktree.read(cx).root_dir() else {
|
||||
return Task::ready(None);
|
||||
};
|
||||
let file_abs_path = file.abs_path(cx);
|
||||
let file_relative_path = file.path().clone();
|
||||
let package_json_data =
|
||||
self.combined_package_json_data(fs.clone(), &worktree_root, &file_abs_path, cx);
|
||||
self.combined_package_json_data(fs.clone(), &worktree_root, &file_relative_path, cx);
|
||||
|
||||
cx.background_spawn(async move {
|
||||
let mut task_templates = TaskTemplates(Vec::new());
|
||||
|
@ -426,7 +453,7 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
}
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
"Failed to read package.json for worktree {file_abs_path:?}: {e:#}"
|
||||
"Failed to read package.json for worktree {file_relative_path:?}: {e:#}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -455,14 +482,73 @@ impl ContextProvider for TypeScriptContextProvider {
|
|||
replace_test_name_parameters(symbol),
|
||||
);
|
||||
}
|
||||
let file_path = location
|
||||
.file_location
|
||||
.buffer
|
||||
.read(cx)
|
||||
.file()
|
||||
.map(|file| file.path());
|
||||
|
||||
let task = location
|
||||
.worktree_root
|
||||
.zip(location.fs)
|
||||
.map(|(worktree_root, fs)| self.detect_package_manager(worktree_root, fs, cx));
|
||||
let args = location.worktree_root.zip(location.fs).zip(file_path).map(
|
||||
|((worktree_root, fs), file_path)| {
|
||||
(
|
||||
self.combined_package_json_data(fs.clone(), &worktree_root, file_path, cx),
|
||||
worktree_root,
|
||||
fs,
|
||||
)
|
||||
},
|
||||
);
|
||||
cx.background_spawn(async move {
|
||||
if let Some(task) = task {
|
||||
vars.insert(TYPESCRIPT_RUNNER_VARIABLE, task.await.to_owned());
|
||||
if let Some((task, worktree_root, fs)) = args {
|
||||
let package_json_data = task.await.log_err();
|
||||
vars.insert(
|
||||
TYPESCRIPT_RUNNER_VARIABLE,
|
||||
detect_package_manager(worktree_root, fs, package_json_data.clone())
|
||||
.await
|
||||
.to_owned(),
|
||||
);
|
||||
|
||||
if let Some(package_json_data) = package_json_data {
|
||||
if let Some(path) = package_json_data.jest_package_path {
|
||||
vars.insert(
|
||||
TYPESCRIPT_JEST_PACKAGE_PATH_VARIABLE,
|
||||
path.parent()
|
||||
.unwrap_or(Path::new(""))
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(path) = package_json_data.mocha_package_path {
|
||||
vars.insert(
|
||||
TYPESCRIPT_MOCHA_PACKAGE_PATH_VARIABLE,
|
||||
path.parent()
|
||||
.unwrap_or(Path::new(""))
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(path) = package_json_data.vitest_package_path {
|
||||
vars.insert(
|
||||
TYPESCRIPT_VITEST_PACKAGE_PATH_VARIABLE,
|
||||
path.parent()
|
||||
.unwrap_or(Path::new(""))
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(path) = package_json_data.jasmine_package_path {
|
||||
vars.insert(
|
||||
TYPESCRIPT_JASMINE_PACKAGE_PATH_VARIABLE,
|
||||
path.parent()
|
||||
.unwrap_or(Path::new(""))
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(vars)
|
||||
})
|
||||
|
@ -991,8 +1077,16 @@ async fn handle_symlink(src_dir: PathBuf, dest_dir: PathBuf) -> Result<()> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::{AppContext as _, TestAppContext};
|
||||
use std::path::Path;
|
||||
|
||||
use gpui::{AppContext as _, BackgroundExecutor, TestAppContext};
|
||||
use language::language_settings;
|
||||
use project::{FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use unindent::Unindent;
|
||||
use util::path;
|
||||
|
||||
use crate::typescript::{PackageJsonData, TypeScriptContextProvider};
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_outline(cx: &mut TestAppContext) {
|
||||
|
@ -1033,4 +1127,82 @@ mod tests {
|
|||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_package_json_discovery(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
settings::init(cx);
|
||||
Project::init_settings(cx);
|
||||
language_settings::init(cx);
|
||||
});
|
||||
|
||||
let package_json_1 = json!({
|
||||
"dependencies": {
|
||||
"mocha": "1.0.0",
|
||||
"vitest": "1.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": ""
|
||||
}
|
||||
})
|
||||
.to_string();
|
||||
|
||||
let package_json_2 = json!({
|
||||
"devDependencies": {
|
||||
"vitest": "2.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": ""
|
||||
}
|
||||
})
|
||||
.to_string();
|
||||
|
||||
let fs = FakeFs::new(executor);
|
||||
fs.insert_tree(
|
||||
path!("/root"),
|
||||
json!({
|
||||
"package.json": package_json_1,
|
||||
"sub": {
|
||||
"package.json": package_json_2,
|
||||
"file.js": "",
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let provider = TypeScriptContextProvider::new();
|
||||
let package_json_data = cx
|
||||
.update(|cx| {
|
||||
provider.combined_package_json_data(
|
||||
fs.clone(),
|
||||
path!("/root").as_ref(),
|
||||
"sub/file1.js".as_ref(),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
pretty_assertions::assert_eq!(
|
||||
package_json_data,
|
||||
PackageJsonData {
|
||||
jest_package_path: None,
|
||||
mocha_package_path: Some(Path::new(path!("/root/package.json")).into()),
|
||||
vitest_package_path: Some(Path::new(path!("/root/sub/package.json")).into()),
|
||||
jasmine_package_path: None,
|
||||
scripts: [
|
||||
(
|
||||
Path::new(path!("/root/package.json")).into(),
|
||||
"test".to_owned()
|
||||
),
|
||||
(
|
||||
Path::new(path!("/root/sub/package.json")).into(),
|
||||
"test".to_owned()
|
||||
)
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
package_manager: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{borrow::Cow, path::Path};
|
||||
use std::{borrow::Cow, path::PathBuf};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use async_trait::async_trait;
|
||||
|
@ -11,8 +11,6 @@ pub(crate) struct NodeLocator;
|
|||
|
||||
const TYPESCRIPT_RUNNER_VARIABLE: VariableName =
|
||||
VariableName::Custom(Cow::Borrowed("TYPESCRIPT_RUNNER"));
|
||||
const TYPESCRIPT_JEST_TASK_VARIABLE: VariableName =
|
||||
VariableName::Custom(Cow::Borrowed("TYPESCRIPT_JEST"));
|
||||
|
||||
#[async_trait]
|
||||
impl DapLocator for NodeLocator {
|
||||
|
@ -34,14 +32,21 @@ impl DapLocator for NodeLocator {
|
|||
return None;
|
||||
}
|
||||
let test_library = build_config.args.first()?;
|
||||
let program_path = Path::new("$ZED_WORKTREE_ROOT")
|
||||
let program_path_base: PathBuf = match test_library.as_str() {
|
||||
"jest" => "${ZED_CUSTOM_TYPESCRIPT_JEST_PACKAGE_PATH}".to_owned(),
|
||||
"mocha" => "${ZED_CUSTOM_TYPESCRIPT_MOCHA_PACKAGE_PATH}".to_owned(),
|
||||
"vitest" => "${ZED_CUSTOM_TYPESCRIPT_VITEST_PACKAGE_PATH}".to_owned(),
|
||||
"jasmine" => "${ZED_CUSTOM_TYPESCRIPT_JASMINE_PACKAGE_PATH}".to_owned(),
|
||||
_ => VariableName::WorktreeRoot.template_value(),
|
||||
}
|
||||
.into();
|
||||
|
||||
let program_path = program_path_base
|
||||
.join("node_modules")
|
||||
.join(".bin")
|
||||
.join(test_library);
|
||||
|
||||
let mut args = if test_library == "jest"
|
||||
|| test_library == &TYPESCRIPT_JEST_TASK_VARIABLE.template_value()
|
||||
{
|
||||
let mut args = if test_library == "jest" {
|
||||
vec!["--runInBand".to_owned()]
|
||||
} else {
|
||||
vec![]
|
||||
|
|
|
@ -278,7 +278,7 @@ impl language::LanguageToolchainStore for RemoteStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct EmptyToolchainStore;
|
||||
pub struct EmptyToolchainStore;
|
||||
#[async_trait(?Send)]
|
||||
impl language::LanguageToolchainStore for EmptyToolchainStore {
|
||||
async fn active_toolchain(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue