1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

refactor(testing): redirect console output via reporter (#11911)

This feeds console output to the reporter and handles silencing there
instead of in the JavaScript code.
This commit is contained in:
Casper Beyer 2021-09-04 21:16:35 +08:00 committed by GitHub
parent 44ca3ce6ae
commit ce79cb5797
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 33 deletions

View file

@ -313,27 +313,27 @@ unitTest(function consoleTestStringifyCircular() {
"JSON {}", "JSON {}",
); );
assertEquals( assertEquals(
stringify(console), stringify(new Console(() => {})),
`console { `console {
log: [Function: bound ], log: [Function: log],
debug: [Function: bound ], debug: [Function: debug],
info: [Function: bound ], info: [Function: info],
dir: [Function: bound ], dir: [Function: dir],
dirxml: [Function: bound ], dirxml: [Function: dir],
warn: [Function: bound ], warn: [Function: warn],
error: [Function: bound ], error: [Function: error],
assert: [Function: bound ], assert: [Function: assert],
count: [Function: bound ], count: [Function: count],
countReset: [Function: bound ], countReset: [Function: countReset],
table: [Function: bound ], table: [Function: table],
time: [Function: bound ], time: [Function: time],
timeLog: [Function: bound ], timeLog: [Function: timeLog],
timeEnd: [Function: bound ], timeEnd: [Function: timeEnd],
group: [Function: bound ], group: [Function: group],
groupCollapsed: [Function: bound ], groupCollapsed: [Function: group],
groupEnd: [Function: bound ], groupEnd: [Function: groupEnd],
clear: [Function: bound ], clear: [Function: clear],
trace: [Function: bound ], trace: [Function: trace],
indentLevel: 0, indentLevel: 0,
[Symbol(isConsoleInstance)]: true [Symbol(isConsoleInstance)]: true
}`, }`,

View file

@ -68,6 +68,13 @@ pub struct TestDescription {
pub name: String, pub name: String,
} }
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum TestOutput {
// TODO(caspervonb): add stdout and stderr redirection.
Console(String),
}
#[derive(Debug, Clone, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub enum TestResult { pub enum TestResult {
@ -90,6 +97,7 @@ pub struct TestPlan {
pub enum TestEvent { pub enum TestEvent {
Plan(TestPlan), Plan(TestPlan),
Wait(TestDescription), Wait(TestDescription),
Output(TestOutput),
Result(TestDescription, TestResult, u64), Result(TestDescription, TestResult, u64),
} }
@ -129,6 +137,7 @@ impl TestSummary {
trait TestReporter { trait TestReporter {
fn report_plan(&mut self, plan: &TestPlan); fn report_plan(&mut self, plan: &TestPlan);
fn report_wait(&mut self, description: &TestDescription); fn report_wait(&mut self, description: &TestDescription);
fn report_output(&mut self, output: &TestOutput);
fn report_result( fn report_result(
&mut self, &mut self,
description: &TestDescription, description: &TestDescription,
@ -140,11 +149,15 @@ trait TestReporter {
struct PrettyTestReporter { struct PrettyTestReporter {
concurrent: bool, concurrent: bool,
echo_output: bool,
} }
impl PrettyTestReporter { impl PrettyTestReporter {
fn new(concurrent: bool) -> PrettyTestReporter { fn new(concurrent: bool, echo_output: bool) -> PrettyTestReporter {
PrettyTestReporter { concurrent } PrettyTestReporter {
concurrent,
echo_output,
}
} }
} }
@ -160,6 +173,14 @@ impl TestReporter for PrettyTestReporter {
} }
} }
fn report_output(&mut self, output: &TestOutput) {
if self.echo_output {
match output {
TestOutput::Console(line) => println!("{}", line),
}
}
}
fn report_result( fn report_result(
&mut self, &mut self,
description: &TestDescription, description: &TestDescription,
@ -217,8 +238,11 @@ impl TestReporter for PrettyTestReporter {
} }
} }
fn create_reporter(concurrent: bool) -> Box<dyn TestReporter + Send> { fn create_reporter(
Box::new(PrettyTestReporter::new(concurrent)) concurrent: bool,
echo_output: bool,
) -> Box<dyn TestReporter + Send> {
Box::new(PrettyTestReporter::new(concurrent, echo_output))
} }
/// Test a single specifier as documentation containing test programs, an executable test module or /// Test a single specifier as documentation containing test programs, an executable test module or
@ -248,7 +272,6 @@ async fn test_specifier(
test_source.push_str(&format!( test_source.push_str(&format!(
"await Deno[Deno.internal].runTests({});\n", "await Deno[Deno.internal].runTests({});\n",
json!({ json!({
"disableLog": program_state.flags.log_level == Some(Level::Error),
"filter": filter, "filter": filter,
"shuffle": shuffle, "shuffle": shuffle,
}), }),
@ -558,6 +581,7 @@ async fn test_specifiers(
shuffle: Option<u64>, shuffle: Option<u64>,
concurrent_jobs: NonZeroUsize, concurrent_jobs: NonZeroUsize,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let log_level = program_state.flags.log_level;
let specifiers_with_mode = if let Some(seed) = shuffle { let specifiers_with_mode = if let Some(seed) = shuffle {
let mut rng = SmallRng::seed_from_u64(seed); let mut rng = SmallRng::seed_from_u64(seed);
let mut specifiers_with_mode = specifiers_with_mode.clone(); let mut specifiers_with_mode = specifiers_with_mode.clone();
@ -602,7 +626,9 @@ async fn test_specifiers(
.buffer_unordered(concurrent_jobs.get()) .buffer_unordered(concurrent_jobs.get())
.collect::<Vec<Result<Result<(), AnyError>, tokio::task::JoinError>>>(); .collect::<Vec<Result<Result<(), AnyError>, tokio::task::JoinError>>>();
let mut reporter = create_reporter(concurrent_jobs.get() > 1); let mut reporter =
create_reporter(concurrent_jobs.get() > 1, log_level != Some(Level::Error));
let handler = { let handler = {
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
let earlier = Instant::now(); let earlier = Instant::now();
@ -626,6 +652,10 @@ async fn test_specifiers(
reporter.report_wait(&description); reporter.report_wait(&description);
} }
TestEvent::Output(output) => {
reporter.report_output(&output);
}
TestEvent::Result(description, result, elapsed) => { TestEvent::Result(description, result, elapsed) => {
match &result { match &result {
TestResult::Ok => { TestResult::Ok => {

View file

@ -228,15 +228,19 @@ finishing test case.`;
} }
async function runTests({ async function runTests({
disableLog = false,
filter = null, filter = null,
shuffle = null, shuffle = null,
} = {}) { } = {}) {
const origin = getTestOrigin(); const origin = getTestOrigin();
const originalConsole = globalThis.console; const originalConsole = globalThis.console;
if (disableLog) {
globalThis.console = new Console(() => {}); globalThis.console = new Console((line) => {
} dispatchTestEvent({
output: {
console: line,
},
});
});
const only = ArrayPrototypeFilter(tests, (test) => test.only); const only = ArrayPrototypeFilter(tests, (test) => test.only);
const filtered = ArrayPrototypeFilter( const filtered = ArrayPrototypeFilter(
@ -286,9 +290,7 @@ finishing test case.`;
dispatchTestEvent({ result: [description, result, elapsed] }); dispatchTestEvent({ result: [description, result, elapsed] });
} }
if (disableLog) { globalThis.console = originalConsole;
globalThis.console = originalConsole;
}
} }
window.__bootstrap.internals = { window.__bootstrap.internals = {