mirror of
https://github.com/denoland/deno.git
synced 2024-12-26 09:10:40 -05:00
feat(cli/tools/test_runner): add terse reporter (#11156)
This commit adds "--terse" flag to "deno test" that makes testing reporter output one character per test case instead of one line per case. This is an unstable feature.
This commit is contained in:
parent
9b89668065
commit
9d57a4aaeb
6 changed files with 172 additions and 3 deletions
|
@ -100,6 +100,7 @@ pub enum DenoSubcommand {
|
|||
no_run: bool,
|
||||
fail_fast: bool,
|
||||
quiet: bool,
|
||||
terse: bool,
|
||||
allow_none: bool,
|
||||
include: Option<Vec<String>>,
|
||||
filter: Option<String>,
|
||||
|
@ -1010,6 +1011,11 @@ fn test_subcommand<'a, 'b>() -> App<'a, 'b> {
|
|||
.help("Don't return error code if no test files are found")
|
||||
.takes_value(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("terse")
|
||||
.long("terse")
|
||||
.help("UNSTABLE: Display one character per test instead of one line"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("filter")
|
||||
.set(ArgSettings::AllowLeadingHyphen)
|
||||
|
@ -1699,6 +1705,7 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
|||
let fail_fast = matches.is_present("fail-fast");
|
||||
let allow_none = matches.is_present("allow-none");
|
||||
let quiet = matches.is_present("quiet");
|
||||
let terse = matches.is_present("terse");
|
||||
let filter = matches.value_of("filter").map(String::from);
|
||||
|
||||
let shuffle = if matches.is_present("shuffle") {
|
||||
|
@ -1753,6 +1760,7 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
|
|||
doc,
|
||||
fail_fast,
|
||||
quiet,
|
||||
terse,
|
||||
include,
|
||||
filter,
|
||||
shuffle,
|
||||
|
@ -3391,6 +3399,7 @@ mod tests {
|
|||
filter: Some("- foo".to_string()),
|
||||
allow_none: true,
|
||||
quiet: false,
|
||||
terse: false,
|
||||
include: Some(svec!["dir1/", "dir2/"]),
|
||||
shuffle: None,
|
||||
concurrent_jobs: 1,
|
||||
|
|
|
@ -988,6 +988,7 @@ async fn test_command(
|
|||
doc: bool,
|
||||
fail_fast: bool,
|
||||
quiet: bool,
|
||||
terse: bool,
|
||||
allow_none: bool,
|
||||
filter: Option<String>,
|
||||
shuffle: Option<u64>,
|
||||
|
@ -1205,6 +1206,7 @@ async fn test_command(
|
|||
no_run,
|
||||
fail_fast,
|
||||
quiet,
|
||||
terse,
|
||||
true,
|
||||
filter.clone(),
|
||||
shuffle,
|
||||
|
@ -1243,6 +1245,7 @@ async fn test_command(
|
|||
no_run,
|
||||
fail_fast,
|
||||
quiet,
|
||||
terse,
|
||||
allow_none,
|
||||
filter,
|
||||
shuffle,
|
||||
|
@ -1350,6 +1353,7 @@ fn get_subcommand(
|
|||
doc,
|
||||
fail_fast,
|
||||
quiet,
|
||||
terse,
|
||||
include,
|
||||
allow_none,
|
||||
filter,
|
||||
|
@ -1362,6 +1366,7 @@ fn get_subcommand(
|
|||
doc,
|
||||
fail_fast,
|
||||
quiet,
|
||||
terse,
|
||||
allow_none,
|
||||
filter,
|
||||
shuffle,
|
||||
|
|
|
@ -49,6 +49,12 @@ itest!(doc {
|
|||
output: "test/doc.out",
|
||||
});
|
||||
|
||||
itest!(terse {
|
||||
args: "test --terse test/terse.ts",
|
||||
exit_code: 1,
|
||||
output: "test/terse.out",
|
||||
});
|
||||
|
||||
itest!(quiet {
|
||||
args: "test --quiet test/quiet.ts",
|
||||
exit_code: 0,
|
||||
|
|
11
cli/tests/test/terse.out
Normal file
11
cli/tests/test/terse.out
Normal file
|
@ -0,0 +1,11 @@
|
|||
Check [WILDCARD]/test/terse.ts
|
||||
running 3 tests from [WILDCARD]
|
||||
.Fi
|
||||
failures:
|
||||
|
||||
fail
|
||||
Error: fail
|
||||
[WILDCARD]
|
||||
|
||||
test result: FAILED. 1 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out [WILDCARD]
|
||||
|
11
cli/tests/test/terse.ts
Normal file
11
cli/tests/test/terse.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
Deno.test("ok", function () {});
|
||||
|
||||
Deno.test("fail", function () {
|
||||
throw new Error("fail");
|
||||
});
|
||||
|
||||
Deno.test({
|
||||
name: "ignore",
|
||||
fn() {},
|
||||
ignore: true,
|
||||
});
|
|
@ -202,8 +202,128 @@ impl TestReporter for PrettyTestReporter {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_reporter(concurrent: bool) -> Box<dyn TestReporter + Send> {
|
||||
Box::new(PrettyTestReporter::new(concurrent))
|
||||
struct TerseTestReporter {
|
||||
time: Instant,
|
||||
failed: usize,
|
||||
filtered_out: usize,
|
||||
ignored: usize,
|
||||
passed: usize,
|
||||
measured: usize,
|
||||
pending: usize,
|
||||
failures: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl TerseTestReporter {
|
||||
fn new() -> TerseTestReporter {
|
||||
TerseTestReporter {
|
||||
time: Instant::now(),
|
||||
failed: 0,
|
||||
filtered_out: 0,
|
||||
ignored: 0,
|
||||
passed: 0,
|
||||
measured: 0,
|
||||
pending: 0,
|
||||
failures: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TestReporter for TerseTestReporter {
|
||||
fn visit_event(&mut self, event: TestEvent) {
|
||||
match &event.message {
|
||||
TestMessage::Plan {
|
||||
pending,
|
||||
filtered,
|
||||
only: _,
|
||||
} => {
|
||||
if *pending == 1 {
|
||||
println!("running {} test from {}", pending, event.origin);
|
||||
} else {
|
||||
println!("running {} tests from {}", pending, event.origin);
|
||||
}
|
||||
|
||||
self.pending += pending;
|
||||
self.filtered_out += filtered;
|
||||
}
|
||||
|
||||
TestMessage::Result {
|
||||
name,
|
||||
duration: _,
|
||||
result,
|
||||
} => {
|
||||
self.pending -= 1;
|
||||
|
||||
match result {
|
||||
TestResult::Ok => {
|
||||
print!("{}", colors::green("."),);
|
||||
|
||||
self.passed += 1;
|
||||
}
|
||||
TestResult::Ignored => {
|
||||
print!("{}", colors::yellow("i"),);
|
||||
|
||||
self.ignored += 1;
|
||||
}
|
||||
TestResult::Failed(error) => {
|
||||
print!("{}", colors::red("F"),);
|
||||
|
||||
self.failed += 1;
|
||||
self.failures.push((name.to_string(), error.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn done(&mut self) {
|
||||
if !self.failures.is_empty() {
|
||||
println!("\nfailures:\n");
|
||||
for (name, error) in &self.failures {
|
||||
println!("{}", name);
|
||||
println!("{}", error);
|
||||
println!();
|
||||
}
|
||||
|
||||
println!("failures:\n");
|
||||
for (name, _) in &self.failures {
|
||||
println!("\t{}", name);
|
||||
}
|
||||
}
|
||||
|
||||
let status = if self.pending > 0 || !self.failures.is_empty() {
|
||||
colors::red("FAILED").to_string()
|
||||
} else {
|
||||
colors::green("ok").to_string()
|
||||
};
|
||||
|
||||
println!(
|
||||
"\ntest result: {}. {} passed; {} failed; {} ignored; {} measured; {} filtered out {}\n",
|
||||
status,
|
||||
self.passed,
|
||||
self.failed,
|
||||
self.ignored,
|
||||
self.measured,
|
||||
self.filtered_out,
|
||||
colors::gray(format!("({}ms)", self.time.elapsed().as_millis())),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum TestReporterKind {
|
||||
Pretty,
|
||||
Terse,
|
||||
}
|
||||
|
||||
fn create_reporter(
|
||||
kind: TestReporterKind,
|
||||
concurrent: bool,
|
||||
) -> Box<dyn TestReporter + Send> {
|
||||
match kind {
|
||||
TestReporterKind::Pretty => Box::new(PrettyTestReporter::new(concurrent)),
|
||||
TestReporterKind::Terse => Box::new(TerseTestReporter::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_supported(p: &Path) -> bool {
|
||||
|
@ -344,6 +464,7 @@ pub async fn run_tests(
|
|||
no_run: bool,
|
||||
fail_fast: bool,
|
||||
quiet: bool,
|
||||
terse: bool,
|
||||
allow_none: bool,
|
||||
filter: Option<String>,
|
||||
shuffle: Option<u64>,
|
||||
|
@ -510,7 +631,13 @@ pub async fn run_tests(
|
|||
.buffer_unordered(concurrent_jobs)
|
||||
.collect::<Vec<Result<Result<(), AnyError>, tokio::task::JoinError>>>();
|
||||
|
||||
let mut reporter = create_reporter(concurrent_jobs > 1);
|
||||
let reporter_kind = if terse {
|
||||
TestReporterKind::Terse
|
||||
} else {
|
||||
TestReporterKind::Pretty
|
||||
};
|
||||
|
||||
let mut reporter = create_reporter(reporter_kind, concurrent_jobs > 1);
|
||||
let handler = {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut used_only = false;
|
||||
|
|
Loading…
Reference in a new issue