From 70d1ecaeaa7843b37e8ea5161b24988813b2f543 Mon Sep 17 00:00:00 2001 From: Roj Date: Mon, 18 Jul 2022 22:12:19 +0300 Subject: [PATCH] feat(cli): support configuring the test tool in the config file (#15079) --- cli/args/config_file.rs | 33 +++++++++++++++ cli/args/flags.rs | 25 ++++++----- cli/args/mod.rs | 9 ++++ cli/tests/integration/test_tests.rs | 18 ++++++++ cli/tests/testdata/test/collect.out | 4 ++ cli/tests/testdata/test/collect/deno.jsonc | 7 ++++ .../test/collect/deno.malformed.jsonc | 5 +++ cli/tests/testdata/test/collect/deno2.jsonc | 8 ++++ cli/tests/testdata/test/collect/include.ts | 0 .../testdata/test/collect/include/2_test.ts | 0 .../testdata/test/collect/include/test.ts | 0 cli/tests/testdata/test/collect2.out | 7 ++++ .../test/collect_with_malformed_config.out | 4 ++ cli/tools/lint.rs | 2 +- cli/tools/test.rs | 41 +++++++++++++++++-- 15 files changed, 145 insertions(+), 18 deletions(-) create mode 100644 cli/tests/testdata/test/collect/deno.jsonc create mode 100644 cli/tests/testdata/test/collect/deno.malformed.jsonc create mode 100644 cli/tests/testdata/test/collect/deno2.jsonc create mode 100644 cli/tests/testdata/test/collect/include.ts create mode 100644 cli/tests/testdata/test/collect/include/2_test.ts create mode 100644 cli/tests/testdata/test/collect/include/test.ts create mode 100644 cli/tests/testdata/test/collect2.out create mode 100644 cli/tests/testdata/test/collect_with_malformed_config.out diff --git a/cli/args/config_file.rs b/cli/args/config_file.rs index a0a5837fb3..48f77d0099 100644 --- a/cli/args/config_file.rs +++ b/cli/args/config_file.rs @@ -397,6 +397,28 @@ pub struct FmtConfig { pub files: FilesConfig, } +#[derive(Clone, Debug, Default, Deserialize)] +#[serde(default, deny_unknown_fields)] +struct SerializedTestConfig { + pub files: SerializedFilesConfig, +} + +impl SerializedTestConfig { + pub fn into_resolved( + self, + config_file_specifier: &ModuleSpecifier, + ) -> Result { + Ok(TestConfig { + files: self.files.into_resolved(config_file_specifier)?, + }) + } +} + +#[derive(Clone, Debug, Default)] +pub struct TestConfig { + pub files: FilesConfig, +} + #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ConfigFileJson { @@ -405,6 +427,7 @@ pub struct ConfigFileJson { pub lint: Option, pub fmt: Option, pub tasks: Option, + pub test: Option, } #[derive(Clone, Debug)] @@ -583,6 +606,16 @@ impl ConfigFile { } } + pub fn to_test_config(&self) -> Result, AnyError> { + if let Some(config) = self.json.test.clone() { + let lint_config: SerializedTestConfig = serde_json::from_value(config) + .context("Failed to parse \"test\" configuration")?; + Ok(Some(lint_config.into_resolved(&self.specifier)?)) + } else { + Ok(None) + } + } + /// Return any tasks that are defined in the configuration file as a sequence /// of JSON objects providing the name of the task and the arguments of the /// task in a detail field. diff --git a/cli/args/flags.rs b/cli/args/flags.rs index c6fbb320b2..9bab9db3bc 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -175,7 +175,7 @@ pub struct TestFlags { pub no_run: bool, pub fail_fast: Option, pub allow_none: bool, - pub include: Option>, + pub include: Vec, pub filter: Option, pub shuffle: Option, pub concurrent_jobs: NonZeroUsize, @@ -2682,15 +2682,14 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { NonZeroUsize::new(1).unwrap() }; - let include = if matches.is_present("files") { - let files: Vec = matches + let include: Vec = if matches.is_present("files") { + matches .values_of("files") .unwrap() .map(String::from) - .collect(); - Some(files) + .collect::>() } else { - None + Vec::new() }; flags.coverage_dir = matches.value_of("coverage").map(String::from); @@ -4995,7 +4994,7 @@ mod tests { fail_fast: None, filter: Some("- foo".to_string()), allow_none: true, - include: Some(svec!["dir1/", "dir2/"]), + include: svec!["dir1/", "dir2/"], ignore: vec![], shuffle: None, concurrent_jobs: NonZeroUsize::new(1).unwrap(), @@ -5067,7 +5066,7 @@ mod tests { filter: None, allow_none: false, shuffle: None, - include: None, + include: vec![], ignore: vec![], concurrent_jobs: NonZeroUsize::new(4).unwrap(), trace_ops: false, @@ -5095,7 +5094,7 @@ mod tests { filter: None, allow_none: false, shuffle: None, - include: None, + include: vec![], ignore: vec![], concurrent_jobs: NonZeroUsize::new(1).unwrap(), trace_ops: false, @@ -5127,7 +5126,7 @@ mod tests { filter: None, allow_none: false, shuffle: None, - include: None, + include: vec![], ignore: vec![], concurrent_jobs: NonZeroUsize::new(1).unwrap(), trace_ops: false, @@ -5153,7 +5152,7 @@ mod tests { filter: None, allow_none: false, shuffle: Some(1), - include: None, + include: vec![], ignore: vec![], concurrent_jobs: NonZeroUsize::new(1).unwrap(), trace_ops: false, @@ -5179,7 +5178,7 @@ mod tests { filter: None, allow_none: false, shuffle: None, - include: None, + include: vec![], ignore: vec![], concurrent_jobs: NonZeroUsize::new(1).unwrap(), trace_ops: false, @@ -5206,7 +5205,7 @@ mod tests { filter: None, allow_none: false, shuffle: None, - include: None, + include: vec![], ignore: vec![], concurrent_jobs: NonZeroUsize::new(1).unwrap(), trace_ops: false, diff --git a/cli/args/mod.rs b/cli/args/mod.rs index accdeae7ff..badfdc39d7 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -14,6 +14,7 @@ pub use config_file::LintConfig; pub use config_file::LintRulesConfig; pub use config_file::MaybeImportsResult; pub use config_file::ProseWrap; +pub use config_file::TestConfig; pub use config_file::TsConfig; pub use flags::*; @@ -244,6 +245,14 @@ impl CliOptions { } } + pub fn to_test_config(&self) -> Result, AnyError> { + if let Some(config_file) = &self.maybe_config_file { + config_file.to_test_config() + } else { + Ok(None) + } + } + pub fn to_fmt_config(&self) -> Result, AnyError> { if let Some(config) = &self.maybe_config_file { config.to_fmt_config() diff --git a/cli/tests/integration/test_tests.rs b/cli/tests/integration/test_tests.rs index 8e7df2dfbc..32be3c127f 100644 --- a/cli/tests/integration/test_tests.rs +++ b/cli/tests/integration/test_tests.rs @@ -62,6 +62,24 @@ itest!(collect { output: "test/collect.out", }); +itest!(test_with_config { + args: "test --config test/collect/deno.jsonc test/collect", + exit_code: 0, + output: "test/collect.out", +}); + +itest!(test_with_config2 { + args: "test --config test/collect/deno2.jsonc test/collect", + exit_code: 0, + output: "test/collect2.out", +}); + +itest!(test_with_malformed_config { + args: "test --config test/collect/deno.malformed.jsonc", + exit_code: 1, + output: "test/collect_with_malformed_config.out", +}); + itest!(jobs_flag { args: "test test/short-pass.ts --jobs", exit_code: 0, diff --git a/cli/tests/testdata/test/collect.out b/cli/tests/testdata/test/collect.out index 9f3495298c..dc5161a909 100644 --- a/cli/tests/testdata/test/collect.out +++ b/cli/tests/testdata/test/collect.out @@ -1,4 +1,8 @@ +Check [WILDCARD]/test/collect/include/2_test.ts +Check [WILDCARD]/test/collect/include/test.ts Check [WILDCARD]/test/collect/test.ts +running 0 tests from ./test/collect/include/2_test.ts +running 0 tests from ./test/collect/include/test.ts running 0 tests from ./test/collect/test.ts ok | 0 passed | 0 failed ([WILDCARD]) diff --git a/cli/tests/testdata/test/collect/deno.jsonc b/cli/tests/testdata/test/collect/deno.jsonc new file mode 100644 index 0000000000..b8acda27d0 --- /dev/null +++ b/cli/tests/testdata/test/collect/deno.jsonc @@ -0,0 +1,7 @@ +{ + "test": { + "files": { + "exclude": ["./ignore"] + } + } +} diff --git a/cli/tests/testdata/test/collect/deno.malformed.jsonc b/cli/tests/testdata/test/collect/deno.malformed.jsonc new file mode 100644 index 0000000000..f2d8cbc652 --- /dev/null +++ b/cli/tests/testdata/test/collect/deno.malformed.jsonc @@ -0,0 +1,5 @@ +{ + "test": { + "dont_know_this_field": {} + } +} diff --git a/cli/tests/testdata/test/collect/deno2.jsonc b/cli/tests/testdata/test/collect/deno2.jsonc new file mode 100644 index 0000000000..a4d244e31e --- /dev/null +++ b/cli/tests/testdata/test/collect/deno2.jsonc @@ -0,0 +1,8 @@ +{ + "test": { + "files": { + "include": ["./include/"], + "exclude": ["./ignore", "./include/2_test.ts"] + } + } +} diff --git a/cli/tests/testdata/test/collect/include.ts b/cli/tests/testdata/test/collect/include.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cli/tests/testdata/test/collect/include/2_test.ts b/cli/tests/testdata/test/collect/include/2_test.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cli/tests/testdata/test/collect/include/test.ts b/cli/tests/testdata/test/collect/include/test.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cli/tests/testdata/test/collect2.out b/cli/tests/testdata/test/collect2.out new file mode 100644 index 0000000000..af31ee31e2 --- /dev/null +++ b/cli/tests/testdata/test/collect2.out @@ -0,0 +1,7 @@ +Check [WILDCARD]/test/collect/include/test.ts +Check [WILDCARD]/test/collect/test.ts +running 0 tests from ./test/collect/include/test.ts +running 0 tests from ./test/collect/test.ts + +ok | 0 passed | 0 failed ([WILDCARD]) + diff --git a/cli/tests/testdata/test/collect_with_malformed_config.out b/cli/tests/testdata/test/collect_with_malformed_config.out new file mode 100644 index 0000000000..25c34406fd --- /dev/null +++ b/cli/tests/testdata/test/collect_with_malformed_config.out @@ -0,0 +1,4 @@ +error: Failed to parse "test" configuration + +Caused by: + unknown field `dont_know_this_field`, expected `files` diff --git a/cli/tools/lint.rs b/cli/tools/lint.rs index 1c79ff8f6f..cfc6633875 100644 --- a/cli/tools/lint.rs +++ b/cli/tools/lint.rs @@ -70,7 +70,7 @@ pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> { } = lint_flags; // First, prepare final configuration. // Collect included and ignored files. CLI flags take precendence - // over config file, ie. if there's `files.ignore` in config file + // over config file, i.e. if there's `files.ignore` in config file // and `--ignore` CLI flag, only the flag value is taken into account. let mut include_files = args.clone(); let mut exclude_files = ignore.clone(); diff --git a/cli/tools/test.rs b/cli/tools/test.rs index f3d4d6f6c8..cbb5d0b531 100644 --- a/cli/tools/test.rs +++ b/cli/tools/test.rs @@ -15,6 +15,7 @@ use crate::fmt_errors::format_js_error; use crate::fs_util::collect_specifiers; use crate::fs_util::is_supported_test_ext; use crate::fs_util::is_supported_test_path; +use crate::fs_util::specifier_to_file_path; use crate::graph_util::contains_specifier; use crate::graph_util::graph_valid; use crate::located_script_name; @@ -1363,8 +1364,40 @@ async fn fetch_specifiers_with_test_mode( ignore: Vec, include_inline: bool, ) -> Result, AnyError> { - let mut specifiers_with_mode = - collect_specifiers_with_test_mode(include, ignore, include_inline)?; + let maybe_test_config = ps.options.to_test_config()?; + + let mut include_files = include.clone(); + let mut exclude_files = ignore.clone(); + + if let Some(test_config) = maybe_test_config.as_ref() { + if include_files.is_empty() { + include_files = test_config + .files + .include + .iter() + .map(|s| s.to_string()) + .collect::>(); + } + + if exclude_files.is_empty() { + exclude_files = test_config + .files + .exclude + .iter() + .filter_map(|s| specifier_to_file_path(s).ok()) + .collect::>(); + } + } + + if include_files.is_empty() { + include_files.push(".".to_string()); + } + + let mut specifiers_with_mode = collect_specifiers_with_test_mode( + include_files, + exclude_files, + include_inline, + )?; for (specifier, mode) in &mut specifiers_with_mode { let file = ps .file_fetcher @@ -1390,7 +1423,7 @@ pub async fn run_tests( Permissions::from_options(&ps.options.permissions_options()); let specifiers_with_mode = fetch_specifiers_with_test_mode( &ps, - test_flags.include.unwrap_or_else(|| vec![".".to_string()]), + test_flags.include, test_flags.ignore.clone(), test_flags.doc, ) @@ -1434,7 +1467,7 @@ pub async fn run_tests_with_watch( let permissions = Permissions::from_options(&ps.options.permissions_options()); - let include = test_flags.include.unwrap_or_else(|| vec![".".to_string()]); + let include = test_flags.include; let ignore = test_flags.ignore.clone(); let paths_to_watch: Vec<_> = include.iter().map(PathBuf::from).collect(); let no_check = ps.options.type_check_mode() == TypeCheckMode::None;