1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-01 16:51:13 -05:00

feat: Add support for "deno test --fail-fast=N" (#11316)

This commit adds support for specifying threshold in the "--fail-fast"
flag for "deno test" subcommand. Previously using "--fail-fast" stopped
running the test suite after first failure and with this change users
may specify number of failed tests that will cause the suite to be interrupted.

Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
This commit is contained in:
Yasser A.Idrissi 2021-07-12 11:55:42 +01:00 committed by GitHub
parent 0bc54a0099
commit 32855f2c85
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 113 additions and 9 deletions

View file

@ -98,7 +98,7 @@ pub enum DenoSubcommand {
Test { Test {
doc: bool, doc: bool,
no_run: bool, no_run: bool,
fail_fast: bool, fail_fast: Option<usize>,
quiet: bool, quiet: bool,
allow_none: bool, allow_none: bool,
include: Option<Vec<String>>, include: Option<Vec<String>>,
@ -1001,8 +1001,23 @@ fn test_subcommand<'a, 'b>() -> App<'a, 'b> {
Arg::with_name("fail-fast") Arg::with_name("fail-fast")
.long("fail-fast") .long("fail-fast")
.alias("failfast") .alias("failfast")
.help("Stop on first error") .help("Stop after N errors. Defaults to stopping after first failure.")
.takes_value(false), .min_values(0)
.required(false)
.takes_value(true)
.require_equals(true)
.value_name("N")
.validator(|val: String| match val.parse::<usize>() {
Ok(val) => {
if val == 0 {
return Err(
"fail-fast should be an number greater than 0".to_string(),
);
}
Ok(())
}
Err(_) => Err("fail-fast should be a number".to_string()),
}),
) )
.arg( .arg(
Arg::with_name("allow-none") Arg::with_name("allow-none")
@ -1696,11 +1711,20 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
let no_run = matches.is_present("no-run"); let no_run = matches.is_present("no-run");
let doc = matches.is_present("doc"); let doc = matches.is_present("doc");
let fail_fast = matches.is_present("fail-fast");
let allow_none = matches.is_present("allow-none"); let allow_none = matches.is_present("allow-none");
let quiet = matches.is_present("quiet"); let quiet = matches.is_present("quiet");
let filter = matches.value_of("filter").map(String::from); let filter = matches.value_of("filter").map(String::from);
let fail_fast = if matches.is_present("fail-fast") {
if let Some(value) = matches.value_of("fail-fast") {
Some(value.parse().unwrap())
} else {
Some(1)
}
} else {
None
};
let shuffle = if matches.is_present("shuffle") { let shuffle = if matches.is_present("shuffle") {
let value = if let Some(value) = matches.value_of("shuffle") { let value = if let Some(value) = matches.value_of("shuffle") {
value.parse::<u64>().unwrap() value.parse::<u64>().unwrap()
@ -3387,7 +3411,7 @@ mod tests {
subcommand: DenoSubcommand::Test { subcommand: DenoSubcommand::Test {
no_run: true, no_run: true,
doc: false, doc: false,
fail_fast: false, fail_fast: None,
filter: Some("- foo".to_string()), filter: Some("- foo".to_string()),
allow_none: true, allow_none: true,
quiet: false, quiet: false,
@ -3426,6 +3450,29 @@ mod tests {
); );
} }
#[test]
fn test_with_fail_fast() {
let r = flags_from_vec(svec!["deno", "test", "--fail-fast=3"]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Test {
no_run: false,
doc: false,
fail_fast: Some(3),
filter: None,
allow_none: false,
quiet: false,
shuffle: None,
include: None,
concurrent_jobs: 1,
terse: false
},
..Flags::default()
}
);
}
#[test] #[test]
fn bundle_with_cafile() { fn bundle_with_cafile() {
let r = flags_from_vec(svec![ let r = flags_from_vec(svec![

View file

@ -987,7 +987,7 @@ async fn test_command(
include: Option<Vec<String>>, include: Option<Vec<String>>,
no_run: bool, no_run: bool,
doc: bool, doc: bool,
fail_fast: bool, fail_fast: Option<usize>,
quiet: bool, quiet: bool,
allow_none: bool, allow_none: bool,
filter: Option<String>, filter: Option<String>,

View file

@ -0,0 +1,23 @@
[WILDCARD]
running 10 tests from [WILDCARD]/test/fail_fast_with_val.ts
test test 1 ... FAILED ([WILDCARD])
test test 2 ... FAILED ([WILDCARD])
failures:
test 1
Error
at [WILDCARD]/test/fail_fast_with_val.ts:2:9
at [WILDCARD]
test 2
Error
at [WILDCARD]/test/fail_fast_with_val.ts:5:9
at [WILDCARD]
failures:
test 1
test 2
test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out ([WILDCARD])

View file

@ -0,0 +1,30 @@
Deno.test("test 1", () => {
throw new Error();
});
Deno.test("test 2", () => {
throw new Error();
});
Deno.test("test 3", () => {
throw new Error();
});
Deno.test("test 4", () => {
throw new Error();
});
Deno.test("test 5", () => {
throw new Error();
});
Deno.test("test 6", () => {
throw new Error();
});
Deno.test("test 7", () => {
throw new Error();
});
Deno.test("test 8", () => {
throw new Error();
});
Deno.test("test 9", () => {
throw new Error();
});
Deno.test("test 0", () => {
throw new Error();
});

View file

@ -340,7 +340,7 @@ pub async fn run_tests(
doc_modules: Vec<ModuleSpecifier>, doc_modules: Vec<ModuleSpecifier>,
test_modules: Vec<ModuleSpecifier>, test_modules: Vec<ModuleSpecifier>,
no_run: bool, no_run: bool,
fail_fast: bool, fail_fast: Option<usize>,
quiet: bool, quiet: bool,
allow_none: bool, allow_none: bool,
filter: Option<String>, filter: Option<String>,
@ -515,6 +515,7 @@ pub async fn run_tests(
let mut has_error = false; let mut has_error = false;
let mut planned = 0; let mut planned = 0;
let mut reported = 0; let mut reported = 0;
let mut failed = 0;
for event in receiver.iter() { for event in receiver.iter() {
match event.message.clone() { match event.message.clone() {
@ -538,6 +539,7 @@ pub async fn run_tests(
if let TestResult::Failed(_) = result { if let TestResult::Failed(_) = result {
has_error = true; has_error = true;
failed += 1;
} }
} }
_ => {} _ => {}
@ -545,10 +547,12 @@ pub async fn run_tests(
reporter.visit_event(event); reporter.visit_event(event);
if has_error && fail_fast { if let Some(x) = fail_fast {
if failed >= x {
break; break;
} }
} }
}
if planned > reported { if planned > reported {
has_error = true; has_error = true;