mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
feat(cli): support configuring the test tool in the config file (#15079)
This commit is contained in:
parent
1f04cea160
commit
70d1ecaeaa
15 changed files with 145 additions and 18 deletions
|
@ -397,6 +397,28 @@ pub struct FmtConfig {
|
||||||
pub files: FilesConfig,
|
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<TestConfig, AnyError> {
|
||||||
|
Ok(TestConfig {
|
||||||
|
files: self.files.into_resolved(config_file_specifier)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct TestConfig {
|
||||||
|
pub files: FilesConfig,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ConfigFileJson {
|
pub struct ConfigFileJson {
|
||||||
|
@ -405,6 +427,7 @@ pub struct ConfigFileJson {
|
||||||
pub lint: Option<Value>,
|
pub lint: Option<Value>,
|
||||||
pub fmt: Option<Value>,
|
pub fmt: Option<Value>,
|
||||||
pub tasks: Option<Value>,
|
pub tasks: Option<Value>,
|
||||||
|
pub test: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -583,6 +606,16 @@ impl ConfigFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_test_config(&self) -> Result<Option<TestConfig>, 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
|
/// 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
|
/// of JSON objects providing the name of the task and the arguments of the
|
||||||
/// task in a detail field.
|
/// task in a detail field.
|
||||||
|
|
|
@ -175,7 +175,7 @@ pub struct TestFlags {
|
||||||
pub no_run: bool,
|
pub no_run: bool,
|
||||||
pub fail_fast: Option<NonZeroUsize>,
|
pub fail_fast: Option<NonZeroUsize>,
|
||||||
pub allow_none: bool,
|
pub allow_none: bool,
|
||||||
pub include: Option<Vec<String>>,
|
pub include: Vec<String>,
|
||||||
pub filter: Option<String>,
|
pub filter: Option<String>,
|
||||||
pub shuffle: Option<u64>,
|
pub shuffle: Option<u64>,
|
||||||
pub concurrent_jobs: NonZeroUsize,
|
pub concurrent_jobs: NonZeroUsize,
|
||||||
|
@ -2682,15 +2682,14 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
||||||
NonZeroUsize::new(1).unwrap()
|
NonZeroUsize::new(1).unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let include = if matches.is_present("files") {
|
let include: Vec<String> = if matches.is_present("files") {
|
||||||
let files: Vec<String> = matches
|
matches
|
||||||
.values_of("files")
|
.values_of("files")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.collect();
|
.collect::<Vec<_>>()
|
||||||
Some(files)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
flags.coverage_dir = matches.value_of("coverage").map(String::from);
|
flags.coverage_dir = matches.value_of("coverage").map(String::from);
|
||||||
|
@ -4995,7 +4994,7 @@ mod tests {
|
||||||
fail_fast: None,
|
fail_fast: None,
|
||||||
filter: Some("- foo".to_string()),
|
filter: Some("- foo".to_string()),
|
||||||
allow_none: true,
|
allow_none: true,
|
||||||
include: Some(svec!["dir1/", "dir2/"]),
|
include: svec!["dir1/", "dir2/"],
|
||||||
ignore: vec![],
|
ignore: vec![],
|
||||||
shuffle: None,
|
shuffle: None,
|
||||||
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
||||||
|
@ -5067,7 +5066,7 @@ mod tests {
|
||||||
filter: None,
|
filter: None,
|
||||||
allow_none: false,
|
allow_none: false,
|
||||||
shuffle: None,
|
shuffle: None,
|
||||||
include: None,
|
include: vec![],
|
||||||
ignore: vec![],
|
ignore: vec![],
|
||||||
concurrent_jobs: NonZeroUsize::new(4).unwrap(),
|
concurrent_jobs: NonZeroUsize::new(4).unwrap(),
|
||||||
trace_ops: false,
|
trace_ops: false,
|
||||||
|
@ -5095,7 +5094,7 @@ mod tests {
|
||||||
filter: None,
|
filter: None,
|
||||||
allow_none: false,
|
allow_none: false,
|
||||||
shuffle: None,
|
shuffle: None,
|
||||||
include: None,
|
include: vec![],
|
||||||
ignore: vec![],
|
ignore: vec![],
|
||||||
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
||||||
trace_ops: false,
|
trace_ops: false,
|
||||||
|
@ -5127,7 +5126,7 @@ mod tests {
|
||||||
filter: None,
|
filter: None,
|
||||||
allow_none: false,
|
allow_none: false,
|
||||||
shuffle: None,
|
shuffle: None,
|
||||||
include: None,
|
include: vec![],
|
||||||
ignore: vec![],
|
ignore: vec![],
|
||||||
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
||||||
trace_ops: false,
|
trace_ops: false,
|
||||||
|
@ -5153,7 +5152,7 @@ mod tests {
|
||||||
filter: None,
|
filter: None,
|
||||||
allow_none: false,
|
allow_none: false,
|
||||||
shuffle: Some(1),
|
shuffle: Some(1),
|
||||||
include: None,
|
include: vec![],
|
||||||
ignore: vec![],
|
ignore: vec![],
|
||||||
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
||||||
trace_ops: false,
|
trace_ops: false,
|
||||||
|
@ -5179,7 +5178,7 @@ mod tests {
|
||||||
filter: None,
|
filter: None,
|
||||||
allow_none: false,
|
allow_none: false,
|
||||||
shuffle: None,
|
shuffle: None,
|
||||||
include: None,
|
include: vec![],
|
||||||
ignore: vec![],
|
ignore: vec![],
|
||||||
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
||||||
trace_ops: false,
|
trace_ops: false,
|
||||||
|
@ -5206,7 +5205,7 @@ mod tests {
|
||||||
filter: None,
|
filter: None,
|
||||||
allow_none: false,
|
allow_none: false,
|
||||||
shuffle: None,
|
shuffle: None,
|
||||||
include: None,
|
include: vec![],
|
||||||
ignore: vec![],
|
ignore: vec![],
|
||||||
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
concurrent_jobs: NonZeroUsize::new(1).unwrap(),
|
||||||
trace_ops: false,
|
trace_ops: false,
|
||||||
|
|
|
@ -14,6 +14,7 @@ pub use config_file::LintConfig;
|
||||||
pub use config_file::LintRulesConfig;
|
pub use config_file::LintRulesConfig;
|
||||||
pub use config_file::MaybeImportsResult;
|
pub use config_file::MaybeImportsResult;
|
||||||
pub use config_file::ProseWrap;
|
pub use config_file::ProseWrap;
|
||||||
|
pub use config_file::TestConfig;
|
||||||
pub use config_file::TsConfig;
|
pub use config_file::TsConfig;
|
||||||
pub use flags::*;
|
pub use flags::*;
|
||||||
|
|
||||||
|
@ -244,6 +245,14 @@ impl CliOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_test_config(&self) -> Result<Option<TestConfig>, 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<Option<FmtConfig>, AnyError> {
|
pub fn to_fmt_config(&self) -> Result<Option<FmtConfig>, AnyError> {
|
||||||
if let Some(config) = &self.maybe_config_file {
|
if let Some(config) = &self.maybe_config_file {
|
||||||
config.to_fmt_config()
|
config.to_fmt_config()
|
||||||
|
|
|
@ -62,6 +62,24 @@ itest!(collect {
|
||||||
output: "test/collect.out",
|
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 {
|
itest!(jobs_flag {
|
||||||
args: "test test/short-pass.ts --jobs",
|
args: "test test/short-pass.ts --jobs",
|
||||||
exit_code: 0,
|
exit_code: 0,
|
||||||
|
|
4
cli/tests/testdata/test/collect.out
vendored
4
cli/tests/testdata/test/collect.out
vendored
|
@ -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
|
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
|
running 0 tests from ./test/collect/test.ts
|
||||||
|
|
||||||
ok | 0 passed | 0 failed ([WILDCARD])
|
ok | 0 passed | 0 failed ([WILDCARD])
|
||||||
|
|
7
cli/tests/testdata/test/collect/deno.jsonc
vendored
Normal file
7
cli/tests/testdata/test/collect/deno.jsonc
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"test": {
|
||||||
|
"files": {
|
||||||
|
"exclude": ["./ignore"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
cli/tests/testdata/test/collect/deno.malformed.jsonc
vendored
Normal file
5
cli/tests/testdata/test/collect/deno.malformed.jsonc
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"test": {
|
||||||
|
"dont_know_this_field": {}
|
||||||
|
}
|
||||||
|
}
|
8
cli/tests/testdata/test/collect/deno2.jsonc
vendored
Normal file
8
cli/tests/testdata/test/collect/deno2.jsonc
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"test": {
|
||||||
|
"files": {
|
||||||
|
"include": ["./include/"],
|
||||||
|
"exclude": ["./ignore", "./include/2_test.ts"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
0
cli/tests/testdata/test/collect/include.ts
vendored
Normal file
0
cli/tests/testdata/test/collect/include.ts
vendored
Normal file
0
cli/tests/testdata/test/collect/include/2_test.ts
vendored
Normal file
0
cli/tests/testdata/test/collect/include/2_test.ts
vendored
Normal file
0
cli/tests/testdata/test/collect/include/test.ts
vendored
Normal file
0
cli/tests/testdata/test/collect/include/test.ts
vendored
Normal file
7
cli/tests/testdata/test/collect2.out
vendored
Normal file
7
cli/tests/testdata/test/collect2.out
vendored
Normal file
|
@ -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])
|
||||||
|
|
4
cli/tests/testdata/test/collect_with_malformed_config.out
vendored
Normal file
4
cli/tests/testdata/test/collect_with_malformed_config.out
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
error: Failed to parse "test" configuration
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
unknown field `dont_know_this_field`, expected `files`
|
|
@ -70,7 +70,7 @@ pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> {
|
||||||
} = lint_flags;
|
} = lint_flags;
|
||||||
// First, prepare final configuration.
|
// First, prepare final configuration.
|
||||||
// Collect included and ignored files. CLI flags take precendence
|
// 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.
|
// and `--ignore` CLI flag, only the flag value is taken into account.
|
||||||
let mut include_files = args.clone();
|
let mut include_files = args.clone();
|
||||||
let mut exclude_files = ignore.clone();
|
let mut exclude_files = ignore.clone();
|
||||||
|
|
|
@ -15,6 +15,7 @@ use crate::fmt_errors::format_js_error;
|
||||||
use crate::fs_util::collect_specifiers;
|
use crate::fs_util::collect_specifiers;
|
||||||
use crate::fs_util::is_supported_test_ext;
|
use crate::fs_util::is_supported_test_ext;
|
||||||
use crate::fs_util::is_supported_test_path;
|
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::contains_specifier;
|
||||||
use crate::graph_util::graph_valid;
|
use crate::graph_util::graph_valid;
|
||||||
use crate::located_script_name;
|
use crate::located_script_name;
|
||||||
|
@ -1363,8 +1364,40 @@ async fn fetch_specifiers_with_test_mode(
|
||||||
ignore: Vec<PathBuf>,
|
ignore: Vec<PathBuf>,
|
||||||
include_inline: bool,
|
include_inline: bool,
|
||||||
) -> Result<Vec<(ModuleSpecifier, TestMode)>, AnyError> {
|
) -> Result<Vec<(ModuleSpecifier, TestMode)>, AnyError> {
|
||||||
let mut specifiers_with_mode =
|
let maybe_test_config = ps.options.to_test_config()?;
|
||||||
collect_specifiers_with_test_mode(include, ignore, include_inline)?;
|
|
||||||
|
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::<Vec<_>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if exclude_files.is_empty() {
|
||||||
|
exclude_files = test_config
|
||||||
|
.files
|
||||||
|
.exclude
|
||||||
|
.iter()
|
||||||
|
.filter_map(|s| specifier_to_file_path(s).ok())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
for (specifier, mode) in &mut specifiers_with_mode {
|
||||||
let file = ps
|
let file = ps
|
||||||
.file_fetcher
|
.file_fetcher
|
||||||
|
@ -1390,7 +1423,7 @@ pub async fn run_tests(
|
||||||
Permissions::from_options(&ps.options.permissions_options());
|
Permissions::from_options(&ps.options.permissions_options());
|
||||||
let specifiers_with_mode = fetch_specifiers_with_test_mode(
|
let specifiers_with_mode = fetch_specifiers_with_test_mode(
|
||||||
&ps,
|
&ps,
|
||||||
test_flags.include.unwrap_or_else(|| vec![".".to_string()]),
|
test_flags.include,
|
||||||
test_flags.ignore.clone(),
|
test_flags.ignore.clone(),
|
||||||
test_flags.doc,
|
test_flags.doc,
|
||||||
)
|
)
|
||||||
|
@ -1434,7 +1467,7 @@ pub async fn run_tests_with_watch(
|
||||||
let permissions =
|
let permissions =
|
||||||
Permissions::from_options(&ps.options.permissions_options());
|
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 ignore = test_flags.ignore.clone();
|
||||||
let paths_to_watch: Vec<_> = include.iter().map(PathBuf::from).collect();
|
let paths_to_watch: Vec<_> = include.iter().map(PathBuf::from).collect();
|
||||||
let no_check = ps.options.type_check_mode() == TypeCheckMode::None;
|
let no_check = ps.options.type_check_mode() == TypeCheckMode::None;
|
||||||
|
|
Loading…
Reference in a new issue